go实现区块链[2]-整合默克尔树+POW

添加merkleRoot

merkleTree.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import "crypto/sha256"


//默克尔树节点
type MerkleTree struct{
RootNode *MerkleNode
}

//默克尔根节点
type MerkleNode struct{
Left *MerkleNode
Right *MerkleNode
Data []byte
}
//生成默克尔树中的节点,如果是叶子节点,则Left,right为nil ,如果为非叶子节点,根据Left,right生成当前节点的hash
func NewMerkleNode(left,right *MerkleNode,data []byte) *MerkleNode{
mnode := MerkleNode{}

if left ==nil && right==nil{
mnode.Data = data
}else{
prevhashes := append(left.Data,right.Data...)
firsthash:= sha256.Sum256(prevhashes)
hash:=sha256.Sum256(firsthash[:])
mnode.Data = hash[:]
}

mnode.Left = left
mnode.Right = right

return &mnode
}

//构建默克尔树
func NewMerkleTree(data [][]byte) *MerkleTree{
var nodes []MerkleNode
//构建叶子节点。
for _,datum := range data{
node:= NewMerkleNode(nil,nil,datum)
nodes = append(nodes,*node)
}
//j代表的是某一层的第一个元素
j:=0
//第一层循环代表 nSize代表某一层的个数,每循环一次减半
for nSize :=len(data);nSize >1;nSize = (nSize+1)/2{
//第二条循环i+=2代表两两拼接。 i2是为了当个数是基数的时候,拷贝最后的元素。
for i:=0 ; i<nSize ;i+=2{
i2 := min(i+1,nSize-1)

node := NewMerkleNode(&nodes[j+i],&nodes[j+i2],nil)
nodes = append(nodes,*node)
}
//j代表的是某一层的第一个元素
j+=nSize

}

mTree := MerkleTree{&(nodes[len(nodes)-1])}
return &mTree
}

根据交易创建merkleROOT

1
2
3
4
5
6
7
8
9
10
11
12
13

func (b*Block) createMerkelTreeRoot(transations []*Transation){
var tranHash [][]byte

for _,tx:= range transations{

tranHash = append(tranHash,tx.Hash())
}

mTree := NewMerkleTree(tranHash)

b.Merkleroot = mTree.RootNode.Data
}

测试merkle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


func TestCreateMerkleTreeRoot(){
//初始化区块
block := &Block{
2,
[]byte{},
[]byte{},
[]byte{},
1418755780,
404454260,
0,
[]*Transation{},
}



txin := TXInput{[]byte{},-1,nil}
txout := NewTXOutput(subsidy,"first")
tx := Transation{nil,[]TXInput{txin},[]TXOutput{*txout}}

txin2 := TXInput{[]byte{},-1,nil}
txout2 := NewTXOutput(subsidy,"second")
tx2 := Transation{nil,[]TXInput{txin2},[]TXOutput{*txout2}}

var Transations []*Transation

Transations = append(Transations,&tx,&tx2)

block.createMerkelTreeRoot(Transations)

fmt.Printf("%x\n",block.Merkleroot)
}

增加挖矿逻辑

proofofwork.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package main

import (
"math/big"
"bytes"
"crypto/sha256"
)

type ProofOfWork struct{
block * Block
tartget * big.Int
}
const targetBits = 16


func NewProofofWork(b*Block) * ProofOfWork{

target := big.NewInt(1)
target.Lsh(target,uint(256-targetBits))
pow := &ProofOfWork{b,target}
return pow
}

func (pow * ProofOfWork) prepareData(nonce int32) []byte{

data := bytes.Join(
[][]byte{
IntToHex(pow.block.Version),
pow.block.PrevBlockHash,
pow.block.Merkleroot,
IntToHex(pow.block.Time),
IntToHex(pow.block.Bits),
IntToHex(nonce)},
[]byte{},
)
return data
}

func (pow * ProofOfWork) Run() (int32,[]byte){

var nonce int32
var secondhash [32]byte
nonce = 0
var currenthash big.Int

for nonce < maxnonce{


//序列化
data:= pow.prepareData(nonce)
//double hash
fitstHash := sha256.Sum256(data)
secondhash = sha256.Sum256(fitstHash[:])
// fmt.Printf("%x\n",secondhash)


currenthash.SetBytes(secondhash[:])
//比较
if currenthash.Cmp(pow.tartget) == -1{
break
}else{
nonce++
}
}


return nonce,secondhash[:]
}

func (pow * ProofOfWork) Validate() bool{
var hashInt big.Int

data:=pow.prepareData(pow.block.Nonce)

fitstHash := sha256.Sum256(data)
secondhash := sha256.Sum256(fitstHash[:])
hashInt.SetBytes(secondhash[:])
isValid:= hashInt.Cmp(pow.tartget) == -1

return isValid
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func TestPow(){
//初始化区块
block := &Block{
2,
[]byte{},
[]byte{},
[]byte{},
1418755780,
404454260,
0,
[]*Transation{},
}

pow:=NewProofofWork(block)

nonce,_:= pow.Run()

block.Nonce = nonce

fmt.Println("POW:",pow.Validate())

}