簡單區塊鏈的實現(帶POW挖礦系統)
阿新 • • 發佈:2018-12-20
前言
在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資料庫儲存、等,更加接近真正的比特幣系統
也歡迎各位給我留言,共同學習: )