Go語言學習(三) 簡單比特幣挖礦類實現
阿新 • • 發佈:2018-12-13
//utils.go
package main
import (
"bytes"
"encoding/binary"
"log"
)
func IntToHex(num int64)[]byte{
buff:=new(bytes.Buffer) //開闢記憶體,儲存位元組集
err:=binary.Write(buff,binary.BigEndian,num)//num轉化位元組集寫入
if err!=nil{
log.Panic(err)
}
return buff.Bytes() //返回位元組集合
}
//block.go package main import ( "time" ) //定義區塊 type Block struct{ Timestamp int64 //時間線,1970年1月1日00.00.00 Data []byte //交易資料 PrevBlockHash []byte //上一塊資料的雜湊 Hash []byte //當前塊資料的雜湊 Nonce int //工作量證明 } /*//設定結構體物件雜湊 func (block *Block)SetHash(){ //處理當前的時間,轉化為10進位制的字串,再轉化為位元組集合 timestamp:=[]byte(strconv.FormatInt(block.Timestamp,10)) //疊加要雜湊的資料 headers:=bytes.Join([][]byte{block.PrevBlockHash,block.Data,timestamp},[]byte{}) //計算出雜湊地址 hash:=sha256.Sum256(headers) block.Hash=hash[:]//設定雜湊 }*/ //建立一個區塊 func NewBlock(data string, prevBlockHash []byte) *Block{ //block是一個指標,取得一個物件初始化之後的地址 block:=&Block{time.Now().Unix(),[]byte(data),prevBlockHash,[]byte{},0} pow:=NewProofOfWork(block)//挖礦附加這個區塊 nonce,hash:=pow.Run()//開始挖礦 block.Hash=hash[:] block.Nonce=nonce //block.SetHash()//設定當前雜湊 return block } //建立創世區塊, func NewGenesisBlock() *Block{ return NewBlock("hello, welcome to my second BlockChain",[]byte{}) }
//blockchain.go package main type BlockChain struct{ blocks []*Block //一個數組,每個元素都是指標,儲存block區塊的地址 } //增加一個區塊 func (blocks *BlockChain)AddBlock(data string ){ prevBlock:=blocks.blocks[len(blocks.blocks)-1] //取出最後一個區塊 newBlock:=NewBlock(data,prevBlock.Hash) //建立一個區塊 blocks.blocks=append(blocks.blocks,newBlock) //區塊鏈插入新的區塊 } //建立一個區塊鏈 func NewBlockchain ()*BlockChain{ return &BlockChain{[]*Block{NewGenesisBlock()}} }
//proofofwork.go package main import ( "bytes" "crypto/sha256" "fmt" "math" "math/big" ) var( maxNonce=math.MaxInt64 //最大的64位整數 ) const targetBits=24//對比的位數 type ProofOfWork struct{ block *Block //區塊 target * big.Int //儲存計算雜湊對比的特定整數 } //建立一個工作量證明的挖礦物件 func NewProofOfWork(block *Block)*ProofOfWork{ target:=big.NewInt(1) //初始化目標整數 target.Lsh(target,uint(256-targetBits)) //資料轉換 pow:=&ProofOfWork{block,target} //建立物件 return pow } //準備資料進行挖礦計算 func (pow * ProofOfWork) prepareData(nonce int)[]byte{ data:=bytes.Join( [][]byte{ pow.block.PrevBlockHash,//上一塊雜湊 pow.block.Data,//當前資料 IntToHex(pow.block.Timestamp),//時間十六進位制 IntToHex(int64(targetBits)),//位數十六進位制 IntToHex(int64(nonce)),//儲存工作量的nonce },[]byte{}, ) return data } //挖礦執行 func (pow * ProofOfWork) Run()(int,[]byte){ var hashInt big.Int var hash [32]byte nonce:=0 fmt.Printf("當前挖礦計算的區塊資料%s",pow.block.Data) for nonce<maxNonce{ data:=pow.prepareData(nonce)//準備好的資料 hash=sha256.Sum256(data)//計算出雜湊 fmt.Printf("\r%x",hash)//列印顯示雜湊 hashInt.SetBytes(hash[:])//獲取要對比的資料 if hashInt.Cmp(pow.target)==-1{//挖礦的校驗 break }else{ nonce++ } } fmt.Println("\n\n") return nonce,hash[:]//nonce解題的答案,hash當前雜湊 } //校驗挖礦是不是真的成功 func (pow * ProofOfWork) Validate()bool{ var hashInt big.Int data := pow.prepareData(pow.block.Nonce)//準備好的資料 hash:=sha256.Sum256(data)//計算出雜湊 hashInt.SetBytes(hash[:])//獲取要對比的資料 isValid:=(hashInt.Cmp(pow.target)==-1)//校驗資料 return isValid }
//test_pow.go
package main
import (
"crypto/sha256"
"fmt"
"strconv"
"time"
)
func mainx(){
flag:=0
start:=time.Now() //當前時間
for i:=0;i<10000000000;i++{ //迴圈挖礦
data:=sha256.Sum256([]byte(strconv.Itoa(i))) //計算雜湊
fmt.Printf("%10d,%x\n",i,data)
fmt.Printf("%s\n",string(data[len(data)-2:]))
if string(data[len(data)-2:])=="00"{ //位數的雜湊匹配
usedtime:=time.Since(start)
fmt.Printf("挖礦成功,用時%d ms\n",usedtime)
flag=1
break
}
}
if flag==0{
println("挖礦失敗")
}
}
//main.go
package main
import (
"fmt"
"strconv"
)
func main(){
fmt.Println("hello game start")
bc:=NewBlockchain() //建立區塊鏈
bc.AddBlock("小明1 pay 小紅 10")
bc.AddBlock("小明2 pay 小紅 20")
bc.AddBlock("小明3 pay 小紅 30")
for _,block:=range bc.blocks{
fmt.Printf("上一塊雜湊%x\n",block.PrevBlockHash)
fmt.Printf("資料: %s\n",block.Data)
fmt.Printf("當前雜湊%x\n",block.Hash)
pow:=NewProofOfWork(block)//校驗工作量
fmt.Printf("pow %s\n",strconv.FormatBool(pow.Validate()))
fmt.Println()
}
}