Skip to content

Commit

Permalink
Merge pull request #2321 from AleoHQ/fix/deployment-external-record
Browse files Browse the repository at this point in the history
[Fix] Deployment verification for programs that create external records.
  • Loading branch information
howardwu authored Jan 27, 2024
2 parents 0941869 + 13cde7a commit 6d396af
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 25 deletions.
27 changes: 25 additions & 2 deletions synthesizer/process/src/stack/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

use crate::{stack::Address, CallStack, Registers, RegistersCall, StackEvaluate, StackExecute};
use aleo_std::prelude::{finish, lap, timer};
use console::{network::prelude::*, program::Request};
use console::{
account::Field,
network::prelude::*,
program::{Register, Request, Value, ValueType},
};
use synthesizer_program::{
Call,
CallOperator,
Expand Down Expand Up @@ -281,7 +285,26 @@ impl<N: Network> CallTrait<N> for Call<N> {
let outputs = function
.outputs()
.iter()
.map(|output| substack.sample_value(&address, output.value_type(), rng))
.map(|output| match output.value_type() {
ValueType::Record(record_name) => {
// Get the register index containing the record.
let index = match output.operand() {
Operand::Register(Register::Locator(index)) => Field::from_u64(*index),
_ => bail!("Expected a `Register::Locator` operand for a record output."),
};
// Compute the encryption randomizer as `HashToScalar(tvk || index)`.
let randomizer = N::hash_to_scalar_psd2(&[*request.tvk(), index])?;
// Construct the record nonce.
let record_nonce = N::g_scalar_multiply(&randomizer);
Ok(Value::Record(substack.sample_record(
&address,
record_name,
record_nonce,
rng,
)?))
}
_ => substack.sample_value(&address, output.value_type(), rng),
})
.collect::<Result<Vec<_>>>()?;
// Map the output operands to registers.
let output_registers = function
Expand Down
23 changes: 2 additions & 21 deletions synthesizer/process/src/stack/helpers/sample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,6 @@
use super::*;

impl<N: Network> Stack<N> {
/// Returns a record for the given record name, with the given burner address.
pub fn sample_record<R: Rng + CryptoRng>(
&self,
burner_address: &Address<N>,
record_name: &Identifier<N>,
rng: &mut R,
) -> Result<Record<N, Plaintext<N>>> {
// Sample a record.
let record = self.sample_record_internal(burner_address, record_name, 0, rng)?;
// Ensure the record matches the value type.
self.matches_record(&record, record_name)?;
// Return the record.
Ok(record)
}

/// Samples a plaintext value according to the given plaintext type.
pub fn sample_plaintext<R: Rng + CryptoRng>(
&self,
Expand All @@ -53,14 +38,13 @@ impl<N: Network> Stack<N> {
// Return the future value.
Ok(future)
}
}

impl<N: Network> Stack<N> {
/// Returns a record for the given record name.
fn sample_record_internal<R: Rng + CryptoRng>(
pub(crate) fn sample_record_internal<R: Rng + CryptoRng>(
&self,
burner_address: &Address<N>,
record_name: &Identifier<N>,
nonce: Group<N>,
depth: usize,
rng: &mut R,
) -> Result<Record<N, Plaintext<N>>> {
Expand Down Expand Up @@ -88,9 +72,6 @@ impl<N: Network> Stack<N> {
})
.collect::<Result<IndexMap<_, _>>>()?;

// Initialize the nonce.
let nonce = Group::rand(rng);

// Return the record.
Record::<N, Plaintext<N>>::from_plaintext(owner, data, nonce)
}
Expand Down
20 changes: 18 additions & 2 deletions synthesizer/process/src/stack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,17 +307,33 @@ impl<N: Network> StackProgram<N> for Stack<N> {
| ValueType::Public(plaintext_type)
| ValueType::Private(plaintext_type) => Ok(Value::Plaintext(self.sample_plaintext(plaintext_type, rng)?)),
ValueType::Record(record_name) => {
Ok(Value::Record(self.sample_record(burner_address, record_name, rng)?))
Ok(Value::Record(self.sample_record(burner_address, record_name, Group::rand(rng), rng)?))
}
ValueType::ExternalRecord(locator) => {
// Retrieve the external stack.
let stack = self.get_external_stack(locator.program_id())?;
// Sample the output.
Ok(Value::Record(stack.sample_record(burner_address, locator.resource(), rng)?))
Ok(Value::Record(stack.sample_record(burner_address, locator.resource(), Group::rand(rng), rng)?))
}
ValueType::Future(locator) => Ok(Value::Future(self.sample_future(locator, rng)?)),
}
}

/// Returns a record for the given record name, with the given burner address and nonce.
fn sample_record<R: Rng + CryptoRng>(
&self,
burner_address: &Address<N>,
record_name: &Identifier<N>,
nonce: Group<N>,
rng: &mut R,
) -> Result<Record<N, Plaintext<N>>> {
// Sample a record.
let record = self.sample_record_internal(burner_address, record_name, nonce, 0, rng)?;
// Ensure the record matches the value type.
self.matches_record(&record, record_name)?;
// Return the record.
Ok(record)
}
}

impl<N: Network> StackProgramTypes<N> for Stack<N> {
Expand Down
10 changes: 10 additions & 0 deletions synthesizer/program/src/traits/stack_and_registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use std::sync::Arc;

use crate::{FinalizeGlobalState, Function, Operand, Program};
use console::{
account::Group,
network::Network,
prelude::{bail, Result},
program::{
Expand Down Expand Up @@ -92,6 +93,15 @@ pub trait StackProgram<N: Network> {
value_type: &ValueType<N>,
rng: &mut R,
) -> Result<Value<N>>;

/// Returns a record for the given record name, with the given burner address and nonce.
fn sample_record<R: Rng + CryptoRng>(
&self,
burner_address: &Address<N>,
record_name: &Identifier<N>,
record_nonce: Group<N>,
rng: &mut R,
) -> Result<Record<N, Plaintext<N>>>;
}

pub trait FinalizeRegistersState<N: Network> {
Expand Down
40 changes: 40 additions & 0 deletions synthesizer/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,46 @@ function check:
assert!(vm.contains_program(&ProgramID::from_str("parent_program.aleo").unwrap()));
}

#[test]
fn test_deployment_with_external_records() {
let rng = &mut TestRng::default();

// Initialize a private key.
let private_key = sample_genesis_private_key(rng);

// Initialize the genesis block.
let genesis = sample_genesis_block(rng);

// Initialize the VM.
let vm = sample_vm();
// Update the VM.
vm.add_next_block(&genesis).unwrap();

// Deploy the program.
let program = Program::from_str(
r"
import credits.aleo;
program test_program.aleo;
function transfer:
input r0 as credits.aleo/credits.record;
input r1 as u64.private;
input r2 as u64.private;
input r3 as [address; 10u32].private;
call credits.aleo/transfer_private r0 r3[0u32] r1 into r4 r5;
call credits.aleo/transfer_private r5 r3[0u32] r2 into r6 r7;
",
)
.unwrap();

let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap();
assert!(vm.check_transaction(&deployment, None, rng).is_ok());
vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap();

// Check that program is deployed.
assert!(vm.contains_program(&ProgramID::from_str("test_program.aleo").unwrap()));
}

#[test]
#[ignore]
fn test_deployment_memory_overload() {
Expand Down

0 comments on commit 6d396af

Please sign in to comment.