区块链实战PoW工作量证明的实现

Posted 小生凡一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区块链实战PoW工作量证明的实现相关的知识,希望对你有一定的参考价值。

Version 2

  1. 定义一个工作量证明的结构ProofOfWork

    block

​ 目标值

  1. 提供一个创造PoW的方法

    NewProofOfWork(参数)

  2. 提供一个计算哈希值的方法

    Run()

  3. 提供一个校验函数

    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工作量证明的实现的主要内容,如果未能解决你的问题,请参考以下文章

区块链实现之POW分析

区块链实现之POW分析

区块链,工作证明(POW)代码+原理 golang版剖析

创建区块链之v2实现pow(ProofOfWork工作量证明)

五分钟看明白区块链,工作证明(POW)代码+原理 golang版剖析

区块链之工作量证明