区块链实战PoW工作量证明的实现
Posted 小生凡一
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区块链实战PoW工作量证明的实现相关的知识,希望对你有一定的参考价值。
Version 2
-
定义一个工作量证明的结构ProofOfWork
block
目标值
-
提供一个创造PoW的方法
NewProofOfWork(参数)
-
提供一个计算哈希值的方法
Run()
-
提供一个校验函数
IsValid()
结构目录
block.go
package main
import (
"time"
)
/*
1.定义一个区块的结构Block
a.区块头:6个字段
b.区块体:字符串表示data
*/
//区块
type Block struct {
Version int64 //版本
PerBlockHash []byte //前一个区块的hash值
Hash []byte //当前区块的hash值,是为了简化代码
MerKelRoot []byte //梅克尔根
TimeStamp int64 //时间抽
Bits int64 //难度值
Nonce int64 //随机值
//区块体
Data []byte //交易信息
}
/*
提供一个创建区块的方法
NewBlock(参数)
*/
func NewBlock(data string ,prevBlockHash []byte) *Block {
var block Block
block = Block{
Version: 2,
PerBlockHash: prevBlockHash,
//Hash: []byte{}, //区块不存储hash值,节点接受区块后独立计算并存储在本地。
MerKelRoot: []byte{},
TimeStamp: time.Now().Unix(),
Bits: targetBits,
Nonce: 0,
Data: []byte(data),
}
// block.SetHash() //填充Hash
PoW:= NewProofOfWork(&block)
nonce , hash :=PoW.Run()
block.Nonce=nonce
block.Hash=hash
return &block
}
/*
func (block *Block) SetHash() {
// 源码里面是要传二维切片 func Join(s [][]byte, sep []byte) []byte
tmp :=[][]byte{
IntToByte(block.Version),
block.PerBlockHash,
block.MerKelRoot,
IntToByte(block.TimeStamp),
IntToByte(block.Bits),
IntToByte(block.Nonce),
}
data:=bytes.Join(tmp,[]byte{}) //之后再计算hash
hash := sha256.Sum256(data)
block.Hash = hash[:] //变切片
}
*/
//创始块
func NewGensisBlock() *Block{
return NewBlock("Genesis Block!",[]byte{})
}
blockChain.go
package main
/*
1. 定义一个区块链结构BlockChain
Block数组
*/
type BlockChain struct {
blocks []*Block
}
/*
2. 提供一个创建BlockChain()的方法
NewBlockChain()
*/
func NewBlockChain() *BlockChain {
block := NewGensisBlock()
return &BlockChain{blocks:[]*Block{block}} //创建只有一个元素的区块链,初始化
}
/*
3. 提供一个添加区块的方法
AddBlock(参数)
*/
func (bc *BlockChain)AddBlock(data string) {
PerBlockHash := bc.blocks[len(bc.blocks)-1].Hash //这一个区块的哈希是前一块的哈希值
block := NewBlock(data,PerBlockHash)
bc.blocks = append(bc.blocks,block)
}
proofOfWork.go
package main
import (
"bytes"
"crypto/sha256"
"fmt"
"math"
"math/big"
)
/*
1. 定义一个工作量证明的结构ProofOfWork
block
目标值
*/
type ProofOfWork struct {
block *Block
target *big.Int //目标值
}
/*
2. 提供一个创造PoW的方法
NewProofOfWork(参数)
*/
const targetBits = 24
func NewProofOfWork(block *Block) *ProofOfWork { //工作量证明
target := big.NewInt(1) //000....001
target.Lsh(target,uint(256-targetBits)) //将1向左移动 //ox00000010000000..00
pow:=ProofOfWork{
block: block,
target: target,
}
return &pow
}
func (pow *ProofOfWork) PrepareData(nonce int64) []byte {
// 源码里面是要传二维切片 func Join(s [][]byte, sep []byte) []byte
block := pow.block
tmp :=[][]byte{
IntToByte(block.Version),
block.PerBlockHash,
block.MerKelRoot,
IntToByte(block.TimeStamp),
IntToByte(block.Bits),
IntToByte(block.Nonce),
}
data:=bytes.Join(tmp,[]byte{}) //之后再计算hash
return data
}
/*
2. 提供一个计算哈希值的方法
Run()
*/
func (pow *ProofOfWork)Run() (int64,[]byte) {
/*伪代码
for nonce {
hash := sha256(block_data+nonce)
if (hash) < pow.target{
flag=1
}else{
flag=0
}
}
return nonce,hash[:]
*/
//1.凭借数据
//2.哈希值转成big.Int类型
var hash [32]byte
var nonce int64 = 0
var hashInt big.Int
fmt.Println("开始挖矿了!")
fmt.Printf("难度 target hash : %x\\n" ,pow.target.Bytes())
for nonce < math.MaxInt64 {
data:=pow.PrepareData(nonce)
hash = sha256.Sum256(data)
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
//
hashInt.SetBytes(hash[:])
if hashInt.Cmp(pow.target) == -1 {
fmt.Printf("Found ,nonce :%d ,hash :%x \\n",nonce,hash)
}else {
//fmt.Printf("Not Found ,current nonce :%d ,hash :%x \\n",nonce,hash)
nonce++
}
}
return nonce,hash[:]
}
/*
3. 提供一个校验函数
IsValid()
*/
func (pow *ProofOfWork)IsValid() bool{
var hashInt big.Int
data := pow.PrepareData(pow.block.Nonce)
hash:=sha256.Sum256(data)
hashInt.SetBytes(hash[:])
return hashInt.Cmp(pow.target) == -1 //如果是-1就是找到了就是
}
utils.go
package main
import (
"bytes"
"encoding/binary"
"fmt"
"os"
)
func IntToByte(num int64) []byte {
//func Write(w io.Writer, order ByteOrder, data interface{}) error {
var buffer bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, num)
CheckErr("IntToByte",err)
return buffer.Bytes()
}
func CheckErr(position string,err error) {
if err != nil {
fmt.Println("error ,pos:",position,err)
os.Exit(1)
}
}
main.go
package main
import "fmt"
func main() {
bc := NewBlockChain()
bc.AddBlock("A send B 1BTC")
bc.AddBlock("B send C 1BTC")
for _,block := range bc.blocks {
fmt.Printf("Version : %d\\n",block.Version)
fmt.Printf("PerBlockHash : %x\\n",block.PerBlockHash)
fmt.Printf("Hash : %x\\n",block.Hash)
fmt.Printf("MerKelRoot : %x\\n",block.MerKelRoot)
fmt.Printf("TimeStamp : %d\\n",block.TimeStamp)
fmt.Printf("Bits : %d\\n",block.Bits)
fmt.Printf("Nonce : %d\\n",block.Nonce)
fmt.Printf("Data : %s\\n",block.Data)
fmt.Printf("IsVaild : %v\\n",NewProofOfWork(block).IsValid())
}
}
结果
结构
以上是关于区块链实战PoW工作量证明的实现的主要内容,如果未能解决你的问题,请参考以下文章
创建区块链之v2实现pow(ProofOfWork工作量证明)