一文了解Merkle Patricia Trie这种数据结构

基础概念

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 结构

  1. 插入 ("dog", 10)

    rust 复制代码
    root -> d -> o -> g (value=10)
  2. 插入 ("doge", 20)

    ini 复制代码
    root -> d -> o -> g (value=10)
                       -> e (value=20)
  3. 插入 ("cat", 30)

    rust 复制代码
    root -> 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 的实现会更复杂,涉及更多的优化和细节处理。
相关推荐
计算机小白一个4 分钟前
蓝桥杯 Java B 组之岛屿数量、二叉树路径和(区分DFS与回溯)
java·数据结构·算法·蓝桥杯
孤雪心殇5 分钟前
简单易懂,解析Go语言中的Map
开发语言·数据结构·后端·golang·go
柃歌1 小时前
【UCB CS 61B SP24】Lecture 7 - Lists 4: Arrays and Lists学习笔记
java·数据结构·笔记·学习·算法
柃歌1 小时前
【UCB CS 61B SP24】Lecture 4 - Lists 2: SLLists学习笔记
java·数据结构·笔记·学习·算法
干炒 牛河1 小时前
数据结构:双链表list
数据结构·list
醉城夜风~3 小时前
[数据结构]顺序表详解
数据结构
Vacant Seat4 小时前
贪心算法-买卖股票的最佳时机
java·数据结构·算法·贪心算法
郑州吴彦祖7724 小时前
数据结构——二叉树经典习题讲解
java·数据结构·算法·leetcode
和光同尘@5 小时前
74. 搜索二维矩阵(LeetCode 热题 100)
数据结构·c++·线性代数·算法·leetcode·职场和发展·矩阵
zl_dfq5 小时前
数据结构之【顺序表简介】
数据结构·顺序表