Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: emulating blocks and correct (non-partial) note discovery in txe #10356

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 166 additions & 0 deletions noir-projects/noir-contracts/contracts/counter_contract/src/main.nr
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please ignore while in draft, this file is the same as in the follow up pr in which this test acts like a smoke test. I will delete this comment once edited and out of draft.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// docs:start:setup
use dep::aztec::macros::aztec;
mod test;

#[aztec]
contract Counter {
Expand Down Expand Up @@ -41,6 +42,45 @@ contract Counter {
counters.at(owner).add(1, owner, sender);
}
// docs:end:increment

#[private]
fn increment_twice(owner: AztecAddress, sender: AztecAddress) {
unsafe {
dep::aztec::oracle::debug_log::debug_log_format(
"Incrementing counter twice for owner {0}",
[owner.to_field()],
);
}
let counters = storage.counters;
counters.at(owner).add(1, owner, sender);
counters.at(owner).add(1, owner, sender);
}

#[private]
fn increment_and_decrement(owner: AztecAddress, sender: AztecAddress) {
unsafe {
dep::aztec::oracle::debug_log::debug_log_format(
"Incrementing and decrementing counter for owner {0}",
[owner.to_field()],
);
}
let counters = storage.counters;
counters.at(owner).add(1, owner, sender);
counters.at(owner).sub(1, owner, sender);
}

#[private]
fn decrement(owner: AztecAddress, sender: AztecAddress) {
unsafe {
dep::aztec::oracle::debug_log::debug_log_format(
"Decrementing counter for owner {0}",
[owner.to_field()],
);
}
let counters = storage.counters;
counters.at(owner).sub(1, owner, sender);
}

// docs:start:get_counter
unconstrained fn get_counter(owner: AztecAddress) -> pub Field {
let counters = storage.counters;
Expand All @@ -49,10 +89,14 @@ contract Counter {

// docs:end:get_counter
// docs:start:test_imports
use dep::aztec::note::lifecycle::destroy_note;
use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes};
use dep::aztec::note::note_viewer_options::NoteViewerOptions;

use crate::test;
use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map;
use dep::aztec::test::helpers::test_environment::TestEnvironment;

// docs:end:test_imports
// docs:start:txe_test_increment
#[test]
Expand Down Expand Up @@ -91,4 +135,126 @@ contract Counter {
);
}
// docs:end:txe_test_increment

#[test]
unconstrained fn inclusion_proofs() {
let initial_value = 5;
let (env, contract_address, owner) = test::setup(initial_value);
env.advance_block_by(1);

env.impersonate(contract_address);
let counter_slot = Counter::storage_layout().counters.slot;
let owner_slot = derive_storage_slot_in_map(counter_slot, owner);
let mut options = NoteViewerOptions::new();
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
let initial_note_value = notes.get(0).value;
assert(
initial_note_value == initial_value,
f"Expected {initial_value} but got {initial_note_value}",
);

let old_note = notes.get(0);

env.private().get_block_header().prove_note_validity(old_note, &mut env.private());

destroy_note(&mut env.private(), old_note);
env.advance_block_by(1);

env.private().get_block_header().prove_note_is_nullified(old_note, &mut env.private());
env.private().get_block_header().prove_note_inclusion(old_note);

let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);

assert(notes.len() == 0);
}

#[test]
unconstrained fn extended_incrementing_and_decrementing() {
let initial_value = 5;
let (env, contract_address, owner, sender) = test::setup(initial_value);

// Checking from the note cache
env.impersonate(contract_address);
let counter_slot = Counter::storage_layout().counters.slot;
let owner_slot = derive_storage_slot_in_map(counter_slot, owner);
let mut options = NoteViewerOptions::new();
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
let initial_note_value = notes.get(0).value;
assert(
initial_note_value == initial_value,
f"Expected {initial_value} but got {initial_note_value}",
);

// Checking that the note was discovered from private logs
env.advance_block_by(1);
env.impersonate(contract_address);
let counter_slot = Counter::storage_layout().counters.slot;
let owner_slot = derive_storage_slot_in_map(counter_slot, owner);
let mut options = NoteViewerOptions::new();
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
let initial_note_value = notes.get(0).value;
assert(
initial_note_value == initial_value,
f"Expected {initial_value} but got {initial_note_value}",
);

Counter::at(contract_address).increment_twice(owner, sender).call(&mut env.private());

// Checking from the note cache
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
assert(notes.len() == 3);
assert(get_counter(owner) == 7);

// Checking that the note was discovered from private logs
env.advance_block_by(1);
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
assert(get_counter(owner) == 7);
assert(notes.len() == 3);

// Checking from the note cache
Counter::at(contract_address).increment_and_decrement(owner, sender).call(&mut env.private());
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
assert(get_counter(owner) == 7);
// We have a change note of 0
assert(notes.len() == 4);

// Checking that the note was discovered from private logs
env.advance_block_by(1);
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
assert(notes.len() == 4);
assert(get_counter(owner) == 7);

// Checking from the note cache, note that we MUST advance the block to get a correct and updated value.
Counter::at(contract_address).decrement(owner, sender).call(&mut env.private());
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
assert(get_counter(owner) == 11);
assert(notes.len() == 5);

// We advance the block here to have the nullification of the prior note be applied. Should we try nullifiying notes in our DB on notifyNullifiedNote ?
env.advance_block_by(1);
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
assert(get_counter(owner) == 6);
assert(notes.len() == 4);
}

#[test(should_fail)]
unconstrained fn inclusion_proofs_failure() {
let initial_value = 5;
let (env, contract_address, owner) = test::setup(initial_value);

env.impersonate(contract_address);
let counter_slot = Counter::storage_layout().counters.slot;
let owner_slot = derive_storage_slot_in_map(counter_slot, owner);
let mut options = NoteViewerOptions::new();
let notes: BoundedVec<ValueNote, MAX_NOTES_PER_PAGE> = view_notes(owner_slot, options);
let initial_note_value = notes.get(0).value;
assert(
initial_note_value == initial_value,
f"Expected {initial_value} but got {initial_note_value}",
);

let old_note = notes.get(0);

env.private().get_block_header().prove_note_validity(old_note, &mut env.private());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::Counter;
use dep::aztec::{prelude::AztecAddress, test::helpers::test_environment::TestEnvironment};

pub unconstrained fn setup(
initial_value: Field,
) -> (&mut TestEnvironment, AztecAddress, AztecAddress, AztecAddress) {
// Setup env, generate keys
let mut env = TestEnvironment::new();
let owner = env.create_account();
let sender = env.create_account();
env.impersonate(owner);
// Deploy contract and initialize
let initializer = Counter::interface().initialize(initial_value as u64, owner);
let counter_contract = env.deploy_self("Counter").with_private_initializer(initializer);
let contract_address = counter_contract.to_address();
(&mut env, contract_address, owner, sender)
}
4 changes: 1 addition & 3 deletions yarn-project/package.common.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@
"testTimeout": 30000,
"testRegex": "./src/.*\\.test\\.(js|mjs|ts)$",
"rootDir": "./src",
"setupFiles": [
"../../foundation/src/jest/setup.mjs"
]
"setupFiles": ["../../foundation/src/jest/setup.mjs"]
}
}
1 change: 1 addition & 0 deletions yarn-project/pxe/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from './database/index.js';
export * from './utils/index.js';
export { ContractDataOracle } from './contract_data_oracle/index.js';
export { PrivateFunctionsTree } from './contract_data_oracle/private_functions_tree.js';
export { SimulatorOracle } from './simulator_oracle/index.js';
12 changes: 11 additions & 1 deletion yarn-project/simulator/src/client/execution_note_cache.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { computeNoteHashNonce, computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
import { type AztecAddress } from '@aztec/foundation/aztec-address';
import { type Fr } from '@aztec/foundation/fields';
import { Fr } from '@aztec/foundation/fields';

import { type NoteData } from '../acvm/index.js';

Expand Down Expand Up @@ -146,4 +146,14 @@ export class ExecutionNoteCache {
notes.push(note);
this.noteMap.set(note.note.contractAddress.toBigInt(), notes);
}

getAllNotes(): PendingNote[] {
return this.notes;
}

getAllNullifiers(): Fr[] {
return [...this.nullifierMap.values()].flatMap(nullifierArray =>
[...nullifierArray.values()].map(val => new Fr(val)),
);
}
}
Loading
Loading