1 个不稳定版本
0.1.0 | 2022年11月17日 |
---|
#13 在 #merkle-root
40KB
809 行
merkle-tree-rs
一个用于生成梅克尔树和梅克尔证明的 Rust 库。
非常适合与 OpenZeppelin 合约 MerkleProof
工具结合使用的空投和类似机制。
快速入门
将 merkle-tree-rs 添加到您的仓库中,还需要 serde 和 serde_json 以支持 json。
[dependencies]
merkle-tree-rs = "0.1.0"
serde = "1.0.147"
serde_json = "1.0"
构建梅克尔树
use merkle_tree_rs::standard::StandardMerkleTree;
use std::fs;
let values = vec![
vec![
"0x1111111111111111111111111111111111111111".to_string(),
"5000000000000000000".to_string(),
],
vec![
"0x2222222222222222222222222222222222222222".to_string(),
"2500000000000000000".to_string(),
],
];
let tree = StandardMerkleTree::of(values, &["address".to_string(), "uint256".to_string()]);
let root = tree.root();
println!("Merkle root: {}", root);
let tree_json = serde_json::to_string(&tree.dump()).unwrap();
fs::write("tree.json", tree_json).unwrap();
- 获取要包含在树中的值。(注意:考虑从文件中读取它们。)
- 构建梅克尔树。设置编码以匹配值。
- 打印梅克尔根。您可能需要在智能合约中发布此值。
- 编写一个描述树的文件。您将向用户分发此文件,以便他们可以为树中的值生成证明。
获取证明
假设我们正在寻找与地址 0x11...11
对应的条目的证明。
use merkle_tree_rs::standard::StandardMerkleTree;
use std::fs;
let tree_json = fs::read_to_string("tree.json").unwrap();
let tree_data: StandardMerkleTreeData = serde_json::from_str(&tree_json).unwrap();
let tree = StandardMerkleTree::load(tree_data);
for (i, v) in tree.clone().enumerate() {
if v[0] == "0x1111111111111111111111111111111111111111" {
let proof = tree.get_proof(LeafType::Number(i));
println!("Value : {:?}", v);
println!("Proof : {:?}", proof);
}
}
- 从之前生成的描述中加载树。
- 遍历条目以找到您感兴趣的条目。
- 使用条目的索引生成证明。
在实际操作中,这可能在提交证明到链之前在客户端应用程序中完成,查找的地址是连接的钱包地址。
请参阅 MerkleProof
了解如何在 Solidity 中验证证明的文档。
标准梅克尔树
此库适用于为以太坊智能合约设计的“标准”梅克尔树。我们根据使其安全且适用于链上验证的一些特性对其进行了定义。
从最后三点我们可以得到,树中具有值 [addr, amount]
的叶子的哈希可以通过以下方式在 Solidity 中计算
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(addr, amount))));
这是一个具有偏见的设 计,我们相信它将为大多数用户提供最佳的开箱即用体验。根据用户请求,我们可能会在未来引入自定义选项。
API & 示例
StandardMerkleTree
use merkle_tree_rs::standard::StandardMerkleTree,
StandardMerkleTree.的
目前支持编码的类型包括地址、uint、uint256和字符串。
let values = vec![
vec![
"0x1111111111111111111111111111111111111111".to_string(),
"5000000000000000000".to_string(),
],
vec![
"0x2222222222222222222222222222222222222222".to_string(),
"2500000000000000000".to_string(),
],
];
let encoding = ["address".to_string(), "uint256".to_string()];
let tree = StandardMerkleTree::of(values, &encoding);
从树中元素的数组创建一个标准默克尔树,包括它们的类型用于ABI编码。
注意 考虑从CSV文件读取元素数组,以便与电子表格或其他数据处理管道轻松互操作。
树.根
println!("{}", tree.root());
树的根是对树中值的承诺。它可以被发布(例如,在智能合约中)以证明其值是树的组成部分。
树.转储
let tree_json = serde_json::to_string(&tree.dump()).unwrap();
fs::write("tree.json", tree_json).unwrap();
返回默克尔树的描述,以便分发。它包含所有必要的信 息来重建树、找到相关的叶子节点并生成证明。您应该在Web应用程序或命令行界面中将此信息分发给用户,以便他们可以为他们的兴趣叶子节点生成证明。
StandardMerkleTree.加载
let tree_json = fs::read_to_string("tree.json").unwrap();
let tree_data: StandardMerkleTreeData = serde_json::from_str(&tree_json).unwrap();
let tree = StandardMerkleTree::load(tree_data);
从先前由 dump
返回的描述中加载树。
树.getProof
let proof = tree.get_proof(LeafType::Number(i));
返回树的第 i
个值的证明。索引指的是构建树时数组中值的位 置。
它被包装在 LeafType
枚举中,其中 Number 表示索引(usize),
LeafBytes 表示值(Vec<string>)。使用值效率较低,因为如果值不在树中,它将失败。
let proof = tree.getProof(LeafType::LeafBytes([alice, "100"]));
树.getMultiProof
let multi_proof = tree.getMultiProof([LeafType::Number(i0), LeafType::Number(i1), ...]);
返回一个多证明结构,包含 i0,i1,...
索引处的值的证明、prooflags和leaves。索引指的是构建树时数组中值的位 置。
返回的多证明包含一个包含正在证明的叶子的数组。这个数组可能不同于 i0,i1,...
给出的顺序!返回的顺序很重要,因为叶子必须按此顺序提交进行验证(例如,在智能合约中)。
也接受值而不是索引,但这将效率较低。如果任何值不在树中,它将失败。
遍历树
for (i, v) in tree.clone().enumerate {
console.log("value: {:?}", v);
console.log("proof: {:?}", tree.getProof(LeafType::Number(i)));
}
列出树中的值及其索引,可用于获取证明。
树.render
println!("{:?}", tree.render());
返回一个可视化的树表示,可用于调试。
树.leafHash
let leaf = tree.leafHash(["alice".to_string(), "100".to_string()]);
返回值的叶子哈希,如标准默克尔树中定义。
对应于Solidity中的以下表达式
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(alice, 100))));
归属
依赖关系
~19–37MB
~558K SLoC