溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

區(qū)塊鏈初始化與實(shí)現(xiàn)POW工作量證明

發(fā)布時(shí)間:2020-07-20 00:59:18 來(lái)源:網(wǎng)絡(luò) 閱讀:11214 作者:暗黑魔君 欄目:編程語(yǔ)言

目錄:

一.初始化區(qū)塊鏈

1.代碼結(jié)構(gòu)

2. 定義區(qū)塊結(jié)構(gòu)與方法

3. 定義區(qū)塊鏈結(jié)構(gòu)與方法

4. 幫助庫(kù)代碼

5. 測(cè)試生成區(qū)塊與初始化區(qū)塊鏈

6. 測(cè)試代碼

二. POW挖礦實(shí)現(xiàn)

1.代碼結(jié)構(gòu)

2. 定義pow算法實(shí)現(xiàn)

3. 修改區(qū)塊的生成方式(從自定義到挖礦)

4. 測(cè)試代碼,測(cè)試挖礦

5.驗(yàn)證區(qū)塊有效性


一.初始化區(qū)塊鏈

1. 代碼結(jié)構(gòu)

區(qū)塊鏈初始化與實(shí)現(xiàn)POW工作量證明


Block.go :定義區(qū)塊結(jié)構(gòu)與方法

BlockChain.go :定義區(qū)塊鏈結(jié)構(gòu)與方法

help.go :將常用代碼塊進(jìn)行封裝,形成幫助庫(kù)

main.go:測(cè)試代碼


2.定義區(qū)塊結(jié)構(gòu)與方法


package BLC

import (
   "time"
   "strconv"
   "bytes"
   "crypto/sha256"
)

//定義區(qū)塊
type Block struct {
   //1.區(qū)塊高度,也就是區(qū)塊的編號(hào),第幾個(gè)區(qū)塊
   Height int64
   //2.上一個(gè)區(qū)塊的Hash值
   PreBlockHash []byte
   //3.交易數(shù)據(jù)(最終都屬于transaction 事務(wù))
   Data []byte
   //4.創(chuàng)建時(shí)間的時(shí)間戳
   TimeStamp int64
   //5.當(dāng)前區(qū)塊的Hash值
   Hash []byte
   //6.Nonce 隨機(jī)數(shù),用于驗(yàn)證工作量證明
   Nonce int64
}

//定義區(qū)塊生成Hash的方法
func (block *Block) SetHash() {
   //1.將Height 轉(zhuǎn)換為字節(jié)數(shù)組 []byte
   heightBytes := IntToHex(block.Height)

   //2.將TimeStamp 轉(zhuǎn)換為字節(jié)數(shù)組 []byte
   //2.1 將Int64的TimeStamp 轉(zhuǎn)換成二進(jìn)制
   timeString := strconv.FormatInt(block.TimeStamp, 2)
   //2.2 將二進(jìn)制字符串轉(zhuǎn)成字節(jié)數(shù)組
   timeBytes := []byte(timeString)

   //3.拼接所有屬性,形成一個(gè)二維的byte數(shù)組
   blockBytes := bytes.Join([][]byte{heightBytes, block.PreBlockHash, block.Data, timeBytes, block.Hash}, []byte{})
   //4.生成Hash
   hash := sha256.Sum256(blockBytes)
   block.Hash = hash[:]
}

//1. 創(chuàng)建新的區(qū)塊
func NewBlock(data string, height int64, PreBlockHash []byte) *Block {
   //創(chuàng)建區(qū)塊
   block := &Block{
      height,
      PreBlockHash,
      []byte(data),
      time.Now().Unix(),
      nil,
      0,
   }
   //設(shè)置Hash
   block.SetHash()
   return block

}

//2.生成創(chuàng)世區(qū)塊
func CreateGenesisBlock(data string) *Block {

   return NewBlock(data, 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})

}



3.定義區(qū)塊鏈與方法

package BLC

type BlockChain struct {
   Blocks []*Block //存儲(chǔ)有序的區(qū)塊
}


func (blc *BlockChain)AddBlockChain(data string,height int64,preHash []byte){
   //創(chuàng)建新區(qū)塊
   newBlock := NewBlock(data,height,preHash)
   //往鏈中添加區(qū)塊
   blc.Blocks=append(blc.Blocks,newBlock)

}


//1.創(chuàng)建帶有創(chuàng)世區(qū)塊的區(qū)塊鏈
func CreateBlockChainWithGenesisBlock() *BlockChain {

   //創(chuàng)建創(chuàng)世區(qū)塊
   genesisBlock := CreateGenesisBlock("Genesis Data..")
   //返回區(qū)塊鏈對(duì)象
   return &BlockChain{[]*Block{genesisBlock}}

}


4.幫助代碼庫(kù)

package BLC

import (
   "bytes"
   "encoding/binary"
   "log"
)

//將int64轉(zhuǎn)換為字節(jié)數(shù)組
func IntToHex(num int64) []byte {
   buff := new(bytes.Buffer)
   err := binary.Write(buff, binary.BigEndian, num)
   if err != nil {
      log.Panic(err)
   }
   return buff.Bytes()
}


5.測(cè)試代碼

package main

import (
   "publicChain/BLC"
   "fmt"
)

func main() {

   //創(chuàng)建創(chuàng)世區(qū)塊
   blockChain := BLC.CreateBlockChainWithGenesisBlock()

   //創(chuàng)建新的區(qū)塊
   blockChain.AddBlockChain("Send $100 to Bruce", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
   blockChain.AddBlockChain("Send $200 to Apple", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
   blockChain.AddBlockChain("Send $300 to Alice", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
   blockChain.AddBlockChain("Send $400 to Bob", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)

   fmt.Printf("創(chuàng)建的區(qū)塊鏈為:\t%v\n", blockChain)
   fmt.Printf("區(qū)塊鏈存儲(chǔ)的區(qū)塊為:\t%v\n", blockChain.Blocks)
   fmt.Printf("第二個(gè)區(qū)塊的數(shù)據(jù)信息(交易信息)為:\t%v\n", string(blockChain.Blocks[1].Data))

}


結(jié)果顯示


二. POW挖礦實(shí)現(xiàn)

1.代碼結(jié)構(gòu)


區(qū)塊鏈初始化與實(shí)現(xiàn)POW工作量證明

多出的ProofOfWork.go用于實(shí)現(xiàn)挖礦


2. 定義pow算法實(shí)現(xiàn)

ProofOfWork.go


package BLC

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

type ProofOfWork struct {
   Block  *Block   //當(dāng)前要驗(yàn)證的區(qū)塊
   target *big.Int //大數(shù)存儲(chǔ),區(qū)塊難度
}

//數(shù)據(jù)拼接,返回字節(jié)數(shù)組
func (pow *ProofOfWork) prePareData(nonce int) []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
}

//256位Hash里面至少要有16個(gè)零0000 0000 0000 0000
const targetBit = 16

func (proofOfWork *ProofOfWork) Run(num int64) ([]byte, int64) {

   //3.判斷Hash的有效性,如果滿足條件循環(huán)體

   nonce := 0
   var hashInt big.Int //存儲(chǔ)新生成的hash值
   var hash [32]byte

   for {
      //1. 將Block的屬性拼接成字節(jié)數(shù)組
      databytes := proofOfWork.prePareData(nonce)

      //2.生成Hash
      hash = sha256.Sum256(databytes)
      fmt.Printf("挖礦中..%x\n", hash)
      //3. 將hash存儲(chǔ)至hashInt
      hashInt.SetBytes(hash[:])


      //4.判斷hashInt是否小于Block里面的target
      // Cmp compares x and y and returns:
      //
      //   -1 if x <  y
      //    0 if x == y
      //   +1 if x >  y
      //需要hashInt(y)小于設(shè)置的target(x)
      if proofOfWork.target.Cmp(&hashInt) == 1 {
         //fmt.Println("挖礦成功", hashInt)
         fmt.Printf("第%d個(gè)區(qū)塊,挖礦成功:%x\n",num,hash)
         fmt.Println(time.Now())
         time.Sleep(time.Second * 2)
         break

      }

      nonce ++

   }

   return hash[:], int64(nonce)

}

//創(chuàng)建新的工作量證明對(duì)象
func NewProofOfWork(block *Block) *ProofOfWork {
   /*1.創(chuàng)建初始值為1的target
   0000 0001
   8 - 2
   */

   target := big.NewInt(1)

   //2.左移256-targetBit
   target = target.Lsh(target, 256-targetBit)

   return &ProofOfWork{block, target}
}




3. 修改區(qū)塊的生成方式(從自定義到挖礦)

Block.go

package BLC

import (
   "time"
)

//定義區(qū)塊
type Block struct {
   //1.區(qū)塊高度,也就是區(qū)塊的編號(hào),第幾個(gè)區(qū)塊
   Height int64
   //2.上一個(gè)區(qū)塊的Hash值
   PreBlockHash []byte
   //3.交易數(shù)據(jù)(最終都屬于transaction 事務(wù))
   Data []byte
   //4.創(chuàng)建時(shí)間的時(shí)間戳
   TimeStamp int64
   //5.當(dāng)前區(qū)塊的Hash值
   Hash []byte
   //6.Nonce 隨機(jī)數(shù),用于驗(yàn)證工作量證明
   Nonce int64
}

//1. 創(chuàng)建新的區(qū)塊
func NewBlock(data string, height int64, PreBlockHash []byte) *Block {
   //創(chuàng)建區(qū)塊
   block := &Block{
      height,
      PreBlockHash,
      []byte(data),
      time.Now().Unix(),
      nil,
      0,
   }
   //調(diào)用工作量證明的方法,并且返回有效的Hash和Nonce值
   //創(chuàng)建pow對(duì)象
   pow := NewProofOfWork(block)
   //挖礦驗(yàn)證
   hash, nonce := pow.Run(height)

   block.Hash = hash[:]
   block.Nonce = nonce
   return block

}

//2.生成創(chuàng)世區(qū)塊
func CreateGenesisBlock(data string) *Block {

   return NewBlock(data, 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})

}


4. 測(cè)試代碼,測(cè)試挖礦

main.go


package main

import (
   "publicChain/part2-工作量證明/BLC"
   "fmt"
)

func main() {

   fmt.Println("開始挖礦")
   //創(chuàng)建創(chuàng)世區(qū)塊
   blockChain := BLC.CreateBlockChainWithGenesisBlock()

   //創(chuàng)建新的區(qū)塊
   blockChain.AddBlockChain("Send $100 to Bruce", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)

   blockChain.AddBlockChain("Send $200 to Apple", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)

   blockChain.AddBlockChain("Send $300 to Alice", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)

   blockChain.AddBlockChain("Send $400 to Bob", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)

   fmt.Printf("創(chuàng)建的區(qū)塊鏈為:\t%v\n", blockChain)
   fmt.Printf("區(qū)塊鏈存儲(chǔ)的區(qū)塊為:\t%v\n", blockChain.Blocks)
   fmt.Printf("第二個(gè)區(qū)塊的數(shù)據(jù)信息(交易信息)為:\t%v\n", string(blockChain.Blocks[1].Data))
   fmt.Printf("第二個(gè)區(qū)塊的隨機(jī)數(shù)為:\t%v\n", blockChain.Blocks[1].Nonce)

}

測(cè)試結(jié)果

區(qū)塊鏈初始化與實(shí)現(xiàn)POW工作量證明


共計(jì)對(duì)五個(gè)區(qū)塊進(jìn)行挖礦,結(jié)果如上

5.驗(yàn)證區(qū)塊有效性 

ProofOfWork.go


//判斷挖礦得到的區(qū)塊是否有效
func (proofOfWork *ProofOfWork) IsValid() bool {
   //1.proofOfWork.Block.Hash
   //2.proofOfWork.Target
   var hashInt big.Int

   hashInt.SetBytes(proofOfWork.Block.Hash)

   if proofOfWork.target.Cmp(&hashInt) == 1 {
      return true
   }
   return false
}

測(cè)試代碼:

main.go

//通過(guò)POW挖出新的區(qū)塊block
block := BLC.NewBlock("Send $500 to Tom", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
//手動(dòng)將該區(qū)塊添加至區(qū)塊鏈中
blockChain.Blocks = append(blockChain.Blocks, block)
//創(chuàng)建一個(gè)工作量證明對(duì)象
proofOfWork := BLC.NewProofOfWork(block)
//判斷該區(qū)塊是否合法有效
fmt.Println(proofOfWork.IsValid())

測(cè)試結(jié)果:


區(qū)塊鏈初始化與實(shí)現(xiàn)POW工作量證明

第六個(gè)區(qū)塊是我們新創(chuàng)建的區(qū)塊,返回值為true,驗(yàn)證有效


參考資料:

區(qū)塊鏈共識(shí)算法-POW: https://www.jianshu.com/p/b23cbafbbad2 


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI