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(zkos): Implement ZK OS Merkle tree #3625

Open
wants to merge 32 commits into
base: main
Choose a base branch
from

Conversation

slowli
Copy link
Contributor

@slowli slowli commented Feb 19, 2025

What ❔

Implements a persistent Merkle tree for ZK OS using RocksDB and amortized design similar to Jellyfish Merkle tree used for Era.

Some stuff in the PR is preliminary:

  • Batch insertion proofs don't support read operations and are constructed slightly differently compared to the in-memory tree.
  • There are no metrics (but there are logs with latencies / stats for key operations).
  • No reader APIs.
  • No pruning.

Why ❔

ZK OS will need a persistent Merkle tree sooner or later. Amortized versioned design looks like a good choice (although not as good as for sparse Merkle trees, since internal nodes are almost guaranteed to be full in this case).

Is this a breaking change?

  • Yes
  • No

Operational changes

None.

Checklist

  • PR title corresponds to the body of PR (we generate changelog entries from PRs).
  • Tests for the changes have been added / updated.
  • Documentation comments have been added / updated.
  • Code has been formatted via zkstack dev fmt and zkstack dev lint.

}

/// Returns the new root hash of the tree on success.
pub fn verify(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAIU, the verification procedure implemented in the ZK OS repo uses separate Merkle paths for each of sorted_leaves, so the proof there is longer, but IIUC, the amount of hashing is the same (e.g., Merkle paths are not folded separately for each leaf; they are used almost in the same way as hashes here).

2025-02-19T11:07:06.144174Z INFO loadtest: Verified tree consistency in 41.126574667s
```

I.e., latency is dominated by I/O (~30% for key–index lookup, ~30% for loading tree nodes, and ~20% for tree
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Intuitively, there should be a way to optimize key–index lookup, but I haven't come up with anything functional yet. Stuff like reusing RocksDB iterators doesn't seem to provide efficiency boost.

@slowli slowli marked this pull request as ready for review February 19, 2025 14:55
@slowli slowli requested a review from popzxc February 19, 2025 14:56
Comment on lines +125 to +126
pub(crate) fn get(&self, depth_in_node: u8, index_on_level: u64) -> H256 {
let bit_shift = self.internal_node_depth - depth_in_node;
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it make sense to validate depth_in_node and index_on_level? i.e add asserts
assert(depth_in_node < self.internal_node_depth)
assert(index_on_level < self.nodes.len() * (1 << bit_shift))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's possible, but I'm reasonably sure that both assertions hold by construction due to how get() is used in collect_hashes(). E.g., depth_in_node is defined as depth % P::INTERNAL_NODE_DEPTH, i.e., it's always valid.

Copy link
Contributor

@perekopskiy perekopskiy left a comment

Choose a reason for hiding this comment

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

I would find some diagrams explaining terms and types used very helpful for reviewing and understanding. Can be done out of the scope for this PR of course

@slowli slowli requested a review from perekopskiy February 24, 2025 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants