マークル ツリーの実装は多数あります。ここでは、純粋なメモリの実装についてのリファレンスを示します。これは理解に役立ちます。
プロジェクトアドレス https://github.com/cbergoon/merkletree
コア分析
1. 構造
type Content interface {
CalculateHash() ([]byte, error)
Equals(other Content) (bool, error)
}
//MerkleTree is the container for the tree. It holds a pointer to the root of the tree,
//a list of pointers to the leaf nodes, and the merkle root.
type MerkleTree struct {
Root *Node
merkleRoot []byte
Leafs []*Node
hashStrategy func() hash.Hash
}
//Node represents a node, root, or leaf in the tree. It stores pointers to its immediate
//relationships, a hash, the content stored if it is【 a leaf, and other metadata.
type Node struct {
Tree *MerkleTree
Parent *Node
Left *Node
Right *Node
leaf bool
dup bool
Hash []byte
C Content
}
2. コアメソッド
//buildWithContent is a helper function that for a given set of Contents, generates a
//corresponding tree and returns the root node, a list of leaf nodes, and a possible error.
//Returns an error if cs contains no Contents.
// 这里先计算了所有的叶子节点的hash,然后在递归调用 buildIntermediate 来构建整个树
func buildWithContent(cs []Content, t *MerkleTree) (*Node, []*Node, error) {
if len(cs) == 0 {
return nil, nil, errors.New("error: cannot construct tree with no content")
}
var leafs []*Node
for _, c := range cs {
hash, err := c.CalculateHash()
if err != nil {
return nil, nil, err
}
leafs = append(leafs, &Node{
Hash: hash,
C: c,
leaf: true,
Tree: t,
})
}
if len(leafs)%2 == 1 {
duplicate := &Node{
Hash: leafs[len(leafs)-1].Hash,
C: leafs[len(leafs)-1].C,
leaf: true,
dup: true,
Tree: t,
}
leafs = append(leafs, duplicate)
}
root, err := buildIntermediate(leafs, t)
if err != nil {
return nil, nil, err
}
return root, leafs, nil
}
//buildIntermediate is a helper function that for a given list of leaf nodes, constructs
//the intermediate and root levels of the tree. Returns the resulting root node of the tree.
func buildIntermediate(nl []*Node, t *MerkleTree) (*Node, error) {
var nodes []*Node
for i := 0; i < len(nl); i += 2 {
h := t.hashStrategy()
var left, right int = i, i + 1
if i+1 == len(nl) {
right = i
}
chash := append(nl[left].Hash, nl[right].Hash...)
if _, err := h.Write(chash); err != nil {
return nil, err
}
n := &Node{
Left: nl[left],
Right: nl[right],
Hash: h.Sum(nil),
Tree: t,
}
nodes = append(nodes, n)
nl[left].Parent = n
nl[right].Parent = n
if len(nl) == 2 {
return n, nil
}
}
return buildIntermediate(nodes, t)
}
他のメソッドについては、ソース コードの実装を参照してください。組織的に考えると比較的わかりやすいです。