剛接觸區(qū)塊鏈岭接,百度了下冕末,發(fā)現(xiàn)有人用Golang
編寫了一些區(qū)塊鏈的鏈構(gòu)建過程和工作量證明的代碼姆另,發(fā)現(xiàn)工作量證明的代碼跑不通喇肋,我將這些代碼整理了下,將報(bào)錯(cuò)的地方調(diào)試修復(fù)了下迹辐,這里給出修復(fù)后能夠跑通的代碼蝶防。
代碼如下:
package main
import (
"crypto/sha256"
"fmt"
"math/big"
"time"
"bytes"
"math"
"strconv"
)
const targetBits = 24
const maxNonce int = math.MaxInt64
type Blockchain struct {
blocks []*Block
}
type Block struct {
Timestamp int64
Data []byte
PrevBlockHash []byte
Hash []byte
Nonce int
}
type ProofOfWork struct {
block *Block
target *big.Int
}
func NewBlockchain() *Blockchain {
return &Blockchain{[]*Block{NewGenesisBlock()}}
}
func NewGenesisBlock() *Block {
return NewBlock("Genesis Block", []byte{})
}
func NewBlock(data string, prevBlockHash []byte) *Block {
block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}, 0}
pow := NewProofOfWork(block)
nonce, hash := pow.Run()
block.Hash = hash[:]
block.Nonce = nonce
return block
}
func NewProofOfWork(b *Block) *ProofOfWork {
target := big.NewInt(1)
target.Lsh(target, uint(256-targetBits))
pow := &ProofOfWork{b, target}
return pow
}
func (pow *ProofOfWork) prepareData(nonce int) []byte {
data := bytes.Join(
[][]byte{
pow.block.PrevBlockHash,
pow.block.Data,
[]byte(strconv.FormatInt(pow.block.Timestamp,10)),
[]byte(strconv.FormatInt(int64(targetBits),10)),
[]byte(strconv.FormatInt(int64(nonce),10)),
},
[]byte{},
)
return data
}
func (pow *ProofOfWork) Validate() bool {
var hashInt big.Int
data := pow.prepareData(pow.block.Nonce)
hash := sha256.Sum256(data)
hashInt.SetBytes(hash[:])
isValid := hashInt.Cmp(pow.target) == -1
return isValid
}
func (pow *ProofOfWork) Run() (int, []byte) {
var hashInt big.Int
var hash [32]byte
nonce := 0
fmt.Printf("Mining the block containing \"%s\"\n", pow.block.Data)
for nonce < maxNonce {
data := pow.prepareData(nonce)
hash = sha256.Sum256(data)
hashInt.SetBytes(hash[:])
if hashInt.Cmp(pow.target) == -1 {
fmt.Printf("\r%x", hash)
break
} else {
nonce++
}
}
fmt.Print("\n\n")
return nonce, hash[:]
}
func (bc *Blockchain) AddBlock(data string) {
prevBlock := bc.blocks[len(bc.blocks)-1]
newBlock := NewBlock(data, prevBlock.Hash)
bc.blocks = append(bc.blocks, newBlock)
}
func main() {
bc := NewBlockchain()
bc.AddBlock("Send 1 BTC to Ivan")
bc.AddBlock("Send 2 more BTC to Ivan")
for _, block := range bc.blocks {
fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash)
fmt.Printf("Data: %s\n", block.Data)
fmt.Printf("Hash: %x\n", block.Hash)
pow := NewProofOfWork(block)
fmt.Printf("PoW: %s\n", strconv.FormatBool(pow.Validate()))
fmt.Println()
}
}
編譯:go build -o demo
,執(zhí)行:./demo
明吩,大概幾分鐘之后輸出結(jié)果(如果不驗(yàn)證節(jié)點(diǎn)的正確性间学,那么結(jié)果的輸出更快):
Mining the block containing "Genesis Block"
0000002116784eb8746d411854031889a4a38695605336a68cebeb93aae7a315
Mining the block containing "Send 1 BTC to Ivan"
00000053b1627863dd41cbd507870c2f76e7300623ce655ae19d18fe30890341
Mining the block containing "Send 2 more BTC to Ivan"
000000a9b3b1ca2760cdc1348fca8c94042a067e2b001f8ff3c9b95f87ce334d
Prev. hash:
Data: Genesis Block
Hash: 0000002116784eb8746d411854031889a4a38695605336a68cebeb93aae7a315
PoW: true
Prev. hash: 0000002116784eb8746d411854031889a4a38695605336a68cebeb93aae7a315
Data: Send 1 BTC to Ivan
Hash: 00000053b1627863dd41cbd507870c2f76e7300623ce655ae19d18fe30890341
PoW: true
Prev. hash: 00000053b1627863dd41cbd507870c2f76e7300623ce655ae19d18fe30890341
Data: Send 2 more BTC to Ivan
Hash: 000000a9b3b1ca2760cdc1348fca8c94042a067e2b001f8ff3c9b95f87ce334d
PoW: true
(備注:源代碼的作者不是本人) 讓我們一起學(xué)習(xí)區(qū)塊鏈知識(shí),共同進(jìn)步印荔,end ~