1.原理與補(bǔ)充知識(shí)
1.big.Int 的一些常見(jiàn)方法和屬性:
-
SetInt64(x int64)
:將一個(gè)int64
類(lèi)型的整數(shù)賦值給big.Int
。 -
SetString(s string, base int)
:將一個(gè)字符串表示的整數(shù)按照指定的進(jìn)制轉(zhuǎn)換為big.Int
。 -
SetBytes(x )(s string):講一個(gè)字節(jié)型變量轉(zhuǎn)換成big.Init
-
Add(x, y *big.Int) *big.Int
:將兩個(gè)big.Int
相加,并返回結(jié)果。 -
Sub(x, y *big.Int) *big.Int
:將一個(gè)big.Int
減去另一個(gè)big.Int
,并返回結(jié)果。 -
Mul(x, y *big.Int) *big.Int
:將兩個(gè)big.Int
相乘,并返回結(jié)果。 -
Div(x, y, z *big.Int) *big.Int
:將一個(gè)big.Int
除以另一個(gè)big.Int
,并返回商。 -
Mod(x, y, z *big.Int) *big.Int
:將一個(gè)big.Int
對(duì)另一個(gè)big.Int
取模,并返回結(jié)果。 -
Cmp(y *big.Int) int
:將big.Int
與另一個(gè)big.Int
比較,返回 -1、0 或 1,分別表示小于、等于或大于。
2.Target,nonce和PoW
target本質(zhì)上是一個(gè)和SHA256生成哈希值一樣大的整數(shù)
特殊的是這個(gè)數(shù)前幾位都是0
我們要求,通過(guò)反復(fù)枚舉nonce,生成一個(gè)小于target的數(shù)字。這樣新產(chǎn)生的區(qū)塊是成立的(即前面0個(gè)數(shù)大于等于)
這一過(guò)程被稱(chēng)為:工作量證明(PoW算法)
3.SHA256的充足性
sha256生成的哈希值256二進(jìn)制位,有大約是1.157920892×10^77種可能
而我們要求一個(gè)區(qū)塊鏈中的區(qū)塊哈希值不能相同,這個(gè)算法產(chǎn)生的值重復(fù)的概率幾乎為零
哪怕是滿(mǎn)足target限制的hash值也是
2.源代碼
package main
?
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
"log"
"math"
"math/big"
"time"
)
?
type Block struct {
Timestamp int64
Hash ? ? []byte
PrevHash []byte
Target ? []byte
Nonce ? ? int64 ?
Data ? ? []byte
}
?
const (
Difficulty = 12
)
?
func (b *Block) GetTarget() []byte {
target := big.NewInt(1)
target.Lsh(target, uint(256-Difficulty))
return target.Bytes()
}
?
func (b *Block) GetBase4Nonce(nonce int64) []byte {
data := bytes.Join([][]byte{
ToHexInt(b.Timestamp),
b.PrevHash,
ToHexInt(int64(nonce)),
b.Target,
b.Data,
},
[]byte{},
)
return data
}
?
func (b *Block) FindNonce() int64 {
var intHash big.Int
var intTarget big.Int
var hash [32]byte
var nonce int64
nonce = 0
intTarget.SetBytes(b.Target)
?
for nonce < math.MaxInt64 {
data := b.GetBase4Nonce(nonce)
hash = sha256.Sum256(data)
intHash.SetBytes(hash[:])
if intHash.Cmp(&intTarget) == -1 {
break
} else {
nonce++
}
}
return nonce
}
?
func (b *Block) ValidatePoW() bool {
var intHash big.Int
var intTarget big.Int
var hash [32]byte
intTarget.SetBytes(b.Target)
data := b.GetBase4Nonce(b.Nonce)
hash = sha256.Sum256(data)
intHash.SetBytes(hash[:])
if intHash.Cmp(&intTarget) == -1 {
return true
}
return false
}
?
?
func Handle(err error) {
if err != nil {
log.Panic(err)
}
}
?
func ToHexInt(num int64) []byte {
buff := new(bytes.Buffer)
err := binary.Write(buff, binary.BigEndian, num)
Handle(err)
return buff.Bytes()
}
?
type BlockChain struct {
Blocks []*Block
}
?
func (bc *BlockChain) AddBlock(data string) {
newBlock := CreateBlock(bc.Blocks[len(bc.Blocks)-1].Hash, []byte(data))
bc.Blocks = append(bc.Blocks, newBlock)
}
?
func CreateBlockChain() *BlockChain {
blockchain := BlockChain{}
blockchain.Blocks = append(blockchain.Blocks, GenesisBlock())
return &blockchain
}
?
func (b *Block) SetHash() {
information := bytes.Join([][]byte{ToHexInt(b.Timestamp), b.PrevHash, b.Target, ToHexInt(b.Nonce), b.Data}, []byte{})
hash := sha256.Sum256(information)
b.Hash = hash[:]
}
?
func CreateBlock(prevhash, data []byte) *Block {
block := Block{time.Now().Unix(), []byte{}, prevhash, []byte{}, 0, data}
block.Target = block.GetTarget()
block.Nonce = block.FindNonce()
block.SetHash()
return &block
}
?
func GenesisBlock() *Block {
genesisWords := "Hello, blockchain!"
return CreateBlock([]byte{}, []byte(genesisWords))
}
?
func main() {
chain := CreateBlockChain()
time.Sleep(time.Second)
chain.AddBlock("After genesis, I have something to say.")
time.Sleep(time.Second)
chain.AddBlock("Leo Cao is awesome!")
time.Sleep(time.Second)
chain.AddBlock("I can't wait to follow his github!")
time.Sleep(time.Second)
?
for _, block := range chain.Blocks {
fmt.Printf("Timestamp: %d\n", block.Timestamp)
fmt.Printf("hash: %x\n", block.Hash)
fmt.Printf("Previous hash: %x\n", block.PrevHash)
fmt.Printf("nonce: %d\n", block.Nonce)
fmt.Printf("data: %s\n", block.Data)
fmt.Println("Proof of Work validation:", block.ValidatePoW())
}
}
3.分塊分析
1.導(dǎo)入包作用
import ( "bytes" "crypto/sha256" "encoding/binary" "fmt" "log" "math" ? //提供了基本函數(shù) π e登常量 等等計(jì)算功能 //加密貨幣中的加密算法、共識(shí)機(jī)制和地址生成算法都可能涉及到數(shù)學(xué)運(yùn)算 "math/big" //這個(gè)包提供了大數(shù)運(yùn)算的支持 //加密貨幣中的橢圓曲線(xiàn)加密算法中經(jīng)常需要處理大數(shù) //區(qū)塊鏈中的一些計(jì)算可能涉及到非常大的數(shù)字,比如計(jì)算工作量證明的難度目標(biāo)值 "time" )
2.區(qū)塊包含元素作用
type Block struct { Timestamp int64 Hash ? ? []byte PrevHash []byte Target ? []byte //Target 字段通常用于表示工作量證明(Proof of Work,PoW)算法中的難度目標(biāo)值。 //在PoW算法中,礦工需要不斷嘗試不同的Nonce值,使得區(qū)塊的哈希值小于或等于Target,以此來(lái)滿(mǎn)足網(wǎng)絡(luò)的難度要求 //區(qū)塊頭中,Target字段表示了當(dāng)前區(qū)塊的目標(biāo)哈希值,礦工需要通過(guò)不斷調(diào)整Nonce值來(lái)尋找滿(mǎn)足條件的哈希值,從而完成區(qū)塊的挖掘工作 Nonce int64 //Nonce 字段是一個(gè)整數(shù)值,用于在PoW算法中嘗試尋找有效哈希值的過(guò)程中進(jìn)行遞增或變化。 //礦工通過(guò)調(diào)整Nonce值來(lái)產(chǎn)生不同的區(qū)塊哈希,以嘗試滿(mǎn)足難度目標(biāo)。 Data []byte }
3.難度
const ( Difficulty = 12 //設(shè)置難度 )
difficulty 反映了礦工找到下一個(gè)有效區(qū)塊的難易程度,難度隨區(qū)塊頭目標(biāo)Hash值(target)的變動(dòng)而變動(dòng),target值越小,難度越大。
4.生成Target
// 在區(qū)塊結(jié)構(gòu)體(Block)中獲取難度目標(biāo)(Target)的字節(jié)數(shù)組表示。 func (b *Block) GetTarget() []byte { //區(qū)塊頭目標(biāo)Hash值(target) target值越小,難度越大 target := big.NewInt(1) //NewInt 大整數(shù)對(duì)象是一種能夠存儲(chǔ)任意精度整數(shù)的數(shù)據(jù)類(lèi)型,用于處理超出普通整數(shù)范圍的大數(shù)字計(jì)算 target.Lsh(target, uint(256-Difficulty)) //Lsh 方法是左移操作,用于將 target 左移 256-Difficulty 位 return target.Bytes() }
如果我把區(qū)塊鏈比作 設(shè)置挖礦目標(biāo)和挖礦兩個(gè)部分,那么這個(gè)GetTarget函數(shù)實(shí)現(xiàn)的是那個(gè)部分?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-857307.html
顯然是設(shè)置難度文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-857307.html
5.所有數(shù)據(jù)連成字節(jié)
// 將區(qū)塊的時(shí)間戳(Timestamp)、前一個(gè)區(qū)塊的哈希值(PrevHash)、給定的 nonce、挖礦目標(biāo)值(Target)、以及區(qū)塊數(shù)據(jù)(Data)連接成字節(jié)返回 func (b *Block) GetBase4Nonce(nonce int64) []byte { //(b *Block) 是一個(gè)方法接收器(receiver),它定義了一個(gè)方法 GetBase4Nonce() 與 Block 結(jié)構(gòu)體相關(guān)聯(lián) //指針類(lèi)型接收器 意味著這個(gè)方法可以在 Block 類(lèi)型的實(shí)例上被調(diào)用,并且可以修改這個(gè)實(shí)例的狀態(tài) data := bytes.Join([][]byte{ ToHexInt(b.Timestamp), b.PrevHash, ToHexInt(int64(nonce)), b.Target, b.Data, }, //字節(jié)切片被放置在一個(gè)外部的切片 [][]byte{} 中,以便稍后使用 bytes.Join 函數(shù)將它們連接起來(lái),形成一個(gè)單獨(dú)的字節(jié)切片 []byte{}, ) return data }
6.nonce枚舉產(chǎn)生合法區(qū)塊
func (b *Block) FindNonce() int64 { var intHash big.Int //哈希值 //big.Int 是 Go 語(yǔ)言標(biāo)準(zhǔn)庫(kù) math/big 中的一個(gè)結(jié)構(gòu)體類(lèi)型,用于表示任意精度的整數(shù) var intTarget big.Int //要求挖礦大小target的值 var hash [32]byte var nonce int64 //nonce變量,試圖通過(guò)枚舉來(lái)實(shí)現(xiàn)區(qū)塊的創(chuàng)建PoW驗(yàn)證合法 nonce = 0 intTarget.SetBytes(b.Target) ? for nonce < math.MaxInt64 { // 將賦值語(yǔ)句放在函數(shù)體內(nèi)部 data := b.GetBase4Nonce(nonce) //調(diào)用函數(shù), 傳入nonce 返回一個(gè)包含所有數(shù)據(jù)的切片 hash = sha256.Sum256(data) ? ? ? ? //使用SHA-256 計(jì)算data切片的 哈希值 intHash.SetBytes(hash[:]) ? ? ? ? ?//將 hash 數(shù)組轉(zhuǎn)換為 big.Int 類(lèi)型,并賦值給 intHash,準(zhǔn)備與目標(biāo)值進(jìn)行比較 if intHash.Cmp(&intTarget) == -1 { //big.Int 類(lèi)型的方法 Cmp() 來(lái)比較兩個(gè)大整數(shù) intHash 和 intTarget 的大小 break } else { nonce++ } } return nonce } //這個(gè)函數(shù)在創(chuàng)建block節(jié)點(diǎn)中用到 ?
7.判斷節(jié)點(diǎn)是否合法
// 通過(guò)hash和target的比較 判斷節(jié)點(diǎn)是否合法 func (b *Block) ValidatePoW() bool { var intHash big.Int var intTarget big.Int var hash [32]byte intTarget.SetBytes(b.Target) //將字節(jié)數(shù)組 b.Target 的值設(shè)置給 intTarget 變量 data := b.GetBase4Nonce(b.Nonce) hash = sha256.Sum256(data) intHash.SetBytes(hash[:]) if intHash.Cmp(&intTarget) == -1 { return true } return false }
8.處理錯(cuò)誤
// 用于處理錯(cuò)誤的通用函數(shù) Handle(err error) 作用是在出現(xiàn)錯(cuò)誤時(shí),記錄錯(cuò)誤信息并終止程序的執(zhí)行 func Handle(err error) { if err != nil { log.Panic(err) } }
運(yùn)行結(jié)果
go run main.go ? ? Timestamp: 1711788684 hash: d21ec302d0aa322a933947b2020419e054627dbb0bf074d56deb42b862abedcb Previous hash: nonce: 14124 data: Hello, blockchain! Proof of Work validation: true Timestamp: 1711788685 hash: 6f3c44e96d073df10d86ec1f2c609795cffea2d23220e42cec19c8bceedeb96d Previous hash: d21ec302d0aa322a933947b2020419e054627dbb0bf074d56deb42b862abedcb nonce: 270 data: This is the second blockchain. Proof of Work validation: true Timestamp: 1711788686 hash: 84b859767f63568e9779ce3bee36d93b28a734b4611bca087b30040fdf158140 Previous hash: 6f3c44e96d073df10d86ec1f2c609795cffea2d23220e42cec19c8bceedeb96d nonce: 463 data: We added Pow in it Proof of Work validation: true Timestamp: 1711788687 hash: 5ac063f26d47122350219560d39c8fff1f0187206244c5e75e1f7ddc0f4d9104 Previous hash: 84b859767f63568e9779ce3bee36d93b28a734b4611bca087b30040fdf158140 nonce: 2248 data: We learn Hash in a new way,more deeply. Proof of Work validation: true Timestamp: 1711788688 hash: 33b8604d40d2ac8f097fcb4ed8a76ef72bd37ae2959cec623ba880d1d6489cd5 Previous hash: 5ac063f26d47122350219560d39c8fff1f0187206244c5e75e1f7ddc0f4d9104 nonce: 246 data: Waiting forward to the next Line! Proof of Work validation: true ?
到了這里,關(guān)于簡(jiǎn)易區(qū)塊鏈的搭建(2)——工作量證明的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!