-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduce initialize_or_replace (#6519)
This fixes the issue described in [these comments](AztecProtocol/aztec-packages#6442 (comment)), which highlighted that `PrivateMutable` was providing a poor API as it forced users to call unconstrained functions and leave correctness up to them. This is a simple replacement to make #6442 cleaner and help guide future development, but it should only be considered a patch - we'll eventually do a more thoughtful complete pass over the entire API to bring coherency to it. I tried adding tests for this (I wanted to test that regardless what the return value of the nullifier check oracle was, either an inclusion proof or a new nullifier would be included in the context), but this proved to be very hard because notes are sent to the oracle as raw fields in a custom packed format which `oracle::get_notes` decodes on the spot. We'd need to have that be a separate library, but that exceeds the scope of this PR.
- Loading branch information
Showing
2 changed files
with
80 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; | ||
use crate::{context::PrivateContext, state_vars::private_mutable::PrivateMutable}; | ||
use crate::test::{mocks::mock_note::MockNote, helpers::context_builder::ContextBuilder}; | ||
use dep::std::{unsafe::zeroed, test::OracleMock}; | ||
|
||
global contract_address = AztecAddress::from_field(13); | ||
global storage_slot = 17; | ||
|
||
fn setup() -> PrivateMutable<MockNote, &mut PrivateContext> { | ||
let mut context = ContextBuilder::new().contract_address(contract_address).private(); | ||
let state_var = PrivateMutable::new(&mut context, storage_slot); | ||
|
||
// This oracle is called for its side effects alone - it's always expected to return 0. | ||
OracleMock::mock("notifyCreatedNote").returns(0); | ||
|
||
state_var | ||
} | ||
|
||
#[test] | ||
fn test_initialize_or_replace_without_nullifier() { | ||
let state_var = setup(); | ||
|
||
let ivpk_m: GrumpkinPoint = zeroed(); | ||
let broadcast = false; | ||
|
||
let value = 42; | ||
let mut note = MockNote::new(value).contract_address(contract_address).storage_slot(storage_slot).build(); | ||
|
||
OracleMock::mock("checkNullifierExists").returns(0); | ||
state_var.initialize_or_replace(&mut note, broadcast, ivpk_m); | ||
|
||
// Since we reported there was no nullifier, we should initialize and see the following side-effects: | ||
// - a new note being created | ||
// - no notes being read | ||
// - the initialization nullifier being emitted | ||
assert_eq(state_var.context.new_note_hashes.len(), 1); | ||
assert_eq(state_var.context.note_hash_read_requests.len(), 0); | ||
assert_eq(state_var.context.new_nullifiers.len(), 1); | ||
|
||
// Note that if the oracle was wrong and the initialization nullifier did exist, this attempt to write it again | ||
// would cause the sequencer to revert this transaction - we are therefore safe from bad oracles. | ||
let nullifier = state_var.context.new_nullifiers.get(0); | ||
assert_eq(nullifier.value, state_var.compute_initialization_nullifier()); | ||
assert_eq(nullifier.note_hash, 0); | ||
} | ||
|
||
#[test] | ||
fn test_initialize_or_replace_with_nullifier() { | ||
// Here we'd want to test a scenario like the one above with the oracle indicating that the initialization | ||
// nullifier does exist. Unfortunately that requires us to produce a valid oracle return value for getNotes, | ||
// which is fairly involved as it deals with serialization of notes, and is relatively complicated to replicate | ||
// in Noir. | ||
} |