From f4c9edbb2b0fa680e2559b5fda031a6cbd7f1dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 23 Apr 2024 14:10:50 +0000 Subject: [PATCH] Remove slow updates --- .../writing_contracts/oracles/pop_capsule.md | 6 +- .../sandbox/references/sandbox-reference.md | 1 - docs/docs/misc/migration_notes.md | 22 ++ noir-projects/aztec-nr/Nargo.toml | 1 - .../aztec-nr/slow-updates-tree/Nargo.toml | 8 - .../aztec-nr/slow-updates-tree/src/leaf.nr | 20 -- .../aztec-nr/slow-updates-tree/src/lib.nr | 8 - .../slow-updates-tree/src/slow_map.nr | 188 ------------------ .../src/slow_update_proof.nr | 52 ----- noir-projects/noir-contracts/Nargo.toml | 1 - .../src/capsule.nr | 3 +- .../src/main.nr | 4 + .../contracts/slow_tree_contract/Nargo.toml | 9 - .../slow_tree_contract/src/capsule.nr | 10 - .../contracts/slow_tree_contract/src/main.nr | 142 ------------- .../contracts/slow_tree_contract/src/types.nr | 33 --- .../token_blacklist_contract/Nargo.toml | 3 +- .../end-to-end/src/e2e_slow_tree.test.ts | 153 -------------- 18 files changed, 32 insertions(+), 632 deletions(-) delete mode 100644 noir-projects/aztec-nr/slow-updates-tree/Nargo.toml delete mode 100644 noir-projects/aztec-nr/slow-updates-tree/src/leaf.nr delete mode 100644 noir-projects/aztec-nr/slow-updates-tree/src/lib.nr delete mode 100644 noir-projects/aztec-nr/slow-updates-tree/src/slow_map.nr delete mode 100644 noir-projects/aztec-nr/slow-updates-tree/src/slow_update_proof.nr delete mode 100644 noir-projects/noir-contracts/contracts/slow_tree_contract/Nargo.toml delete mode 100644 noir-projects/noir-contracts/contracts/slow_tree_contract/src/capsule.nr delete mode 100644 noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr delete mode 100644 noir-projects/noir-contracts/contracts/slow_tree_contract/src/types.nr delete mode 100644 yarn-project/end-to-end/src/e2e_slow_tree.test.ts diff --git a/docs/docs/developers/contracts/writing_contracts/oracles/pop_capsule.md b/docs/docs/developers/contracts/writing_contracts/oracles/pop_capsule.md index a364be5d881..6c150b7ec71 100644 --- a/docs/docs/developers/contracts/writing_contracts/oracles/pop_capsule.md +++ b/docs/docs/developers/contracts/writing_contracts/oracles/pop_capsule.md @@ -12,16 +12,16 @@ On this page you will learn how to use the `popCapsule` oracle. To see what othe In a new file on the same level as your `main.nr`, implement an unconstrained function that calls the pop_capsule oracle: -#include_code pop_capsule noir-projects/noir-contracts/contracts/slow_tree_contract/src/capsule.nr rust +#include_code pop_capsule noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr rust ### 2. Import this into your smart contract If it lies in the same directory as your smart contract, you can import it like this: -#include_code import_pop_capsule noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr rust +#include_code import_pop_capsule noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr rust ### 3. Use it as any other oracle Now it becomes a regular oracle you can call like this: -#include_code pop_capsule noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr rust +#include_code pop_capsule noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr rust diff --git a/docs/docs/developers/sandbox/references/sandbox-reference.md b/docs/docs/developers/sandbox/references/sandbox-reference.md index 8ce365cdf2a..512ef3e31af 100644 --- a/docs/docs/developers/sandbox/references/sandbox-reference.md +++ b/docs/docs/developers/sandbox/references/sandbox-reference.md @@ -197,7 +197,6 @@ PriceFeedContractArtifact SchnorrAccountContractArtifact SchnorrHardcodedAccountContractArtifact SchnorrSingleKeyAccountContractArtifact -SlowTreeContractArtifact StatefulTestContractArtifact TestContractArtifact TokenBlacklistContractArtifact diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index 731f78a774e..ed02683b00b 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -8,6 +8,28 @@ Aztec is in full-speed development. Literally every version breaks compatibility ## 0.36.0 +## `SlowUpdatesTree` replaced for `SharedMutable` + +The old `SlowUpdatesTree` contract and libraries have been removed from the codebase, use the new `SharedMutable` library instead. This will require that you add a global variable specifying a delay in blocks for updates, and replace the slow updates tree state variable with `SharedMutable` variables. + +```diff ++ global CHANGE_ROLES_DELAY_BLOCKS = 5; + +struct Storage { +- slow_update: SharedImmutable, ++ roles: Map>, +} +``` + +Reading from `SharedMutable` is much simpler, all that's required is to call `get_current_value_in_public` or `get_current_value_in_private`, depending on the domain. + +```diff +- let caller_roles = UserFlags::new(U128::from_integer(slow.read_at_pub(context.msg_sender().to_field()).call(&mut context))); ++ let caller_roles = storage.roles.at(context.msg_sender()).get_current_value_in_public(); +``` + +Finally, you can remove all capsule usage on the client code or tests, since those are no longer required when working with `SharedMutable`. + ## [Aztec.nr & js] Portal addresses Deployments have been modified. No longer are portal addresses treated as a special class, being immutably set on creation of a contract. They are no longer passed in differently compared to the other variables and instead should be implemented using usual storage by those who require it. One should use the storage that matches the usecase - likely shared storage to support private and public. diff --git a/noir-projects/aztec-nr/Nargo.toml b/noir-projects/aztec-nr/Nargo.toml index 94e4674f336..e3d50c4968d 100644 --- a/noir-projects/aztec-nr/Nargo.toml +++ b/noir-projects/aztec-nr/Nargo.toml @@ -6,7 +6,6 @@ members = [ "compressed-string", "easy-private-state", "field-note", - "slow-updates-tree", "value-note", "tests", ] diff --git a/noir-projects/aztec-nr/slow-updates-tree/Nargo.toml b/noir-projects/aztec-nr/slow-updates-tree/Nargo.toml deleted file mode 100644 index 9460f7c31cf..00000000000 --- a/noir-projects/aztec-nr/slow-updates-tree/Nargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "slow_updates_tree" -authors = ["aztec-labs"] -compiler_version = ">=0.18.0" -type = "lib" - -[dependencies] -aztec = { path = "../aztec" } \ No newline at end of file diff --git a/noir-projects/aztec-nr/slow-updates-tree/src/leaf.nr b/noir-projects/aztec-nr/slow-updates-tree/src/leaf.nr deleted file mode 100644 index e5cda208efb..00000000000 --- a/noir-projects/aztec-nr/slow-updates-tree/src/leaf.nr +++ /dev/null @@ -1,20 +0,0 @@ -use dep::aztec::protocol_types::traits::{Serialize, Deserialize}; - -// A leaf in the tree. -struct Leaf { - next_change: Field, - before: Field, - after: Field, -} - -impl Serialize<3> for Leaf { - fn serialize(leaf: Leaf) -> [Field; 3] { - [leaf.next_change, leaf.before, leaf.after] - } -} - -impl Deserialize<3> for Leaf { - fn deserialize(serialized: [Field; 3]) -> Leaf { - Leaf { next_change: serialized[0], before: serialized[1], after: serialized[2] } - } -} diff --git a/noir-projects/aztec-nr/slow-updates-tree/src/lib.nr b/noir-projects/aztec-nr/slow-updates-tree/src/lib.nr deleted file mode 100644 index b57ed505243..00000000000 --- a/noir-projects/aztec-nr/slow-updates-tree/src/lib.nr +++ /dev/null @@ -1,8 +0,0 @@ -mod leaf; -mod slow_map; -mod slow_update_proof; - -use crate::leaf::Leaf; -use crate::slow_map::SlowMap; -use crate::slow_update_proof::{deserialize_slow_update_proof, SlowUpdateProof}; -use dep::std::merkle::compute_merkle_root; diff --git a/noir-projects/aztec-nr/slow-updates-tree/src/slow_map.nr b/noir-projects/aztec-nr/slow-updates-tree/src/slow_map.nr deleted file mode 100644 index ddfaf6bfa03..00000000000 --- a/noir-projects/aztec-nr/slow-updates-tree/src/slow_map.nr +++ /dev/null @@ -1,188 +0,0 @@ -use crate::{leaf::Leaf, slow_update_proof::SlowUpdateProof}; -use dep::aztec::{ - context::Context, oracle::storage::{storage_read, storage_write}, - protocol_types::traits::{Serialize, Deserialize} -}; -use dep::std::hash::pedersen_hash; -use dep::std::merkle::compute_merkle_root; - -// The epoch length is just a random number for now. -global EPOCH_LENGTH: u64 = 100; - -fn compute_next_change(time: Field) -> Field { - ((time as u64 / EPOCH_LENGTH + 1) * EPOCH_LENGTH) as Field -} - -// TODO(#4760): Rename slow updates to shared mutable and ideally move the impl to state-vars in aztec-nr. -// The simple slow map which stores a sparse tree -struct SlowMap { - context: Context, - storage_slot: Field -} - -impl SlowMap { - pub fn new(context: Context, storage_slot: Field) -> Self { - assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Self { context, storage_slot } - } - - pub fn read_root(self: Self) -> Leaf { - let fields = storage_read(self.storage_slot); - Leaf::deserialize(fields) - } - - // Beware that the initial root could include much state that is not shown by the public storage! - pub fn initialize(self: Self, initial_root: Field) { - let mut root_object = self.read_root(); - assert(root_object.next_change == 0, "cannot initialize twice"); - root_object = Leaf { - next_change: 0xffffffffffffffffffffffffffffff, - before: initial_root, - after: initial_root, - }; - let fields = root_object.serialize(); - storage_write(self.storage_slot, fields); - } - - // Reads the "CURRENT" value of the root - pub fn current_root(self: Self) -> Field { - let time = self.context.public.unwrap().timestamp(); - let root_object = self.read_root(); - if time <= root_object.next_change as u64 { - root_object.before - } else { - root_object.after - } - } - - // docs:start:read_leaf_at - pub fn read_leaf_at(self: Self, key: Field) -> Leaf { - let derived_storage_slot = pedersen_hash([self.storage_slot, key]); - let fields = storage_read(derived_storage_slot); - Leaf::deserialize(fields) - } - // docs:end:read_leaf_at - - // docs:start:read_at - // Reads the "CURRENT" value of the leaf - pub fn read_at(self: Self, key: Field) -> Field { - let time = self.context.public.unwrap().timestamp(); - let leaf = self.read_leaf_at(key); - if time <= leaf.next_change as u64 { - leaf.before - } else { - leaf.after - } - } - // docs:end:read_at - - // Will update values in the "AFTER" tree - // - updates the leaf and root to follow current values, moving from after to before if - // needed. - // - checks that the provided merkle paths match state values - // - update the leaf and compute the net root - // Should only be used when updates from public are desired, since the hashing will be - // costly since done by sequencer. - pub fn update_at(self: Self, p: SlowUpdateProof) { - // The calling function should ensure that the index is within the tree. - // This must be done separately to ensure we are not constraining too tight here. - - let time = self.context.public.unwrap().timestamp(); - let next_change = compute_next_change(time as Field); - - let mut root = self.read_root(); - let mut leaf = self.read_leaf_at(p.index); - - // Move leaf if needed - if time > leaf.next_change as u64 { - leaf.before = leaf.after; - } - - // Move root if needed - if time > root.next_change as u64 { - root.before = root.after; - } - - // Ensures that when before is active, it is not altered by this update - assert( - root.before == compute_merkle_root(leaf.before, p.index, p.before.sibling_path), "Before root don't match" - ); - - // Ensures that the provided sibling path is valid for the CURRENT "after" tree. - // Without this check, someone could provide a sibling path for a different tree - // and update the entire "after" tree at once, causing it to be out of sync with leaf storage. - assert( - root.after == compute_merkle_root(leaf.after, p.index, p.after.sibling_path), "After root don't match" - ); - - // Update the leaf - leaf.after = p.new_value; - leaf.next_change = next_change; - - // Update the after root - root.after = compute_merkle_root(leaf.after, p.index, p.after.sibling_path); - root.next_change = next_change; - - self.update_unsafe(p.index, leaf, root); - } - - // A variation of `update_at` that skips the merkle-membership checks. - // To be used by a contract which has already checked the merkle-membership. - // This allows us to check the merkle-memberships in private and then update - // in public, limiting the cost of the update. - pub fn update_unsafe_at(self: Self, index: Field, leaf_value: Field, new_root: Field) { - // User must ensure that the checks from update_at is performed for safety - let time = self.context.public.unwrap().timestamp(); - let next_change = compute_next_change(time as Field); - - let mut root = self.read_root(); - let mut leaf = self.read_leaf_at(index); - - // Move leaf if needed - if time > leaf.next_change as u64 { - leaf.before = leaf.after; - } - - // Move root if needed - if time > root.next_change as u64 { - root.before = root.after; - } - - // Update the leaf - leaf.after = leaf_value; - leaf.next_change = next_change; - - // Update the root - root.after = new_root; - root.next_change = next_change; - - self.update_unsafe(index, leaf, root); - } - - // Updates the value in the in storage with no checks. - fn update_unsafe(self: Self, index: Field, leaf: Leaf, root: Leaf) { - let derived_storage_slot = pedersen_hash([self.storage_slot, index]); - let fields = leaf.serialize(); - storage_write(derived_storage_slot, fields); - - let fields = root.serialize(); - storage_write(self.storage_slot, fields); - } -} - -/*pub fn compute_merkle_root(leaf: Field, index: Field, hash_path: [Field; N]) -> Field { - let n = hash_path.len(); - let index_bits = index.to_le_bits(n as u32); - let mut current = leaf; - for i in 0..n { - let path_bit = index_bits[i] as bool; - let (hash_left, hash_right) = if path_bit { - (hash_path[i], current) - } else { - (current, hash_path[i]) - }; - current = pedersen_hash([hash_left, hash_right]); - }; - current -} -*/ diff --git a/noir-projects/aztec-nr/slow-updates-tree/src/slow_update_proof.nr b/noir-projects/aztec-nr/slow-updates-tree/src/slow_update_proof.nr deleted file mode 100644 index 6f1b1d79a0f..00000000000 --- a/noir-projects/aztec-nr/slow-updates-tree/src/slow_update_proof.nr +++ /dev/null @@ -1,52 +0,0 @@ -// Subset of the MembershipProof that is needed for the slow update. -struct SlowUpdateInner { - value: Field, // Value only really used for the private flow though :thinking: - sibling_path: [Field; N], -} - -// The slow update proof. Containing two merkle paths -// One for the before and one for the after trees. -// M = 2 * N + 4 -struct SlowUpdateProof { - index: Field, - new_value: Field, - before: SlowUpdateInner, - after: SlowUpdateInner, -} - -pub fn deserialize_slow_update_proof(serialized: [Field; M]) -> SlowUpdateProof { - SlowUpdateProof::deserialize(serialized) -} - -impl SlowUpdateProof { - pub fn serialize(self: Self) -> [Field; M] { - let mut serialized = [0; M]; - serialized[0] = self.index; - serialized[1] = self.new_value; - serialized[2] = self.before.value; - serialized[3 + N] = self.after.value; - - for i in 0..N { - serialized[3 + i] = self.before.sibling_path[i]; - serialized[4 + N + i] = self.after.sibling_path[i]; - } - serialized - } - - pub fn deserialize(serialized: [Field; M]) -> Self { - let mut before_sibling_path = [0; N]; - let mut after_sibling_path = [0; N]; - - for i in 0..N { - before_sibling_path[i] = serialized[3 + i]; - after_sibling_path[i] = serialized[4 + N + i]; - } - - Self { - index: serialized[0], - new_value: serialized[1], - before: SlowUpdateInner { value: serialized[2], sibling_path: before_sibling_path }, - after: SlowUpdateInner { value: serialized[3 + N], sibling_path: after_sibling_path } - } - } -} diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index b3d1c57c752..38a37c0083b 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -33,7 +33,6 @@ members = [ "contracts/schnorr_account_contract", "contracts/schnorr_hardcoded_account_contract", "contracts/schnorr_single_key_account_contract", - "contracts/slow_tree_contract", "contracts/stateful_test_contract", "contracts/test_contract", "contracts/token_contract", diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr index d77649e6b28..8ce37646e61 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr @@ -1,6 +1,6 @@ -// Copied from noir-contracts/contracts/slow_tree_contract/src/capsule.nr // We should extract this to a shared lib in aztec-nr once we settle on a design for capsules +// docs:start:pop_capsule #[oracle(popCapsule)] fn pop_capsule_oracle() -> [Field; N] {} @@ -8,3 +8,4 @@ fn pop_capsule_oracle() -> [Field; N] {} unconstrained pub fn pop_capsule() -> [Field; N] { pop_capsule_oracle() } +// docs:end:pop_capsule \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 9857b3e6f3e..8cb01885ccd 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -18,14 +18,18 @@ contract ContractClassRegisterer { unconstrained_function_broadcasted::{ClassUnconstrainedFunctionBroadcasted, UnconstrainedFunction} }; + // docs:start:import_pop_capsule use crate::capsule::pop_capsule; + // docs:end:import_pop_capsule #[aztec(private)] fn register(artifact_hash: Field, private_functions_root: Field, public_bytecode_commitment: Field) { // TODO: Validate public_bytecode_commitment is the correct commitment of packed_public_bytecode // TODO: Validate packed_public_bytecode is legit public bytecode + // docs:start:pop_capsule let packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS] = pop_capsule(); + // docs:end:pop_capsule // Compute contract class id from preimage let contract_class_id = ContractClassId::compute( diff --git a/noir-projects/noir-contracts/contracts/slow_tree_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/slow_tree_contract/Nargo.toml deleted file mode 100644 index 2edcc357b5a..00000000000 --- a/noir-projects/noir-contracts/contracts/slow_tree_contract/Nargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "slow_tree_contract" -authors = [""] -compiler_version = ">=0.25.0" -type = "contract" - -[dependencies] -aztec = { path = "../../../aztec-nr/aztec" } -slow_updates_tree = { path = "../../../aztec-nr/slow-updates-tree" } diff --git a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/capsule.nr b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/capsule.nr deleted file mode 100644 index 7a00e3354f1..00000000000 --- a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/capsule.nr +++ /dev/null @@ -1,10 +0,0 @@ -// docs:start:pop_capsule -#[oracle(popCapsule)] -fn pop_capsule_oracle() -> [Field; N] {} - -// A capsule is a "blob" of data that is passed to the contract through an oracle. -unconstrained pub fn pop_capsule() -> [Field; N] { - pop_capsule_oracle() -} -// docs:end:pop_capsule - diff --git a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr deleted file mode 100644 index f71c2ff62c5..00000000000 --- a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr +++ /dev/null @@ -1,142 +0,0 @@ -mod capsule; -mod types; - -// This contract allow us to "read" public storage in private through a delayed tree. -// More documentation need to be outlined for this properly, but there is some in -// https://github.com/AztecProtocol/aztec-packages/issues/1291 -// This is made as a separate contract for one thing mainly. Making it simpler to use. -// TODO(#4760): Rename slow updates to shared mutable and ideally move the impl to state-vars in aztec-nr. -contract SlowTree { - use dep::aztec::prelude::{ - AztecAddress, FunctionSelector, NoteHeader, NoteInterface, NoteViewerOptions, PrivateContext, - Map, PublicMutable, PrivateSet - }; - - use dep::aztec::{context::{PublicContext, Context}, protocol_types::type_serialization::FIELD_SERIALIZED_LEN}; - use dep::slow_updates_tree::{SlowMap, Leaf, SlowUpdateProof, compute_merkle_root, deserialize_slow_update_proof}; - - // docs:start:import_pop_capsule - use crate::capsule::pop_capsule; - // docs:end:import_pop_capsule - use crate::types::{MembershipProof, deserialize_membership_proof}; - - // docs:start:constants_and_storage - global TREE_HEIGHT: u64 = 254; - global MEMBERSHIP_SIZE: Field = 256; // TREE_HEIGHT + 2 - global UPDATE_SIZE: Field = 512; // TREE_HEIGHT * 2 + 4 - - global EMPTY_ROOT: Field = 5785871043333994658400733180052743689641713274194136017445890613179954325976; - - #[aztec(storage)] - struct Storage { - trees: Map>, - } - // docs:end:constants_and_storage - - // docs:start:initialize - #[aztec(public)] - fn initialize() { - storage.trees.at(context.msg_sender().to_field()).initialize(EMPTY_ROOT); - } - // docs:end:initialize - // docs:start:read_at_pub - #[aztec(public)] - fn read_at_pub(key: Field) -> Field { - storage.trees.at(context.msg_sender().to_field()).read_at(key) - } - // docs:end:read_at_pub - #[aztec(public)] - fn read_leaf_at_pub(key: Field) -> Leaf { - storage.trees.at(context.msg_sender().to_field()).read_leaf_at(key) - } - // docs:start:read_at_private - #[aztec(private)] - fn read_at(index: Field) -> Field { - // docs:start:pop_capsule - let fields = pop_capsule(); - // docs:end:pop_capsule - let p: MembershipProof = deserialize_membership_proof(fields); - assert(index == p.index, "Index does not match expected"); - - let expected_root = compute_merkle_root(p.value, p.index, p.sibling_path); - let selector = FunctionSelector::from_signature("_assert_current_root(Field,Field)"); - context.call_public_function( - context.this_address(), - selector, - [context.msg_sender().to_field(), expected_root] - ); - - p.value - } - // docs:end:read_at_private - // docs:start:assert_current_root - #[aztec(public)] - #[aztec(internal)] - fn _assert_current_root(caller: Field, expected: Field) { - let root = storage.trees.at(caller).current_root(); - assert(root == expected, "Root does not match expected"); - } - // docs:end:assert_current_root - - // docs:start:update_at_pub - #[aztec(public)] - fn update_at_public(p: SlowUpdateProof) { - storage.trees.at(context.msg_sender().to_field()).update_at(p); - } - // docs:end:update_at_pub - // docs:start:update_at_private - #[aztec(private)] - fn update_at_private(index: Field, new_value: Field) { - let fields = pop_capsule(); - let p: SlowUpdateProof = deserialize_slow_update_proof(fields); - assert(index == p.index, "Index does not match expected"); - assert(new_value == p.new_value, "New value does not match expected"); - - // We compute the root before. - let before_root = compute_merkle_root(p.before.value, p.index, p.before.sibling_path); - let after_root = compute_merkle_root(p.after.value, p.index, p.after.sibling_path); - let new_after_root = compute_merkle_root(p.new_value, p.index, p.after.sibling_path); - - let selector = FunctionSelector::from_signature("_update(Field,Field,Field,Field,Field,Field)"); - context.call_public_function( - context.this_address(), - selector, - [ - context.msg_sender().to_field(), - p.index, - p.new_value, - before_root, - after_root, - new_after_root - ] - ); - } - // docs:end:update_at_private - // docs:start:_update - #[aztec(public)] - #[aztec(internal)] - fn _update( - caller: Field, - index: Field, - new_value: Field, - before: Field, - after: Field, - new_root: Field - ) { - let current_root = storage.trees.at(caller).current_root(); - let after_root = storage.trees.at(caller).read_root().after; - - assert(current_root == before, "Before root does not match expected"); - assert(after_root == after, "After root does not match expected"); - - storage.trees.at(caller).update_unsafe_at(index, new_value, new_root); - } - // docs:end:_update - unconstrained fn un_read_leaf_at(address: AztecAddress, key: Field) -> pub Leaf { - storage.trees.at(address.to_field()).read_leaf_at(key) - } - - unconstrained fn un_read_root(address: AztecAddress) -> pub Leaf { - storage.trees.at(address.to_field()).read_root() - } -} diff --git a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/types.nr b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/types.nr deleted file mode 100644 index 58b934e7aa7..00000000000 --- a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/types.nr +++ /dev/null @@ -1,33 +0,0 @@ -// docs:start:membership_proof -// A single inclusion proof. -// M = N + 2 -struct MembershipProof { - index: Field, - value: Field, - sibling_path: [Field; N], -} -// docs:end:membership_proof - -fn deserialize_membership_proof(serialized: [Field; M]) -> MembershipProof { - let mut sibling_path = [0; N]; - for i in 0..N { - sibling_path[i] = serialized[2 + i]; - } - MembershipProof { index: serialized[0], value: serialized[1], sibling_path } -} - -impl MembershipProof { - fn serialize(self: Self) -> [Field; M] { - let mut serialized = [0; M]; - serialized[0] = self.index; - serialized[1] = self.value; - for i in 0..N { - serialized[2 + i] = self.sibling_path[i]; - } - serialized - } - - fn deserialize(serialized: [Field; M]) -> Self { - deserialize_membership_proof(serialized) - } -} diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/token_blacklist_contract/Nargo.toml index 54bc420b804..ee4f8aa622b 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/Nargo.toml @@ -7,5 +7,4 @@ type = "contract" [dependencies] aztec = { path = "../../../aztec-nr/aztec" } field_note = { path = "../../../aztec-nr/field-note" } -authwit = { path = "../../../aztec-nr/authwit" } -slow_tree = { path = "../slow_tree_contract" } \ No newline at end of file +authwit = { path = "../../../aztec-nr/authwit" } \ No newline at end of file diff --git a/yarn-project/end-to-end/src/e2e_slow_tree.test.ts b/yarn-project/end-to-end/src/e2e_slow_tree.test.ts deleted file mode 100644 index b1f583e9e54..00000000000 --- a/yarn-project/end-to-end/src/e2e_slow_tree.test.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* eslint-disable camelcase */ -import { type CheatCodes, type DebugLogger, Fr, type Wallet } from '@aztec/aztec.js'; -import { openTmpStore } from '@aztec/kv-store/utils'; -import { Pedersen, SparseTree, newTree } from '@aztec/merkle-tree'; -import { SlowTreeContract } from '@aztec/noir-contracts.js/SlowTree'; - -import { setup } from './fixtures/utils.js'; - -describe('e2e_slow_tree', () => { - let logger: DebugLogger; - let wallet: Wallet; - let teardown: () => Promise; - - let contract: SlowTreeContract; - let cheatCodes: CheatCodes; - - beforeAll(async () => { - ({ teardown, logger, wallet, cheatCodes } = await setup()); - contract = await SlowTreeContract.deploy(wallet).send().deployed(); - }, 100_000); - - afterAll(() => teardown()); - - it('Messing around with noir slow tree', async () => { - const depth = 254; - const slowUpdateTreeSimulator = await newTree(SparseTree, openTmpStore(), new Pedersen(), 'test', Fr, depth); - const getMembershipProof = async (index: bigint, includeUncommitted: boolean) => { - return { - index, - value: slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted)!, - // eslint-disable-next-line camelcase - sibling_path: (await slowUpdateTreeSimulator.getSiblingPath(index, includeUncommitted)).toFields(), - }; - }; - - const getMembershipCapsule = (proof: { index: bigint; value: Fr; sibling_path: Fr[] }) => { - return [new Fr(proof.index), proof.value, ...proof.sibling_path]; - }; - - const getUpdateProof = async (newValue: bigint, index: bigint) => { - const beforeProof = await getMembershipProof(index, false); - const afterProof = await getMembershipProof(index, true); - - return { - index, - // eslint-disable-next-line camelcase - new_value: newValue, - // eslint-disable-next-line camelcase - before: { value: beforeProof.value, sibling_path: beforeProof.sibling_path }, - // eslint-disable-next-line camelcase - after: { value: afterProof.value, sibling_path: afterProof.sibling_path }, - }; - }; - - const getUpdateCapsule = (proof: { - index: bigint; - new_value: bigint; - before: { value: Fr; sibling_path: Fr[] }; - after: { value: Fr; sibling_path: Fr[] }; - }) => { - return [ - new Fr(proof.index), - new Fr(proof.new_value), - proof.before.value, - ...proof.before.sibling_path, - proof.after.value, - ...proof.after.sibling_path, - ]; - }; - - const status = async ( - key: bigint, - _root: { before: bigint; after: bigint; next_change: bigint }, - _leaf: { before: bigint; after: bigint; next_change: bigint }, - ) => { - const root = await contract.methods.un_read_root(owner).simulate(); - const leaf = await contract.methods.un_read_leaf_at(owner, key).simulate(); - expect(root).toEqual(_root); - expect(leaf).toEqual(_leaf); - }; - - const owner = wallet.getCompleteAddress().address; - const key = owner.toBigInt(); - - await contract.methods.initialize().send().wait(); - - const computeNextChange = (ts: bigint) => (ts / 100n + 1n) * 100n; - - let _root = { - before: Fr.fromBuffer(slowUpdateTreeSimulator.getRoot(true)).toBigInt(), - after: Fr.fromBuffer(slowUpdateTreeSimulator.getRoot(true)).toBigInt(), - next_change: 2n ** 120n - 1n, - }; - let _leaf = { before: 0n, after: 0n, next_change: 0n }; - await status(key, _root, _leaf); - await wallet.addCapsule(getMembershipCapsule(await getMembershipProof(key, true))); - await contract.methods.read_at(key).send().wait(); - - logger.info(`Updating tree[${key}] to 1 from public`); - const t1 = computeNextChange(BigInt(await cheatCodes.eth.timestamp())); - await contract.methods - .update_at_public(await getUpdateProof(1n, key)) - .send() - .wait(); - await slowUpdateTreeSimulator.updateLeaf(new Fr(1), key); - - // Update below. - _root = { - ..._root, - after: Fr.fromBuffer(slowUpdateTreeSimulator.getRoot(true)).toBigInt(), - next_change: t1, - }; - _leaf = { ..._leaf, after: 1n, next_change: t1 }; - await status(key, _root, _leaf); - - const zeroProof = await getMembershipProof(key, false); - logger.info(`"Reads" tree[${zeroProof.index}] from the tree, equal to ${zeroProof.value}`); - await wallet.addCapsule(getMembershipCapsule({ ...zeroProof, value: new Fr(0) })); - await contract.methods.read_at(key).send().wait(); - - // Progress time to beyond the update and thereby commit it to the tree. - await cheatCodes.aztec.warp((await cheatCodes.eth.timestamp()) + 1000); - await slowUpdateTreeSimulator.commit(); - logger.info('--- Progressing time to after the update ---'); - await status(key, _root, _leaf); - - logger.info( - `Tries to "read" tree[${zeroProof.index}] from the tree, but is rejected as value is not ${zeroProof.value}`, - ); - await wallet.addCapsule(getMembershipCapsule({ ...zeroProof, value: new Fr(0) })); - await expect(contract.methods.read_at(key).prove()).rejects.toThrow( - /Assertion failed: Root does not match expected/, - ); - - logger.info(`"Reads" tree[${key}], expect to be 1`); - await wallet.addCapsule(getMembershipCapsule({ ...zeroProof, value: new Fr(1) })); - await contract.methods.read_at(key).send().wait(); - - logger.info(`Updating tree[${key}] to 4 from private`); - const t2 = computeNextChange(BigInt(await cheatCodes.eth.timestamp())); - await wallet.addCapsule(getUpdateCapsule(await getUpdateProof(4n, key))); - await contract.methods.update_at_private(key, 4n).send().wait(); - await slowUpdateTreeSimulator.updateLeaf(new Fr(4), key); - _root = { - before: Fr.fromBuffer(slowUpdateTreeSimulator.getRoot(false)).toBigInt(), - after: Fr.fromBuffer(slowUpdateTreeSimulator.getRoot(true)).toBigInt(), - next_change: t2, - }; - _leaf = { before: 1n, after: 4n, next_change: t2 }; - - await status(key, _root, _leaf); - }, 200_000); -});