1. 程式人生 > >簡單區塊鏈的實現(帶POW挖礦系統)

簡單區塊鏈的實現(帶POW挖礦系統)

前言

在IT界,2018最火的熱詞相必就是區塊鏈了,C++和GO是目前最適合區塊鏈開發的兩種語言,所以咱們學GO的肯定得學一點區塊鏈的知識,但是區塊鏈涉及太多密碼學,金融學、p2p網路等知識了,從哪裡切入呢,今天我們就從用go實現一條帶有模擬挖礦系統的簡單區塊鏈。

程式碼分析

三大模組 程式碼還是比較簡單清晰的,主要有三個模組,Block模組、BlockChain模組、POW模組即挖礦模組。 執行流程

  • 首先從定義一個區塊開始,一個區塊中包含的資訊有區塊資訊,時間戳,前區塊雜湊值,現區塊雜湊值,經過挖礦後得到的雜湊碰撞值等等。
  • 接著我們開啟一個切片用來存放一個個區塊,但是第一個區塊是比較特殊的,我們稱之為創世區塊,在真實的比特幣中,第一個區塊是由創始人中本聰挖礦所得,沒有前雜湊值,所以這裡我們直接將第一個創世區塊建立新增到區塊切片中。
  • 然後給到一個新增區塊的方法,使用者新增區塊資訊後,經過POW挖礦系統才能成功新增到區塊鏈上。

有了大概的執行流程接下來再來看程式碼就會輕鬆很多了。

程式碼

package main

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

//Block模組
type Block struct {
	Version uint64		//版本號
	MerkelRoot []byte	//這是一個雜湊值,後面V5用到
	TimeStamp string 	//時間戳
	Difficulty uint64
//難度值 Nonce uint64 //挖礦所找到的隨機數 PrevBlockHash []byte//前區塊雜湊值 Data []byte //插入的資料 Hash []byte //當前區塊雜湊值 } //給到一個建立新區塊的方法 func newBlock(data,prehash []byte)*Block { block:=Block{ Version:00, MerkelRoot:[]byte{}, TimeStamp:time.Now().Format("2006-15:04:05"), Difficulty:difficulty, Data:data, PrevBlockHash:
prehash, } //需要被挖礦之後才能建立區塊,所以呼叫挖礦函式 pow:=NewPOW(&block) nonce,hash:=pow.Mine() //挖礦結束,得到雜湊碰撞值 block.Nonce=nonce block.Hash=hash return &block } //Blockchain模組 const gnnesinfo="1996年9月2日,一代偉人誕生了" //給到一個區塊鏈結構 type Blockchain struct { blocks []*Block } //將創世區塊加入區塊鏈,並返回一條可供操作的區塊鏈 func NewblockChain()*Blockchain { var bc Blockchain block:=newBlock([]byte(gnnesinfo),[]byte{}) bc.blocks=append(bc.blocks,block) return &bc } //給到一個增加區塊的方法 func (this *Blockchain)Addblock(data []byte) { lastblockhash:=this.blocks[len(this.blocks)-1].Hash block:=newBlock(data,lastblockhash) this.blocks=append(this.blocks,block) } //遍歷,列印所有 func (this *Blockchain)PrintAll() { for i,v:=range this.blocks { fmt.Printf("=========區塊高度%d=========\n",i) fmt.Printf("Version : %d\n", v.Version) fmt.Printf("PrevBlockHash : %x\n", v.PrevBlockHash) fmt.Printf("Hash : %x\n", v.Hash) fmt.Printf("MerkleRoot : %x\n", v.MerkelRoot) fmt.Printf("TimeStamp : %s\n", v.TimeStamp) fmt.Printf("Difficuty : %d\n", v.Difficulty) fmt.Printf("Nonce : %d\n", v.Nonce) fmt.Printf("Data : %s\n", v.Data) } } //pow挖礦模組 const difficulty=24 //POW挖礦結構需要兩個引數,一個是所需挖礦的區塊,另一個是挖礦成功所需目標數字 type ProofOfWork struct { target *big.Int block *Block } //給到一個根據難度值得到雜湊碰撞目標值的函式 func Gettargetint()*big.Int { targetint:=big.NewInt(1) targetint.Lsh(targetint,256-difficulty) return targetint } //建立挖礦的方法 func NewPOW(block *Block)*ProofOfWork { var this ProofOfWork this.block=block targetint:=Gettargetint() this.target=targetint return &this } //一個用來將uint64轉化為字元切片的小函式,方便接下來的轉化 func uint2byte(num uint64)[]byte { var buff bytes.Buffer binary.Write(&buff,binary.BigEndian,&num) return buff.Bytes() } //挖礦的準備工作,將其他字元組合起來之後求其雜湊值 func (pow *ProofOfWork)PreparetoMine(nonce uint64)[]byte { info:=[][]byte{ pow.block.PrevBlockHash, pow.block.Data, uint2byte(nonce), uint2byte(pow.block.Version), uint2byte(pow.block.Difficulty), []byte(pow.block.TimeStamp), pow.block.MerkelRoot, } allinfo:=bytes.Join(info,[]byte{}) hash:=sha256.Sum256(allinfo) return hash[:] } //pow挖礦方法,返回兩個引數,一個是碰撞成功的數字nonce,另一個是當前區塊雜湊值 func (pow *ProofOfWork)Mine()(uint64,[]byte) { var nonce uint64 //nonce從0開始窮舉,直到出現雜湊值小於給到的目標值 var hash []byte for { hash=pow.PreparetoMine(nonce) var hashint big.Int hashint.SetBytes(hash) //對比雜湊值是否小於目標值,小於則成功退出 if hashint.Cmp(pow.target)==-1 { break } //不小於則繼續窮舉 nonce++ } return nonce,hash } //呼叫 func main() { bc:=NewblockChain() bc.Addblock([]byte("gaozijian")) bc.Addblock([]byte("istheweiren")) bc.PrintAll() }

以上就是一個微型的區塊鏈了,雖然看起來很簡單,但是對於理解比特幣、區塊鏈還是有不少幫助的。

若是感興趣或者不屑一顧的大牛們可以戳我的githubGO語言實現比特幣系統,是這個小區塊鏈的升級版本,並且將持續維護更新,加入了命令列功能、UTXO轉賬機制,bolt資料庫儲存、等,更加接近真正的比特幣系統

也歡迎各位給我留言,共同學習: )