Pow(Proof Of Work)
的中文翻譯是:工作量證明颜价,是區(qū)塊鏈共識(shí)機(jī)制
的一種谒亦。
我們都知道比特幣系統(tǒng)是由全球無數(shù)個(gè)節(jié)點(diǎn)支撐著整個(gè)系統(tǒng)的正常運(yùn)轉(zhuǎn)彬向。每打包一個(gè)區(qū)塊(記一筆賬),也就是把上一個(gè)區(qū)塊和當(dāng)前區(qū)塊的所有的交易(上節(jié)中我們講到區(qū)塊結(jié)構(gòu)的data
)打包在一個(gè)區(qū)塊鏈上并廣播給其他的節(jié)點(diǎn)屡拨。
那么問題來了:
1.全球這么多節(jié)點(diǎn)中每個(gè)節(jié)點(diǎn)都有權(quán)利打包區(qū)塊只酥,區(qū)塊由誰去打包。
2.我為什么要耗費(fèi)我的電腦系統(tǒng)資源去參與到打包區(qū)塊(記賬
)中去呀狼。
Pow
簡單點(diǎn)來說就是我隨機(jī)出一個(gè)數(shù)裂允,誰先猜到了就由誰來記賬。當(dāng)然因?yàn)槟愕姆e極參與哥艇,也會(huì)得到一筆比特幣作為獎(jiǎng)勵(lì)绝编。系統(tǒng)會(huì)自動(dòng)通過當(dāng)前全網(wǎng)的算力將區(qū)塊產(chǎn)出的速度控制在10分鐘左右,那么開辟一個(gè)新區(qū)塊就叫做我們經(jīng)常聽到的挖礦
下面我們就來實(shí)現(xiàn)這么一個(gè)算法
先來簡單回顧一下我們上節(jié)中區(qū)塊組成的基本結(jié)構(gòu)
type Block struct {
Height int64
Data []byte
Timestamp int64
PrevHash []byte
Hash []byte
}
本節(jié)中新增的屬性
Nonce int64
還記得我之前講的“誰先猜到了就由誰來記賬”
這句話嗎貌踏?既然是猜十饥,那么肯定是通過某個(gè)值,不斷的去改變他的值然后進(jìn)行判斷看他是否符合我們需要的結(jié)果祖乳。
所以這個(gè)nonce
就派上用場了逗堵。
block.info上查看到的區(qū)塊信息,看到了嗎眷昆?比特幣區(qū)塊中的nonce
每次創(chuàng)建區(qū)塊蜒秤,都要去驗(yàn)證汁咏。新創(chuàng)建一個(gè)對(duì)象,專門處理挖礦驗(yàn)證作媚。
func NewBlock(height int64, data []byte, prev []byte) *Block {
block := &Block{
height,
data,
time.Now().Unix(),
prev,
nil,
0,
}
//以前的Hash是這么來的
//block.Hash = block.SetHash()
//現(xiàn)在的Hash
//1.創(chuàng)建pow的對(duì)象得到區(qū)塊和難度值
pow := NewProofOfWork(block)
//2.開始挖礦驗(yàn)證區(qū)塊
hash, nonce := pow.Run()
//3.給區(qū)塊進(jìn)行賦值
block.Nonce = nonce
block.Hash = hash
return block
}
工作量證明的結(jié)構(gòu)
type ProofOfWork struct {
Block *Block //當(dāng)前要驗(yàn)證的區(qū)塊
diff *big.Int //大數(shù)據(jù)存儲(chǔ)
}
創(chuàng)建新的工作量證明梆暖,設(shè)置難度值
原理:如果隨機(jī)生成的Hash(二進(jìn)制)小于難度值則挖礦成功
實(shí)現(xiàn)過程:
將1左移(256-20(由常量定義的
targetBit值))位。然后轉(zhuǎn)換成二進(jìn)制格式如下
//前面有20個(gè)零
diff :`0000 0000 0000 0000 00010000...0000`
左移的方法:
diff := diffBig.Lsh(diffBig, 256-targetBit)
創(chuàng)建工作量證明的完整函數(shù):
//創(chuàng)建新的工作量證明
const targetBit = 20
func NewProofOfWork(block *Block) *ProofOfWork {
//設(shè)置好難度
diffBig := big.NewInt(1)
diff := diffBig.Lsh(diffBig, 256-targetBit)
return &ProofOfWork{block, diff}
}
開始運(yùn)行掂骏,用死循環(huán)去不斷累積nonce
當(dāng)找到符合要求的就退出循環(huán)轰驳。滿足條件(當(dāng)隨機(jī)到的值小于難度值算成功)
func (pow *ProofOfWork) Run() ([]byte, int64) {
//1. 將Block的屬性拼接成字節(jié)數(shù)組
nonce := 0
var hashInt big.Int //存儲(chǔ)新生成的HASH
var hash [32]byte
for {
//準(zhǔn)備數(shù)據(jù)
dataBytes := pow.prepareData(nonce)
hash = sha256.Sum256(dataBytes)
fmt.Printf("\r%x :", hash)
//將hash存儲(chǔ)到hashInt
hashInt.SetBytes(hash[:])
//fmt.Println(hashInt)
//判斷hashInt是否小于Block里面的target //3. 判斷hash有效性,如果滿足條件,跳出循環(huán)
if pow.diff.Cmp(&hashInt) == 1 {
break
}
//通過nonce值不斷變化求結(jié)果
nonce = nonce + 1
}
return hash[:], int64(nonce)
}
今天的內(nèi)容你是否學(xué)會(huì)了呢弟灼?如果沒有可以去下載源碼自己進(jìn)行編譯级解,調(diào)試去跟蹤一下執(zhí)行過程。很快就明白了田绑。
https://gitee.com/itgjz/blockchain_learn/tree/master/block_chain_learn3