diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr index d88baa615d3b..2b71790e9543 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr @@ -8,6 +8,8 @@ use protocol_types::{ traits::Packable, }; +mod test; + /// Stores an immutable value in public state which can be read from public, private and unconstrained execution /// contexts. /// @@ -126,6 +128,7 @@ impl PublicImmutable { where T: Packable + Eq, { + // TODO(#15703): this fn should fail if the variable is not initialized WithHash::utility_public_storage_read(self.context, self.storage_slot) } } @@ -135,6 +138,7 @@ impl PublicImmutable { where T: Packable + Eq, { + // TODO(#15703): this fn should fail if the variable is not initialized WithHash::historical_public_storage_read( self.context.get_block_header(), self.context.this_address(), diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable/test.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable/test.nr index b7d78e8763b4..e354ffd15627 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable/test.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable/test.nr @@ -1,53 +1,186 @@ -use crate::{context::PublicContext, state_vars::public_immutable::PublicImmutable}; +use crate::{ + context::{PrivateContext, PublicContext, UtilityContext}, + state_vars::public_immutable::PublicImmutable, +}; use crate::test::{helpers::test_environment::TestEnvironment, mocks::mock_struct::MockStruct}; -use dep::protocol_types::traits::Serialize; +use std::mem::zeroed; -global storage_slot = 7; +global storage_slot: Field = 7; -fn setup() -> TestEnvironment { - TestEnvironment::new() +fn in_public(context: &mut PublicContext) -> PublicImmutable { + PublicImmutable::new(context, storage_slot) } -fn in_public(env: TestEnvironment) -> PublicImmutable { - PublicImmutable::new(&mut env.public(), storage_slot) +fn in_private(context: &mut PrivateContext) -> PublicImmutable { + PublicImmutable::new(context, storage_slot) +} + +fn in_utility(context: UtilityContext) -> PublicImmutable { + PublicImmutable::new(context, storage_slot) } #[test] -fn test_uninitialized_by_default() { - let env = setup(); - let state_var = in_public(env); +unconstrained fn is_uninitialized_by_default() { + let mut env = TestEnvironment::_new(); - assert_eq(state_var.is_initialized(), false); + env.public_context(|context| { + let state_var = in_public(context); + assert_eq(state_var.is_initialized(), false); + }); } #[test] -fn test_initialize_uninitialized() { - let env = setup(); - let state_var = in_public(env); +unconstrained fn initialize_uninitialized_same_tx() { + let mut env = TestEnvironment::_new(); - let value = MockStruct::new(5, 6); + env.public_context(|context| { + let state_var = in_public(context); + + let value = MockStruct::new(5, 6); + state_var.initialize(value); + + assert(state_var.is_initialized()); + }); +} + +#[test] +unconstrained fn initialize_uninitialized_other_tx() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + let state_var = in_public(context); + + let value = MockStruct::new(5, 6); + state_var.initialize(value); + }); + + env.public_context(|context| { + let state_var = in_public(context); + assert(state_var.is_initialized()); + }); +} + +#[test(should_fail)] +unconstrained fn initialize_already_initialized_same_tx() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + let state_var = in_public(context); + + let value = MockStruct::new(5, 6); + state_var.initialize(value); + + let other_value = MockStruct::new(7, 8); + state_var.initialize(other_value); + }); +} + +#[test(should_fail)] +unconstrained fn initialize_already_initialized_other_tx() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + let state_var = in_public(context); + let value = MockStruct::new(5, 6); + state_var.initialize(value); + }); + + env.public_context(|context| { + let state_var = in_public(context); + let other_value = MockStruct::new(7, 8); + state_var.initialize(other_value); + }); +} + +#[test(should_fail_with = "Trying to read from uninitialized PublicImmutable")] +unconstrained fn read_uninitialized_public_fails() { + let mut env = TestEnvironment::_new(); - state_var.initialize(value); + env.public_context(|context| { + let state_var = in_public(context); + let _ = state_var.read(); + }); +} + +// TODO(#15703): this test should be made to fail +#[test] +unconstrained fn read_uninitialized_private_returns_default() { + let mut env = TestEnvironment::_new(); + + env.private_context(|context| { + let state_var = in_private(context); + assert_eq(state_var.read(), zeroed()); + }); +} + +// TODO(#15703): this test should be made to fail +#[test] +unconstrained fn read_uninitialized_utility_returns_default() { + let mut env = TestEnvironment::_new(); + + env.utility_context(|context| { + let state_var = in_utility(context); + assert_eq(state_var.read(), zeroed()); + }); +} + +#[test] +unconstrained fn read_uninitialized_public_same_tx() { + let mut env = TestEnvironment::_new(); - assert(state_var.is_initialized()); - assert(state_var.read() == value); + env.public_context(|context| { + let state_var = in_public(context); + let value = MockStruct::new(5, 6); + state_var.initialize(value); + + assert_eq(state_var.read(), value); + }); } -#[test(should_fail_with = "PublicImmutable already initialized")] -fn test_initialize_already_initialized() { - let env = setup(); - let state_var = in_public(env); +#[test] +unconstrained fn read_uninitialized_public_other_tx() { + let mut env = TestEnvironment::_new(); + let value = MockStruct::new(5, 6); + + env.public_context(|context| { + let state_var = in_public(context); + state_var.initialize(value); + }); + + env.public_context(|context| { + let state_var = in_public(context); + assert_eq(state_var.read(), value); + }); +} +#[test] +unconstrained fn read_uninitialized_private() { + let mut env = TestEnvironment::_new(); let value = MockStruct::new(5, 6); - state_var.initialize(value); - state_var.initialize(value); + env.public_context(|context| { + let state_var = in_public(context); + state_var.initialize(value); + }); + + env.private_context(|context| { + let state_var = in_private(context); + assert_eq(state_var.read(), value); + }); } -#[test(should_fail_with = "PublicImmutable not initialized")] -fn test_read_uninitialized() { - let env = setup(); - let state_var = in_public(env); +#[test] +unconstrained fn read_uninitialized_utility() { + let mut env = TestEnvironment::_new(); + let value = MockStruct::new(5, 6); + + env.public_context(|context| { + let state_var = in_public(context); + state_var.initialize(value); + }); - let _ = state_var.read(); + env.utility_context(|context| { + let state_var = in_utility(context); + assert_eq(state_var.read(), value); + }); } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr index 57929f9bcfd6..851473ae4799 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr @@ -2,6 +2,8 @@ use crate::context::{PublicContext, UtilityContext}; use crate::state_vars::storage::HasStorageSlot; use dep::protocol_types::traits::Packable; +mod test; + // docs:start:public_mutable_struct pub struct PublicMutable { context: Context, diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable/test.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable/test.nr new file mode 100644 index 000000000000..aff535c8b080 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable/test.nr @@ -0,0 +1,79 @@ +use crate::{context::{PublicContext, UtilityContext}, state_vars::public_mutable::PublicMutable}; +use crate::test::{helpers::test_environment::TestEnvironment, mocks::mock_struct::MockStruct}; +use std::mem::zeroed; + +global storage_slot: Field = 7; + +fn in_public(context: &mut PublicContext) -> PublicMutable { + PublicMutable::new(context, storage_slot) +} + +fn in_utility(context: UtilityContext) -> PublicMutable { + PublicMutable::new(context, storage_slot) +} + +#[test] +unconstrained fn read_uninitialized_public_returns_zero() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + let state_var = in_public(context); + assert_eq(state_var.read(), zeroed()); + }); +} + +#[test] +unconstrained fn read_uninitialized_utility_returns_default() { + let mut env = TestEnvironment::_new(); + + env.utility_context(|context| { + let state_var = in_utility(context); + assert_eq(state_var.read(), zeroed()); + }); +} + +#[test] +unconstrained fn write_read_public_same_tx() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + let state_var = in_public(context); + let value = MockStruct::new(5, 6); + + state_var.write(value); + assert_eq(state_var.read(), value); + }); +} + +#[test] +unconstrained fn write_read_public_other_tx() { + let mut env = TestEnvironment::_new(); + + let value = MockStruct::new(5, 6); + + env.public_context(|context| { + let state_var = in_public(context); + state_var.write(value); + }); + + env.public_context(|context| { + let state_var = in_public(context); + assert_eq(state_var.read(), value); + }); +} + +#[test] +unconstrained fn write_read_utility() { + let mut env = TestEnvironment::_new(); + let value = MockStruct::new(5, 6); + + env.public_context(|context| { + let state_var = in_public(context); + state_var.write(value); + }); + + env.utility_context(|context| { + let state_var = in_utility(context); + assert_eq(state_var.read(), value); + }); +} diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index 8008306881fe..6b99b55cae45 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -122,7 +122,9 @@ impl TestEnvironment { let ret_value = f(&mut context); cheatcodes::set_top_level_txe_context(); - // todo: should commit the context to mine a block with the side effects of the context + // todo: should commit the context to mine a block with the side effects of the context. we should have an + // oracle that receives the context we produced probably + self.mine_block(); ret_value } diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment/test.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment/test.nr index d2f2423995fc..42c87b2b8591 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment/test.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment/test.nr @@ -1,9 +1,6 @@ -use crate::test::{helpers::test_environment::TestEnvironment, mocks::mock_struct::MockStruct}; +use crate::test::helpers::test_environment::TestEnvironment; -use dep::std::mem::zeroed; - -global storage_slot: Field = 13; -global value: MockStruct = MockStruct { a: 17, b: 42 }; +mod public_context; #[test(should_fail_with = "cannot be before next timestamp")] unconstrained fn set_next_block_timestamp_to_past_fails() { @@ -98,34 +95,6 @@ unconstrained fn public_context_advances_timestamp() { assert(second_timestamp > first_timestamp); } -#[test] -unconstrained fn public_context_default_storage_value() { - let mut env = TestEnvironment::_new(); - - env.public_context(|context| { - assert_eq(context.storage_read::(storage_slot), zeroed()); - }); -} - -#[test] -unconstrained fn public_context_storage_write_in_same_context() { - let mut env = TestEnvironment::_new(); - - env.public_context(|context| { - context.storage_write(storage_slot, value); - assert_eq(context.storage_read(storage_slot), value); - }); -} - -#[test] -unconstrained fn public_context_storage_write_in_future_context() { - let mut env = TestEnvironment::_new(); - - env.public_context(|context| { context.storage_write(storage_slot, value); }); - - env.public_context(|context| { assert_eq(context.storage_read(storage_slot), value); }); -} - #[test] unconstrained fn private_context_uses_previous_block_number() { let mut env = TestEnvironment::_new(); diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment/test/public_context.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment/test/public_context.nr new file mode 100644 index 000000000000..5b80b239ee90 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment/test/public_context.nr @@ -0,0 +1,103 @@ +use crate::test::{helpers::test_environment::TestEnvironment, mocks::mock_struct::MockStruct}; + +use dep::std::mem::zeroed; + +global storage_slot: Field = 13; + +global value: MockStruct = MockStruct { a: 17, b: 42 }; +global other_value: MockStruct = MockStruct { a: 7, b: 8 }; + +global nullifier: Field = 9; + +#[test] +unconstrained fn default_storage_value() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + assert_eq(context.storage_read::(storage_slot), zeroed()); + }); +} + +#[test] +unconstrained fn storage_write_in_same_context() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + context.storage_write(storage_slot, value); + assert_eq(context.storage_read(storage_slot), value); + }); +} + +#[test] +unconstrained fn storage_write_in_future_context() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { context.storage_write(storage_slot, value); }); + + env.public_context(|context| { assert_eq(context.storage_read(storage_slot), value); }); +} + +#[test] +unconstrained fn storage_multiple_writes_in_same_context() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + context.storage_write(storage_slot, value); + context.storage_write(storage_slot, other_value); + + assert_eq(context.storage_read(storage_slot), other_value); + }); +} + +#[test] +unconstrained fn storage_multiple_writes_in_future_context() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { context.storage_write(storage_slot, value); }); + + env.public_context(|context| { + context.storage_write(storage_slot, other_value); + assert_eq(context.storage_read(storage_slot), other_value); + }); +} + +#[test] +unconstrained fn read_nonexistent_nullifier() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + assert(!context.nullifier_exists(nullifier, context.this_address())); + }); +} + +#[test] +unconstrained fn read_public_nullifier_same_context() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { + context.push_nullifier(nullifier); + assert(context.nullifier_exists(nullifier, context.this_address())); + }); +} + +#[test] +unconstrained fn read_public_nullifier_other_context() { + let mut env = TestEnvironment::_new(); + + env.public_context(|context| { context.push_nullifier(nullifier); }); + + env.public_context(|context| { + assert(context.nullifier_exists(nullifier, context.this_address())); + }); +} + +#[test] +unconstrained fn read_private_nullifier() { + let mut env = TestEnvironment::_new(); + + env.private_context(|context| { context.push_nullifier(nullifier); }); + + env.public_context(|context| { + assert(context.nullifier_exists(nullifier, context.this_address())); + }); +} diff --git a/yarn-project/txe/src/oracle/txe_oracle.ts b/yarn-project/txe/src/oracle/txe_oracle.ts index 9d51019921c2..ac72535525f9 100644 --- a/yarn-project/txe/src/oracle/txe_oracle.ts +++ b/yarn-project/txe/src/oracle/txe_oracle.ts @@ -1239,8 +1239,11 @@ export class TXE implements TypedOracle { async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise { const nullifier = await siloNullifier(targetAddress, innerNullifier!); const db = this.baseFork; - const index = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0]; - return index !== undefined; + + const treeIndex = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0]; + const transientIndex = this.siloedNullifiersFromPublic.find(n => n.equals(nullifier)); + + return treeIndex !== undefined || transientIndex !== undefined; } async avmOpcodeEmitNullifier(nullifier: Fr) {