2.1 ProofOfWork框架
我们在区块中添加一个属性Nonce来表示区块的生成难度,它是区块生成的一个重要条件,Nonce值越高,代表生成区块的难度越大,通过这种难度从而避免区块随意生成,工作量证明则是要完成这一系列难度区块生产所需要的工作量
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/BLC/Block.go
type Block struct {
//1.block height
Height int64
//2.the last block's hash
PreBlockHash []byte
//3.transaction data
Data []byte
//4.timestamp
Timestamp int64
//5.block's hash
Hash []byte
//6.Nonce
Nonce int64
}
当然生成区块的函数也要改一下
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/BLC/Block.go
func Newblock(height int64, preBlockHash []byte, data string) *Block {
//1.crate a new block
block := &Block{height, preBlockHash, []byte(data), time.Now().Unix(), nil, 0}
//2.calling the proof-of-work method returns Hash and Nonce
pow := NewProofOfWork(block)
hash, nonce := pow.Run()
block.Hash = hash[:]
block.Nonce = nonce
return block
}
我们通过工作量证明来生成区块的哈希和Nonce
//2.calling the proof-of-work method returns Hash and Nonce
pow := NewProofOfWork(block)
hash, nonce := pow.Run()
block.Hash = hash[:]
block.Nonce = nonce
2.2 工作量证明算法
接下来我们去构建NewProofOfWork函数和Run方法
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/BLC/ProofOfWork.go
package BLC
import "math/big"
//Has at least 16 0 in front of the hash
const targetBit = 16
type ProofOfWork struct {
Block *Block //The current block to be verified
target *big.Int //big number storage
}
func (proofOfWork *ProofOfWork) Run() ([]byte, int64) {
return nil, 0
}
//Create a new proof-of-work object
func NewProofOfWork(block *Block) *ProofOfWork {
//1.target = 1
target := big.NewInt(1)
//2.shift left
target = target.Lsh(target, 256-targetBit)
return &ProofOfWork{block, target}
}
这里的工作量证明变量我们依旧使用了一个结构体,我们的思路是每一个区块的生成都需要工作量证明
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/BLC/ProofOfWork.go
type ProofOfWork struct {
Block *Block //The current block to be verified
target *big.Int //big number storage
}
那如何实现工作量证明呢,我们定义一个 target变量、targetBit常量,通过左移targetBit位得到某种特定条件的target,新hash只要满足小于target就算有效哈希
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/BLC/ProofOfWork.go
const targetBits = 16
/*...*/
func NewProofOfWork(block *Block) *ProofOfWork {
//1.target = 1
target := big.NewInt(1)
//2.shift left
target = target.Lsh(target, 256-targetBits)
return &ProofOfWork{block, target}
}
2.3 挖矿算法实现
现在我们把区块中的所有属性都集合起来用于生成新的hash
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/BLC/ProofOfWork.go
func (pow *ProofOfWork) prepareData(nonce int64) []byte {
data := bytes.Join(
[][]byte{
pow.Block.PreBlockHash,
pow.Block.Data,
IntToHex(pow.Block.Timestamp),
IntToHex(int64(targetBit)),
IntToHex(int64(nonce)),
IntToHex(int64(pow.Block.Height)),
},
[]byte{},
)
return data
}
接下来我们生成hash和nonce值
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/BLC/ProofOfWork.go
func (proofOfWork *ProofOfWork) Run() ([]byte, int64) {
//1.Concatenate Block properties into byte slice
//2.produce hash
//3.Judging the validity of the hash
nonce := 0
var hashInt big.Int //store the newly generated hash
var hash [32]byte
for {
dataBytes := proofOfWork.prepareData(int64(nonce))
hash = sha256.Sum256(dataBytes)
fmt.Printf("\r%x", hash)
hashInt.SetBytes(hash[:])
if proofOfWork.target.Cmp(&hashInt) == 1 {
break
}
nonce = nonce + 1
}
return hash[:], int64(nonce)
}
然后我们再main函数中运行,非常漂亮,我们通过挖矿实现了区块的产生,成功的增加了难度
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/main.go
func main() {
//creat a Genesis Block
Blockchain := BLC.CreatBlockchainWithGenesisBlock()
// new block
Blockchain.AddBlockToBlockchain(Blockchain.Blocks[len(Blockchain.Blocks)-1].Height+1, Blockchain.Blocks[len(Blockchain.Blocks)-1].Hash, "Send 100RMB To Zhangqiang")
Blockchain.AddBlockToBlockchain(Blockchain.Blocks[len(Blockchain.Blocks)-1].Height+1, Blockchain.Blocks[len(Blockchain.Blocks)-1].Hash, "Send 300RMB To Xinyi")
Blockchain.AddBlockToBlockchain(Blockchain.Blocks[len(Blockchain.Blocks)-1].Height+1, Blockchain.Blocks[len(Blockchain.Blocks)-1].Hash, "Send 200RMB To Gaojian")
Blockchain.AddBlockToBlockchain(Blockchain.Blocks[len(Blockchain.Blocks)-1].Height+1, Blockchain.Blocks[len(Blockchain.Blocks)-1].Hash, "Send 500RMB To Xiaochu")
fmt.Println(Blockchain)
}
0000ea74e6e5a7b8b4b384bb57ab63978f56cdaa080609e9699adc444b888563
000004abeb1003d183fc40a48c93a723ad97f164e3489c7d22b0eddf24f033f8
0000495344f6ee5a571dbe52ac5fd959424a058173edd9cdc03b8f560495e9c8
00004e5f086817a139506275a2a0274bab491890b9b92facfe39e24a8f299285
000078e5dc33079b73723d1e3e5156fecebb9559a7a764c2acc911b7e55e498e
&{[0xc000056180 0xc000056240 0xc0000564e0 0xc00043c060 0xc00043c120]}
2.4 判断区块hash的有效性
我们定一个方法用来判断区块的哈希是否有效
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/BLC/ProofOfWork.go
func (proofOfWork *ProofOfWork) IsVlaid() bool {
var hashInt big.Int
hashInt.SetBytes(proofOfWork.Block.Hash)
if proofOfWork.target.Cmp(&hashInt) == 1 {
return true
}
return false
}
接着我们在main函数中创建一个区块,并且使用验证方法进行验证
/Users/xxx/go/src/publicChain/part5-Basic-Prototype/main.go
package main
import (
"fmt"
"publicChain/part8-Basic-Prototype/BLC"
)
func main() {
block := BLC.Newblock(1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, "Test")
fmt.Printf("%d\n", block.Nonce)
fmt.Printf("%x\n", block.Hash)
proofOfWork := BLC.NewProofOfWork(block)
fmt.Printf("%v", proofOfWork.IsVlaid())
}
000001f16eff6d4110f9ba84471a1d9c0654561020d36cf5fe20e971df123b3d
203277
000001f16eff6d4110f9ba84471a1d9c0654561020d36cf5fe20e971df123b3d
true
结果如期运行,通过了验证
|