1. 程式人生 > >go實現區塊鏈[2]-整合默克爾樹+POW

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()