基础概念
1. Trie(字典树)
Trie 是一种树形数据结构,用于存储键值对。键通常是字符串,树的每一层代表键的一个字符。例如:
- 插入键值对
("apple", 10)
,路径是a -> p -> p -> l -> e
。 - 插入键值对
("app", 20)
,路径是a -> p -> p
。
2. Patricia Trie(压缩前缀树)
Patricia Trie 是对 Trie 的优化,通过合并只有一个子节点的路径来压缩树。例如:
- 如果路径
a -> p -> p
只有一个子节点,可以压缩为一个节点app
。
3. Merkle Tree
Merkle Tree 是一种树结构,每个节点存储其子节点的哈希值。根节点的哈希值可以用于验证整个树的数据完整性。
4. Merkle Patricia Trie
Merkle Patricia Trie 结合了 Patricia Trie 和 Merkle Tree:
- 使用 Patricia Trie 存储键值对。
- 每个节点存储其内容的哈希值,形成 Merkle Tree。
示例
假设我们有以下键值对:
("dog", 10)
("doge", 20)
("cat", 30)
Trie 结构
-
插入
("dog", 10)
:rustroot -> d -> o -> g (value=10)
-
插入
("doge", 20)
:iniroot -> d -> o -> g (value=10) -> e (value=20)
-
插入
("cat", 30)
:rustroot -> c -> a -> t (value=30) -> d -> o -> g (value=10) -> e (value=20)
Patricia Trie 结构
压缩路径:
ini
root -> c -> at (value=30)
-> d -> og (value=10)
-> e (value=20)
Merkle Patricia Trie
为每个节点计算哈希值,形成 Merkle Tree。
Go 实现
以下是一个简化版的 MPT 实现:
go
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
)
type Node struct {
Value int
Children map[byte]*Node
}
type MerklePatriciaTrie struct {
Root *Node
}
func NewMerklePatriciaTrie() *MerklePatriciaTrie {
return &MerklePatriciaTrie{Root: &Node{Children: make(map[byte]*Node)}}
}
func (mpt *MerklePatriciaTrie) Insert(key string, value int) {
current := mpt.Root
for i := 0; i < len(key); i++ {
char := key[i]
if current.Children[char] == nil {
current.Children[char] = &Node{Children: make(map[byte]*Node)}
}
current = current.Children[char]
}
current.Value = value
}
func (mpt *MerklePatriciaTrie) Get(key string) (int, bool) {
current := mpt.Root
for i := 0; i < len(key); i++ {
char := key[i]
if current.Children[char] == nil {
return 0, false
}
current = current.Children[char]
}
return current.Value, true
}
func (mpt *MerklePatriciaTrie) Hash() string {
return calculateHash(mpt.Root)
}
func calculateHash(node *Node) string {
if node == nil {
return ""
}
hash := sha256.New()
for char, child := range node.Children {
hash.Write([]byte{char})
hash.Write([]byte(calculateHash(child)))
}
hash.Write([]byte(fmt.Sprintf("%d", node.Value)))
return hex.EncodeToString(hash.Sum(nil))
}
func main() {
mpt := NewMerklePatriciaTrie()
mpt.Insert("dog", 10)
mpt.Insert("doge", 20)
mpt.Insert("cat", 30)
value, exists := mpt.Get("dog")
fmt.Println("Get dog:", value, exists) // Output: 10 true
fmt.Println("Root Hash:", mpt.Hash())
}
Node.js 实现
以下是一个简化版的 MPT 实现:
javascript
const crypto = require('crypto');
class Node {
constructor() {
this.value = null;
this.children = new Map();
}
}
class MerklePatriciaTrie {
constructor() {
this.root = new Node();
}
insert(key, value) {
let current = this.root;
for (let char of key) {
if (!current.children.has(char)) {
current.children.set(char, new Node());
}
current = current.children.get(char);
}
current.value = value;
}
get(key) {
let current = this.root;
for (let char of key) {
if (!current.children.has(char)) {
return null;
}
current = current.children.get(char);
}
return current.value;
}
hash() {
return this.calculateHash(this.root);
}
calculateHash(node) {
const hash = crypto.createHash('sha256');
if (node) {
for (let [char, child] of node.children) {
hash.update(char);
hash.update(this.calculateHash(child));
}
hash.update(node.value !== null ? node.value.toString() : '');
}
return hash.digest('hex');
}
}
const mpt = new MerklePatriciaTrie();
mpt.insert("dog", 10);
mpt.insert("doge", 20);
mpt.insert("cat", 30);
console.log("Get dog:", mpt.get("dog")); // Output: 10
console.log("Root Hash:", mpt.hash());
总结
- Merkle Patricia Trie 是一种高效的数据结构,结合了 Patricia Trie 的压缩特性和 Merkle Tree 的哈希验证特性。
- 通过 Go 和 Node.js 的示例,你可以看到如何实现一个简化版的 MPT。
- 实际应用中(如以太坊),MPT 的实现会更复杂,涉及更多的优化和细节处理。