From 37eb228ef521f8987ddd4e5e230fddbdea188e18 Mon Sep 17 00:00:00 2001 From: benesjan Date: Mon, 30 Oct 2023 13:51:04 +0000 Subject: [PATCH] using and testing FieldNote --- .../src/e2e_non_contract_account.test.ts | 24 ++++++++++- .../src/contracts/test_contract/Nargo.toml | 1 + .../contracts/test_contract/src/interface.nr | 12 ++++++ .../src/contracts/test_contract/src/main.nr | 43 +++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts b/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts index a5b5fe1d0c0..895646a9e95 100644 --- a/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts +++ b/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts @@ -4,7 +4,7 @@ import { siloNullifier } from '@aztec/circuits.js/abis'; import { DebugLogger } from '@aztec/foundation/log'; import { toBigInt } from '@aztec/foundation/serialize'; import { TestContract } from '@aztec/noir-contracts/types'; -import { AztecNode, PXE, TxStatus } from '@aztec/types'; +import { AztecNode, NotePreimage, PXE, TxStatus } from '@aztec/types'; import { setup } from './fixtures/utils.js'; @@ -17,9 +17,9 @@ describe('e2e_non_contract_account', () => { let logger: DebugLogger; let contract: TestContract; + let wallet: Wallet; beforeEach(async () => { - let wallet: Wallet; ({ teardown, aztecNode, pxe, wallet, logger } = await setup(1)); nonContractAccountWallet = new SignerlessWallet(pxe); @@ -59,4 +59,24 @@ describe('e2e_non_contract_account', () => { const msgSender = toBigInt(logs[0].log.data); expect(msgSender).toBe(0n); }, 120_000); + + // Note: This test doesn't really belong here as it doesn't have anything to do with non-contract accounts. I needed + // to test the FieldNote functionality and it doesn't really fit anywhere else. Creating a separate e2e test for this + // seems wasteful. Move this test if a better place is found. + it('can set and get a constant', async () => { + const value = 123n; + + const receipt = await contract.methods.set_constant(value).send().wait({ interval: 0.1 }); + + // check that 1 commitment was created + const tx = await pxe.getTx(receipt.txHash); + const nonZeroCommitments = tx?.newCommitments.filter(c => c.value > 0); + expect(nonZeroCommitments?.length).toBe(1); + + // Add the note + const preimage = new NotePreimage([new Fr(value)]); + await wallet.addNote(wallet.getCompleteAddress().address, contract.address, new Fr(1), preimage, receipt.txHash); + + expect(await contract.methods.get_constant().view()).toEqual(value); + }); }); diff --git a/yarn-project/noir-contracts/src/contracts/test_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/test_contract/Nargo.toml index afa5e911ac9..be62c146701 100644 --- a/yarn-project/noir-contracts/src/contracts/test_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/test_contract/Nargo.toml @@ -6,4 +6,5 @@ type = "contract" [dependencies] aztec = { path = "../../../../aztec-nr/aztec" } +field_note = { path = "../../../../aztec-nr/field-note" } token_portal_content_hash_lib = { path = "../token_portal_content_hash_lib" } diff --git a/yarn-project/noir-contracts/src/contracts/test_contract/src/interface.nr b/yarn-project/noir-contracts/src/contracts/test_contract/src/interface.nr index 589fc69f397..1bb62e9f3f6 100644 --- a/yarn-project/noir-contracts/src/contracts/test_contract/src/interface.nr +++ b/yarn-project/noir-contracts/src/contracts/test_contract/src/interface.nr @@ -197,6 +197,18 @@ impl TestPrivateContextInterface { } + pub fn set_constant( + self, + context: &mut PrivateContext, + value: Field + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 1]; + serialized_args[0] = value; + + context.call_private_function(self.address, 0x1b3b9e18, serialized_args) + } + + pub fn test_code_gen( self, context: &mut PrivateContext, diff --git a/yarn-project/noir-contracts/src/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/test_contract/src/main.nr index 3b50aa2154a..b22de0d2894 100644 --- a/yarn-project/noir-contracts/src/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/test_contract/src/main.nr @@ -1,30 +1,51 @@ // A contract used for testing a random hodgepodge of small features from simulator and end-to-end tests. contract Test { + use dep::std::option::Option; + // docs:start:unencrypted_import use dep::aztec::log::emit_unencrypted_log; // docs:end:unencrypted_import use dep::aztec::{ + context::Context, abi, abi::PrivateContextInputs, hash::pedersen_hash, context::PrivateContext, + note::{ + note_header::NoteHeader, + utils as note_utils, + }, oracle::{ get_public_key::get_public_key as get_public_key_oracle, context::get_portal_address, rand::rand }, + state_vars::immutable_singleton::ImmutableSingleton, log::emit_unencrypted_log_from_private, types::vec::BoundedVec, constants_gen::EMPTY_NULLIFIED_COMMITMENT, }; use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash}; + use dep::field_note::field_note::{FieldNote, FieldNoteMethods, FIELD_NOTE_LEN}; #[event] struct ExampleEvent { value: Field, } + struct Storage { + example_constant: ImmutableSingleton, + } + + impl Storage { + fn init(context: Context) -> pub Self { + Storage { + example_constant: ImmutableSingleton::new(context, 1, FieldNoteMethods), + } + } + } + #[aztec(private)] // docs:start:empty-constructor fn constructor() {} @@ -177,6 +198,19 @@ contract Test { context.consume_l1_to_l2_message(msg_key, content_hash, secret_for_L1_to_L2_message_consumption); } + #[aztec(private)] + fn set_constant( + value: Field, + ) { + let mut note = FieldNote::new(value); + storage.example_constant.initialize(&mut note, Option::none(), false); + } + + unconstrained fn get_constant() -> Field { + let constant = storage.example_constant.view_note(); + constant.value + } + // Purely exists for testing unconstrained fn get_random( kindaSeed: Field @@ -208,4 +242,13 @@ contract Test { a_note: DummyNote, many_notes: [DummyNote; 3], } + + // Computes note hash and nullifier. + // Note 1: Needs to be defined by every contract producing logs. + // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. + unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, preimage: [Field; FIELD_NOTE_LEN]) -> [Field; 4] { + assert(storage_slot == 1); + let note_header = NoteHeader::new(contract_address, nonce, storage_slot); + note_utils::compute_note_hash_and_nullifier(FieldNoteMethods, note_header, preimage) + } }