区块链Demo

刚接触区块链,百度了下,发现有人用Golang编写了一些区块链的链构建过程和工作量证明的代码,发现工作量证明的代码跑不通,我将这些代码整理了下,将报错的地方调试修复了下,这里给出修复后能够跑通的代码。
代码如下:

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,执行:./demo,大概几分钟之后输出结果(如果不验证节点的正确性,那么结果的输出更快):

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

(备注:源代码的作者不是本人) 让我们一起学习区块链知识,共同进步,end ~

你可能感兴趣的:(区块链Demo)