Golang Merkle tree
个人博客:https://www.huixinyixiao.xn–6qq986b3xl/
Golang 实现Merkle 树
实现Merkle树,需要使用:
"github.com/cbergoon/merkletree"
这个package中含有构造函数,以及接口函数,所有,通过这个包实现Merkle树的相关操作,是很好的。
官方实例代码
// 在这里编写代码
package main
import (
"crypto/sha256"
"github.com/cbergoon/merkletree"
"log"
)
//TestContent implements the Content interface provided by merkletree and represents the content stored in the tree.
type TestContent struct {
x string
}
//CalculateHash hashes the values of a TestContent
func (t TestContent) CalculateHash() ([]byte, error) {
h := sha256.New()
if _, err := h.Write([]byte(t.x)); err != nil {
return nil, err
}
return h.Sum(nil), nil
}
//Equals tests for equality of two Contents
func (t TestContent) Equals(other merkletree.Content) (bool, error) {
return t.x == other.(TestContent).x, nil
}
func main() {
//Build list of Content to build tree
var list []merkletree.Content
/*测试文件*/
var list02 []merkletree.Content
list02 = append(list02, TestContent{
"shan"})
list = append(list, TestContent{
x: "Hello"})
list = append(list, TestContent{
x: "Hi"})
list = append(list, TestContent{
x: "Hey"})
list = append(list, TestContent{
x: "Hola"})
//Create a new Merkle Tree from the list of Content
t, err := merkletree.NewTree(list)
if err != nil {
log.Fatal(err)
}
//Get the Merkle Root of the tree
mr := t.MerkleRoot()
log.Println("Merkle Root:", mr)
//Verify the entire tree (hashes for each node) is valid
vt, err := t.VerifyTree()
if err != nil {
log.Fatal(err)
}
log.Println("Verify Tree: ", vt)
//Verify a specific content in in the tree
vc, err := t.VerifyContent(list02[0])
if err != nil {
log.Fatal(err)
}
log.Println("Verify Content: ", vc)
//String representation
log.Println(t)
}
Note:我改变了验证的信息内容(list02),为了验证这个package 可用性。
1. 源package 解读
在package 中的interface,需要实现两个函数
//Content represents the data that is stored and verified by the tree. A type that
//implements this interface can be used as an item in the tree.
type Content interface {
CalculateHash() ([]byte, error)
Equals(other Content) (bool, error)
}
只是代码实现中需要注意的,可以添加自己实现的算法,比如更改sha256等。
其他函数的调用,不需要做任何改变,直接调用就好。
从上图中可以看出对于所有的交易数据,都是叶子,并且,如果添加的交易数是奇数,也就是黄色区域表示的那样,那么,就会复制最后一个交易,形成偶数个交易数,也就是最后的两个交易其实是一样的。
2. 查询数据路径,重新构造Merkle tree ,看看和我们想的是否一样。
通过插入四个数据:
func appendListData(number int) {
// 随机产生数据
for i := 0; i < number; i++ {
nodeId := "hello" + strconv.Itoa(i)
list = append(list, TestContent{
nodeId})
}
}
上述代码,实现插入数据的功能。
主函数里面直接调用。另外需要将list全局声明。我们查询两个数据hello0和hello1的路径,此时,设置number为4:
从红色区域可以知道,两个叶子节点的父节点是一样的,也就是hello0和hello1叶子共同hash得到。
我们再次查询两个数据hello2和hello3的路径,此时,同样设置number为4:
看,结果如我们所说的那样。
如果我们将上面的两个图中的红色的数据进行hash,一定是root hash。