实现代码:
import (
"encoding/hex"
"errors"
"generateAddress/utils"
"paper/common"
)
type MerkleNode struct {
Value string
Left *MerkleNode
Right *MerkleNode
}
//构建merkle root hash
func ConstructMerkleRoot(txids []string) (*MerkleNode, error) {
//参数校验
if len(txids) == 0 {
return nil,errors.New("txids is empth")
}
//开始构建
var leafNodes []MerkleNode
for _, txid := range txids {
var oneLeaf = MerkleNode{Value:txid, Left:nil, Right:nil}
leafNodes = append(leafNodes, oneLeaf)
}
return ConstructMerkleTreeNodes(leafNodes)
}
func ConstructMerkleTreeNodes(nodes []MerkleNode) (*MerkleNode, error) {
//参数校验
if len(nodes) == 0 {
return nil,errors.New("number of nodes is 0")
}
if len(nodes) == 1 {
return &nodes[0],nil
}
if len(nodes) == 2 {
var root = MerkleNode{}
var err error
if root,err = Merge(&nodes[0], &nodes[1]); err != nil {
return nil, err
}
return &root,nil
}
var (
err error
nodeAmount = len(nodes)
parentNodes []MerkleNode
left *MerkleNode
right *MerkleNode
)
//处理三个及三个以上的节点
for i:=0; i< nodeAmount; i += 2 {
var parentNode = MerkleNode{}
left = &nodes[i]
if i == nodeAmount-1 {//最后一个单独的节点
right = &nodes[i]
} else {
right = &nodes[i+1]
}
if parentNode,err = Merge(left, right); err != nil {
return nil, err
}
parentNodes = append(parentNodes,parentNode)
}
return ConstructMerkleTreeNodes(parentNodes)
}
func Merge(left *MerkleNode, right *MerkleNode) (MerkleNode, error) {
var (
parentNode = MerkleNode{Value:"", Left:left, Right:right}
data []byte
err error
leftBytes []byte
rightBytes []byte
)
//计算的时候txid从BigEdian转变成LittleEdian
if leftBytes,err = utils.ReverseBigEdianString(left.Value); err != nil {
return MerkleNode{},err
}
if rightBytes,err = utils.ReverseBigEdianString(right.Value); err != nil {
return MerkleNode{},err
}
data = append(leftBytes, rightBytes...)
var parentHash = common.Sha256AfterSha256(data)
//用字符串显示时保存为小端
data = utils.ReverseBytes(parentHash[:])
parentNode.Value = hex.EncodeToString(data)
return parentNode,nil
}
测试代码:
func TestConstructMerkleRoot(t *testing.T) {
var testcases = []struct {
txids []string
merkleRoot string
} {
{
[]string {
"b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082",
"f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
},
"7dac2c5666815c17a3b36427de37bb9d2e2c5ccec3f8633eb91a4205cb4c10ff",
},
{
[]string {
"8347cee4a1cb5ad1bb0d92e86e6612dbf6cfc7649c9964f210d4069b426e720a",
"a16f3ce4dd5deb92d98ef5cf8afeaf0775ebca408f708b2146c4fb42b41e14be",
},
"ed92b1db0b3e998c0a4351ee3f825fd5ac6571ce50c050b4b45df015092a6c36",
},
{
[]string {
"09e5c4a5a089928bbe368cd0f2b09abafb3ebf328cd0d262d06ec35bdda1077f",
"591e91f809d716912ca1d4a9295e70c3e78bab077683f79350f101da64588073",
},
"2f0f017f1991a1393798ff851bfc02ce7ba3f5e066815ed3104afb4bd3a0c230",
},
{
[]string{
"8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87",
"fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4",
"6359f0868171b1d194cbee1af2f16ea598ae8fad666d9b012c8ed2b79a236ec4",
"e9a66845e05d5abc0ad04ec80f774a7e585c6e8db975962d069a522137b80c1d",
},
"f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766",
},
{
[]string {
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
},
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
},
{
[]string {
"ef1d870d24c85b89d92ad50f4631026f585d6a34e972eaf427475e5d60acf3a3",
"f9fc751cb7dc372406a9f8d738d5e6f8f63bab71986a39cf36ee70ee17036d07",
"db60fb93d736894ed0b86cb92548920a3fe8310dd19b0da7ad97e48725e1e12e",
"220ebc64e21abece964927322cba69180ed853bb187fbc6923bac7d010b9d87a",
"71b3dbaca67e9f9189dad3617138c19725ab541ef0b49c05a94913e9f28e3f4e",
"fe305e1ed08212d76161d853222048eea1f34af42ea0e197896a269fbf8dc2e0",
"21d2eb195736af2a40d42107e6abd59c97eb6cffd4a5a7a7709e86590ae61987",
"dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053",
"74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20",
},
"2fda58e5959b0ee53c5253da9b9f3c0c739422ae04946966991cf55895287552",
},
}
for _, oneCase := range testcases {
var got *MerkleNode
var err error
if got,err = ConstructMerkleRoot(oneCase.txids); err != nil {
t.Error(err)
return
}
if got.Value != oneCase.merkleRoot {
t.Error("construct merkle root error")
t.Error("want: ", oneCase.merkleRoot)
t.Error("got: ", got.Value)
return
}
}
}
这里的测试数据都来自真实比特币主网区块数据,可自行添加测试用例
(全文完)
参考资料:
https://learnmeabitcoin.com/guide/merkle-root