Skip to content

Commit

Permalink
Feat: Infallible in-memory SMT (#100)
Browse files Browse the repository at this point in the history
* In memory SMT

* Format

* In memory SMT tests

* Tree ptr

* Use Option for delayed SMT initialization

* Use alloc box

* Strongly typed self as Pin in interface

* Use core phantompinned

* Format

* Use in-memory Merkle tree for data driven tests

* Remove block

* Relax constraint on Storage (#101)

* Relax constraint on Storage

* sum tree, and cleanup

* relax storage for binary

Co-authored-by: rakita <[email protected]>
  • Loading branch information
bvrooman and rakita authored Jun 20, 2022
1 parent 900b1b2 commit e078b41
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 45 deletions.
15 changes: 8 additions & 7 deletions fuel-merkle/src/binary/merkle_tree.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::fmt;

use crate::binary::{self, Node};
use crate::common::{Bytes32, Position, Subtree};

use fuel_storage::Storage;

use alloc::boxed::Box;
Expand Down Expand Up @@ -30,18 +31,18 @@ impl<StorageError> From<StorageError> for MerkleTreeError<StorageError> {

type ProofSet = Vec<Bytes32>;

pub struct MerkleTree<'storage, StorageType> {
storage: &'storage mut StorageType,
pub struct MerkleTree<StorageType> {
storage: StorageType,
head: Option<Box<Subtree<Node>>>,
leaves_count: u64,
}

impl<'storage, StorageType, StorageError> MerkleTree<'storage, StorageType>
impl<StorageType, StorageError> MerkleTree<StorageType>
where
StorageType: Storage<u64, Node, Error = StorageError>,
StorageError: 'static,
StorageError: fmt::Debug + Clone + 'static,
{
pub fn new(storage: &'storage mut StorageType) -> Self {
pub fn new(storage: StorageType) -> Self {
Self {
storage,
head: None,
Expand All @@ -50,7 +51,7 @@ where
}

pub fn load(
storage: &'storage mut StorageType,
storage: StorageType,
leaves_count: u64,
) -> Result<Self, MerkleTreeError<StorageError>> {
let mut tree = Self {
Expand Down
1 change: 1 addition & 0 deletions fuel-merkle/src/sparse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod merkle_tree;
mod node;

pub use merkle_tree::{MerkleTree, MerkleTreeError};
pub mod in_memory;

pub(crate) use hash::zero_sum;
pub(crate) use node::{Buffer, Node, StorageNode};
105 changes: 105 additions & 0 deletions fuel-merkle/src/sparse/in_memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::common::Bytes32;
use crate::sparse::Buffer;
use crate::{common, sparse};

type StorageMap = common::StorageMap<Bytes32, Buffer>;
type SparseMerkleTree = sparse::MerkleTree<StorageMap>;

pub struct MerkleTree {
tree: SparseMerkleTree,
}

impl MerkleTree {
pub fn new() -> Self {
Self {
tree: SparseMerkleTree::new(StorageMap::new()),
}
}

pub fn update(&mut self, key: &Bytes32, data: &[u8]) {
let _ = self.tree.update(key, data);
}

pub fn delete(&mut self, key: &Bytes32) {
let _ = self.tree.delete(key);
}

pub fn root(&self) -> Bytes32 {
self.tree.root()
}
}

#[cfg(test)]
mod test {
use super::*;
use sparse::hash::sum;

#[test]
fn test_empty_root() {
let tree = MerkleTree::new();
let root = tree.root();
let expected_root = "0000000000000000000000000000000000000000000000000000000000000000";
assert_eq!(hex::encode(root), expected_root);
}

#[test]
fn test_update_1() {
let mut tree = MerkleTree::new();

tree.update(&sum(b"\x00\x00\x00\x00"), b"DATA");

let root = tree.root();
let expected_root = "39f36a7cb4dfb1b46f03d044265df6a491dffc1034121bc1071a34ddce9bb14b";
assert_eq!(hex::encode(root), expected_root);
}

#[test]
fn test_update_2() {
let mut tree = MerkleTree::new();

tree.update(&sum(b"\x00\x00\x00\x00"), b"DATA");
tree.update(&sum(b"\x00\x00\x00\x01"), b"DATA");

let root = tree.root();
let expected_root = "8d0ae412ca9ca0afcb3217af8bcd5a673e798bd6fd1dfacad17711e883f494cb";
assert_eq!(hex::encode(root), expected_root);
}

#[test]
fn test_update_3() {
let mut tree = MerkleTree::new();

tree.update(&sum(b"\x00\x00\x00\x00"), b"DATA");
tree.update(&sum(b"\x00\x00\x00\x01"), b"DATA");
tree.update(&sum(b"\x00\x00\x00\x02"), b"DATA");

let root = tree.root();
let expected_root = "52295e42d8de2505fdc0cc825ff9fead419cbcf540d8b30c7c4b9c9b94c268b7";
assert_eq!(hex::encode(root), expected_root);
}

#[test]
fn test_update_1_delete_1() {
let mut tree = MerkleTree::new();

tree.update(&sum(b"\x00\x00\x00\x00"), b"DATA");
tree.delete(&sum(b"\x00\x00\x00\x00"));

let root = tree.root();
let expected_root = "0000000000000000000000000000000000000000000000000000000000000000";
assert_eq!(hex::encode(root), expected_root);
}

#[test]
fn test_update_2_delete_1() {
let mut tree = MerkleTree::new();

tree.update(&sum(b"\x00\x00\x00\x00"), b"DATA");
tree.update(&sum(b"\x00\x00\x00\x01"), b"DATA");
tree.delete(&sum(b"\x00\x00\x00\x01"));

let root = tree.root();
let expected_root = "39f36a7cb4dfb1b46f03d044265df6a491dffc1034121bc1071a34ddce9bb14b";
assert_eq!(hex::encode(root), expected_root);
}
}
31 changes: 15 additions & 16 deletions fuel-merkle/src/sparse/merkle_tree.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::common::{AsPathIterator, Bytes32};
use crate::sparse::{zero_sum, Buffer, Node, StorageNode};

use fuel_storage::Storage;

use alloc::string::String;
Expand All @@ -26,25 +25,25 @@ impl<StorageError> From<StorageError> for MerkleTreeError<StorageError> {
}
}

pub struct MerkleTree<'storage, StorageType> {
pub struct MerkleTree<StorageType> {
root_node: Node,
storage: &'storage mut StorageType,
storage: StorageType,
}

impl<'a, 'storage, StorageType, StorageError> MerkleTree<'storage, StorageType>
impl<StorageType, StorageError> MerkleTree<StorageType>
where
StorageType: Storage<Bytes32, Buffer, Error = StorageError>,
StorageError: fmt::Debug + Clone + 'static,
{
pub fn new(storage: &'storage mut StorageType) -> Self {
pub fn new(storage: StorageType) -> Self {
Self {
root_node: Node::create_placeholder(),
storage,
}
}

pub fn load(
storage: &'storage mut StorageType,
storage: StorageType,
root: &Bytes32,
) -> Result<Self, MerkleTreeError<StorageError>> {
let buffer = storage
Expand All @@ -59,7 +58,7 @@ where
}

pub fn update(
&'a mut self,
&mut self,
key: &Bytes32,
data: &[u8],
) -> Result<(), MerkleTreeError<StorageError>> {
Expand All @@ -86,7 +85,7 @@ where
Ok(())
}

pub fn delete(&'a mut self, key: &Bytes32) -> Result<(), MerkleTreeError<StorageError>> {
pub fn delete(&mut self, key: &Bytes32) -> Result<(), MerkleTreeError<StorageError>> {
if self.root() == *zero_sum() {
// The zero root signifies that all leaves are empty, including the
// given key.
Expand All @@ -102,25 +101,25 @@ where
Ok(())
}

pub fn root(&'a self) -> Bytes32 {
pub fn root(&self) -> Bytes32 {
self.root_node().hash()
}

// PRIVATE

fn root_node(&'a self) -> &Node {
fn root_node(&self) -> &Node {
&self.root_node
}

fn set_root_node(&'a mut self, node: Node) {
fn set_root_node(&mut self, node: Node) {
debug_assert!(node.is_leaf() || node.height() == Node::max_height() as u32);
self.root_node = node;
}

fn path_set(&'a self, leaf_node: Node) -> (Vec<Node>, Vec<Node>) {
fn path_set(&self, leaf_node: Node) -> (Vec<Node>, Vec<Node>) {
let root_node = self.root_node().clone();
let root_storage_node = StorageNode::new(self.storage, root_node);
let leaf_storage_node = StorageNode::new(self.storage, leaf_node);
let root_storage_node = StorageNode::new(&self.storage, root_node);
let leaf_storage_node = StorageNode::new(&self.storage, leaf_node);
let (mut path_nodes, mut side_nodes): (Vec<Node>, Vec<Node>) = root_storage_node
.as_path_iter(&leaf_storage_node)
.map(|(node, side_node)| (node.into_node(), side_node.into_node()))
Expand All @@ -133,7 +132,7 @@ where
}

fn update_with_path_set(
&'a mut self,
&mut self,
requested_leaf_node: &Node,
path_nodes: &[Node],
side_nodes: &[Node],
Expand Down Expand Up @@ -197,7 +196,7 @@ where
}

fn delete_with_path_set(
&'a mut self,
&mut self,
requested_leaf_node: &Node,
path_nodes: &[Node],
side_nodes: &[Node],
Expand Down
15 changes: 8 additions & 7 deletions fuel-merkle/src/sum/merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::sum::{empty_sum, Node};
use fuel_storage::Storage;

use alloc::boxed::Box;
use core::fmt;

#[derive(Debug, Clone)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
Expand All @@ -12,16 +13,17 @@ pub enum MerkleTreeError {
InvalidProofIndex(u64),
}

pub struct MerkleTree<'storage, StorageError> {
storage: &'storage mut dyn Storage<Bytes32, Node, Error = StorageError>,
pub struct MerkleTree<StorageType> {
storage: StorageType,
head: Option<Box<Subtree<Node>>>,
}

impl<'storage, StorageError> MerkleTree<'storage, StorageError>
impl<StorageType, StorageError> MerkleTree<StorageType>
where
StorageError: 'static + Clone,
StorageType: Storage<Bytes32, Node, Error = StorageError>,
StorageError: fmt::Debug + Clone + 'static,
{
pub fn new(storage: &'storage mut dyn Storage<Bytes32, Node, Error = StorageError>) -> Self {
pub fn new(storage: StorageType) -> Self {
Self {
storage,
head: None,
Expand Down Expand Up @@ -120,8 +122,7 @@ mod test {
use crate::common::{Bytes32, StorageMap};
use crate::sum::{empty_sum, leaf_sum, node_sum, MerkleTree, Node};

type StorageError = core::convert::Infallible;
type MT<'storage> = MerkleTree<'storage, StorageError>;
type MT<'storage> = MerkleTree<&'storage mut StorageMap<Bytes32, Node>>;
const FEE: u64 = 100;

#[test]
Expand Down
Loading

0 comments on commit e078b41

Please sign in to comment.