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

refactor: SMT path iter uses leaf key #482

Merged
merged 12 commits into from
Jun 9, 2023

Conversation

bvrooman
Copy link
Contributor

@bvrooman bvrooman commented Jun 9, 2023

Related issues:

This PR removes the dependency on storage lookups for the leaf key during deletion. During deletion, we no longer need to look up leafs by leaf keys in storage because we can perform path iteration without the whole leaf: the leaf key is sufficient. This PR refactors the iterator to use a leaf key rather than the entire leaf.

@bvrooman bvrooman self-assigned this Jun 9, 2023
@bvrooman bvrooman requested a review from a team June 9, 2023 17:00
@bvrooman bvrooman marked this pull request as ready for review June 9, 2023 17:00
@bvrooman bvrooman marked this pull request as draft June 9, 2023 17:05
@bvrooman
Copy link
Contributor Author

bvrooman commented Jun 9, 2023

Converted back to draft, since I forgot to update the CHANGELOG. Will do that now!

return Ok(());
}

let leaf_node = Node::create_leaf(key, data);
self.storage.insert(&leaf_node.hash(), &leaf_node.as_ref().into())?;
self.storage.insert(leaf_node.leaf_key(), &leaf_node.as_ref().into())?;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was the line that introduced the potential for malicious collision

@bvrooman bvrooman marked this pull request as ready for review June 9, 2023 17:21
if self.root() == *Self::empty_root() {
// The zero root signifies that all leaves are empty, including the
// given key.
return Ok(());
}

if let Some(primitive) = self.storage.get(key)? {
let leaf_node = Node::create_leaf(key, data);
if let Some(primitive) = self.storage.get(&leaf_node.hash())? {
Copy link
Collaborator

@xgreenx xgreenx Jun 9, 2023

Choose a reason for hiding this comment

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

Actually, I checked the code, and it seems you don't even need a value. Because self.path_set and self.delete_with_path_set use only leaf_key inside the logic.

Copy link
Member

Choose a reason for hiding this comment

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

Does this mean we wouldn't need to pass the data here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeap

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting, I can explore that further

Copy link
Contributor Author

@bvrooman bvrooman Jun 9, 2023

Choose a reason for hiding this comment

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

Unfortunately, this doesn't work: We can't avoid the storage lookup here because we need to know if the deleted item is in the set of leaves or not. Whenever we call delete, we will modify all items along the leaf path. If we never added the item, we end up "reverting" a leaf path that was never actually changed, thus creating a false root. I got far enough into the changes in a PR here #483, but the tests with delete are failing for this reason.

Specifically:

failures:

---- sparse::merkle_tree::test::test_delete_non_existent_key stdout ----
thread 'sparse::merkle_tree::test::test_delete_non_existent_key' panicked at 'assertion failed: `(left == right)`
  left: `"8e87e7b530e86dda2bd6705754af66f4320105e20b5fc8c5a5347064d7cc5bf2"`,
 right: `"108f731f2414e33ae57e584dc26bd276db07874436b2264ca6e520c658185c6b"`', fuel-merkle/src/sparse/merkle_tree.rs:552:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- sparse::merkle_tree::test::test_interleaved_update_delete stdout ----
thread 'sparse::merkle_tree::test::test_interleaved_update_delete' panicked at 'assertion failed: `(left == right)`
  left: `"c37ab7fc94e589545364e797b952a2eadbbbdcf182fe770fc2253fa2d2d36f5d"`,
 right: `"7e6643325042cfe0fc76626c043b97062af51c7e9fc56665f12b479034bce326"`', fuel-merkle/src/sparse/merkle_tree.rs:592:9


failures:
    sparse::merkle_tree::test::test_delete_non_existent_key
    sparse::merkle_tree::test::test_interleaved_update_delete

We need to be able to short-circuit the delete call before modifying the nodes along the leaf path. As far as I am aware, the only way to do this is by checking the storage. In order to check the storage, we need to know the leaf data.

If there is another way we can determine whether or not a leaf is in the set, we can do that.

Maybe we can try:

  • Storing the list of leaves
  • Bloom filter (won't be reliable though)
  • ???

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@xgreenx observed that we can check for the leaf by querying the path set, allowing us to properly check the delete 👍

@bvrooman bvrooman requested review from xgreenx and a team June 9, 2023 19:46
* Refactor path iter to use leaf key

* compile/clippy

* Fix

* Improve

---------

Co-authored-by: green <xgreenx9999@gmail.com>
@bvrooman bvrooman marked this pull request as draft June 9, 2023 21:08
@bvrooman bvrooman changed the title refactor: SMT delete takes leaf data refactor: SMT path iter uses leaf key Jun 9, 2023
xgreenx
xgreenx previously approved these changes Jun 9, 2023
@bvrooman
Copy link
Contributor Author

bvrooman commented Jun 9, 2023

Hmmm, for whatever reason, test_update_with_empty_data_performs_delete still fails. I'm looking into it now. Still, we may not need this behaviour anyway, and we can likely stop supporting it.
Edit: All good now!

@bvrooman bvrooman marked this pull request as ready for review June 9, 2023 22:06
@bvrooman bvrooman enabled auto-merge June 9, 2023 22:06
@bvrooman bvrooman added this pull request to the merge queue Jun 9, 2023
Merged via the queue into master with commit dc28f34 Jun 9, 2023
@bvrooman bvrooman deleted the bvrooman/refactor/smt-delete-api branch June 9, 2023 22:14
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.

Sparse Merkel tree leafs/nodes may override other leafs/nodes
3 participants