From 6cbf7a6e9565290b7e2dbe071d8a08182aa3cf9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 23 Apr 2024 12:16:56 -0300 Subject: [PATCH] feat!: remove slow updates tree (#5954) With #5885 merged, we are no longer using the slow updates tree and can fully delete it. Docs have already been removed by #5884. --- Nargo.toml | 1 - slow-updates-tree/Nargo.toml | 8 - slow-updates-tree/src/leaf.nr | 20 --- slow-updates-tree/src/lib.nr | 8 - slow-updates-tree/src/slow_map.nr | 188 --------------------- slow-updates-tree/src/slow_update_proof.nr | 52 ------ 6 files changed, 277 deletions(-) delete mode 100644 slow-updates-tree/Nargo.toml delete mode 100644 slow-updates-tree/src/leaf.nr delete mode 100644 slow-updates-tree/src/lib.nr delete mode 100644 slow-updates-tree/src/slow_map.nr delete mode 100644 slow-updates-tree/src/slow_update_proof.nr diff --git a/Nargo.toml b/Nargo.toml index 94e4674..e3d50c4 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -6,7 +6,6 @@ members = [ "compressed-string", "easy-private-state", "field-note", - "slow-updates-tree", "value-note", "tests", ] diff --git a/slow-updates-tree/Nargo.toml b/slow-updates-tree/Nargo.toml deleted file mode 100644 index 9460f7c..0000000 --- a/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/slow-updates-tree/src/leaf.nr b/slow-updates-tree/src/leaf.nr deleted file mode 100644 index e5cda20..0000000 --- a/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/slow-updates-tree/src/lib.nr b/slow-updates-tree/src/lib.nr deleted file mode 100644 index b57ed50..0000000 --- a/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/slow-updates-tree/src/slow_map.nr b/slow-updates-tree/src/slow_map.nr deleted file mode 100644 index ddfaf6b..0000000 --- a/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/slow-updates-tree/src/slow_update_proof.nr b/slow-updates-tree/src/slow_update_proof.nr deleted file mode 100644 index 6f1b1d7..0000000 --- a/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 } - } - } -}