源碼地址:https://github.com/corgi-kx/blockchain_consensus_algorithm/tree/master/pow
工作量證明機(jī)制的核心在于不斷hash區(qū)塊自身座慰,將hash值與根據(jù)難度值計算出的一串大數(shù)對比嚷堡,如果自身hash小于大數(shù)則說明挖礦成功萄涯,否則變化自身隨機(jī)數(shù)重新計算。并且程序會隨著出塊間隔時間動態(tài)調(diào)節(jié)難度值(比如比特幣)
區(qū)塊結(jié)構(gòu)
type block struct {
//上一個區(qū)塊的Hash
Lasthash string
//本區(qū)塊Hash
Hash string
//區(qū)塊存儲的數(shù)據(jù)(比如比特幣UTXO模型 則此處可用于存儲交易)
Data string
//時間戳
Timestamp string
//區(qū)塊高度
Height int
//難度值
DiffNum uint
//隨機(jī)數(shù)
Nonce int64
}
挖礦函數(shù):
使用math/big包,根據(jù)全局變量的難度值diffNum計算出用于實際比較的一串大數(shù)newBigint ,并同時將區(qū)塊hash轉(zhuǎn)換為大數(shù)hashInt 兩個大數(shù)進(jìn)行數(shù)值比較,如果hashInt小于newBigint 則代表挖礦成功
//區(qū)塊挖礦(通過自身遞增nonce值計算hash)
func mine(data string) block {
if len(blockchain) < 1 {
log.Panic("還未生成創(chuàng)世區(qū)塊狼忱!")
}
lastBlock := blockchain[len(blockchain)-1]
//制造一個新的區(qū)塊
newBlock := new(block)
newBlock.Lasthash = lastBlock.Hash
newBlock.Timestamp = time.Now().String()
newBlock.Height = lastBlock.Height + 1
newBlock.DiffNum = diffNum
newBlock.Data = data
var nonce int64 = 0
//根據(jù)挖礦難度值計算的一個大數(shù)
newBigint := big.NewInt(1)
newBigint.Lsh(newBigint, 256-diffNum) //相當(dāng)于左移 1<<256-diffNum
for {
newBlock.Nonce = nonce
newBlock.getHash()
hashInt := big.Int{}
hashBytes, _ := hex.DecodeString(newBlock.Hash)
hashInt.SetBytes(hashBytes) //把本區(qū)塊hash值轉(zhuǎn)換為一串?dāng)?shù)字
//如果hash小于挖礦難度值計算的一個大數(shù),則代表挖礦成功
if hashInt.Cmp(newBigint) == -1 {
break
} else {
nonce++ //不滿足條件一睁,則不斷遞增隨機(jī)數(shù)钻弄,直到本區(qū)塊的散列值小于指定的大數(shù)
}
}
return *newBlock
}
func main() {
//制造一個創(chuàng)世區(qū)塊
genesisBlock := new(block)
genesisBlock.Timestamp = time.Now().String()
genesisBlock.Data = "我是創(chuàng)世區(qū)塊!"
genesisBlock.Lasthash = "0000000000000000000000000000000000000000000000000000000000000000"
genesisBlock.Height = 1
genesisBlock.Nonce = 0
genesisBlock.DiffNum = 0
genesisBlock.getHash()
fmt.Println(*genesisBlock)
//將創(chuàng)世區(qū)塊添加進(jìn)區(qū)塊鏈
blockchain = append(blockchain, *genesisBlock)
for i := 0; i < 10; i++ {
newBlock := mine("天氣不錯"+strconv.Itoa(i))
blockchain = append(blockchain, newBlock)
fmt.Println(newBlock)
}
運(yùn)行結(jié)果: