#merkle-tree #tree #merkle #crdt #hash #networking #anti-entropy

merkle-search-tree

一种用于高效基于状态 CRDT 复制和反熵的数据结构

11 个版本 (破坏性更新)

0.8.0 2024年8月21日
0.7.1 2023年10月18日
0.7.0 2023年9月19日
0.4.0 2023年7月26日

#170 in 密码学

Download history 2919/week @ 2024-05-01 2297/week @ 2024-05-08 2813/week @ 2024-05-15 1759/week @ 2024-05-22 2707/week @ 2024-05-29 1372/week @ 2024-06-05 1335/week @ 2024-06-12 706/week @ 2024-06-19 1122/week @ 2024-06-26 695/week @ 2024-07-03 1221/week @ 2024-07-10 880/week @ 2024-07-17 1186/week @ 2024-07-24 1332/week @ 2024-07-31 733/week @ 2024-08-07 936/week @ 2024-08-14

4,296 每月下载量

Apache-2.0

195KB
3.5K SLoC

crates.io docs.rs

默克尔搜索树

此软件包实现了默克尔搜索树,如2019年论文默克尔搜索树:开放网络中高效的基于状态 CRDT中所述,作者为Alex Auvolat & François Taïani。[^引用]

与基于 CRDT 的值类型结合使用时,默克尔搜索树可以作为高效的抗熵原语,允许独立副本并发地在树中修改数据,并在所有对等方之间确定性和最终收敛。

请参阅MerkleSearchTree文档。

使用方法

use merkle_search_tree::{MerkleSearchTree, diff::diff};

// Initialise a tree using the default configuration, appropriate for most uses.
let mut node_a = MerkleSearchTree::default();

// Upsert values into the tree.
//
// For the MST construct to be a CRDT itself, the values stored into the tree
// must also be CRDTs (or at least, have deterministic conflict resolution).
// Here the MST is used as an add-only set (a trivial CRDT) by using () as the
// key values.
node_a.upsert("bananas", &());
node_a.upsert("plátanos", &());

// Another node has differing keys.
let mut node_b = MerkleSearchTree::default();
node_b.upsert("donkey", &());

// The MST root hash can be used as an efficient consistency check (comparison
// is O(1) in space and time).
//
// In this case, both trees are inconsistent w.r.t each other, which is
// indicated by their differing root hashes.
assert_ne!(node_a.root_hash(), node_b.root_hash());

// Generate compact summaries of the MST content, suitable for transmission over
// the network, and use it to compute the diff between two trees.
let diff_range = diff(
    node_b.serialise_page_ranges().unwrap().into_iter(),
    node_a.serialise_page_ranges().unwrap().into_iter(),
);

// In this case, node B can obtain the missing/differing keys in node A by
// requesting keys within the computed diff range (inclusive):
assert_matches::assert_matches!(diff_range.as_slice(), [range] => {
    assert_eq!(range.start(), &"bananas");
    assert_eq!(range.end(), &"plátanos");
});

性能

对默克尔搜索树的操作非常 ,每秒可处理数百万/数十亿个键

键计数 插入所有键 生成根 序列化 差异(一致) 差异(不一致)
100 个键 6µs 3µs 98ns 130ns 261ns
1,000 个键 80µs 38µs 837ns 574ns 3µs
10,000 个键 1100us 388us 10µs 4µs 28µs
100,000 个键 12ms 3ms 112µs 36µs 225µs

以下测量值反映了在 M1 MacBook Pro 上对包含不同数量键的树进行操作的单线程性能。

  • 插入所有键:将行中列出的 N 个键插入空树
  • 生成根:重新生成修改后树的根哈希
  • 序列化:将树编码为网络通信的差分格式
  • 差异(一致):为相同的树生成差异(没有不同的范围)
  • 差异(不一致):为完全不一致的树生成差异

生成这些数字的基准测试包含在此存储库中(运行 cargo bench)。

测试

此软件包使用随机化模糊测试和属性测试进行广泛测试,以验证正确性,并确保发布版本中不会出现恐慌。

参考文献:Alex Auvolat, François Taïani. Merkle搜索树:开放网络中高效的状态CRDT。SRDS 2019 - 第38届IEEE可靠分布式系统国际研讨会,2019年10月,法国里昂。第1-10页,[10.1109/SRDS.2019.00032]。[hal-02303490]

依赖项

~200KB