区块链开发(二)

实际的区块链在出块上要复杂的多,例如比特币采用的工作量证明POW机制。其采用了基于现金哈希的哈希算法,把前一个块的时间戳、nonce、自己要输入的DATA数据等合起来计算其HASH,达到设定的条件(前若干位是0,现金哈希原生要求是20,前一段时间比特币的要求是18,后续会逐渐增多)则成功,否则变更nonce的值重新计算。以下以POW为例设计代码。


package main

    import (
        "fmt"
        "time"
        "crypto/sha256"
        "bytes"
        "math/big"
        "math"
        "strconv"
    )

    const targetBits = 24
    const maxNonce int = math.MaxInt64

    type Block struct {
        Timestamp     int64
        Data          []byte
        PrevBlockHash []byte
        Hash          []byte
        Nonce         int
    }

    type Blockchain struct {
        blocks []*Block
    }

    type ProofOfWork struct {
        block  *Block
        target *big.Int
    }

    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,
                //IntToHex(pow.block.Timestamp),
                //IntToHex(int64(targetBits)),
                //IntToHex(int64(nonce)),
                []byte(strconv.FormatInt((pow.block.Timestamp),16)),
                []byte(strconv.FormatInt((int64(targetBits)),16)),
                []byte(strconv.FormatInt((int64(nonce)),16)),
            },
            []byte{},
        )

        return data
    }


    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 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 NewGenesisBlock() *Block {
        return NewBlock("Genesis Block", []byte{})
    }

    func NewBlockchain() *Blockchain {
        return &Blockchain{[]*Block{NewGenesisBlock()}}
    }

    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 (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 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("Timestamp: %x\n", block.Timestamp)
            fmt.Printf("Hash: %x\n", block.Hash)

            pow := NewProofOfWork(block)
            fmt.Printf("PoW: %s\n", strconv.FormatBool(pow.Validate()))
            fmt.Println()
        }
    }
   


执行go run pow.go可以看到结果

Mining the block containing "Genesis Block"
00000058fb085e863d52480356a2a3f0672e3f05b71f1636eb4787ef6f136942

Mining the block containing "Send 1 BTC to Ivan"
000000ca03afb7aab594372670c5b0daf5c92092d11884a0d934590ac00bf18f

Mining the block containing "Send 2 more BTC to Ivan"
000000622e11eb48cb7ea0b9c76fceadeec0733bfb820915fedef6ba7c19fe94

Prev. hash: 
Data: Genesis Block
Timestamp: 5a658fd4
Hash: 00000058fb085e863d52480356a2a3f0672e3f05b71f1636eb4787ef6f136942
PoW: true

Prev. hash: 00000058fb085e863d52480356a2a3f0672e3f05b71f1636eb4787ef6f136942
Data: Send 1 BTC to Ivan
Timestamp: 5a658fd8
Hash: 000000ca03afb7aab594372670c5b0daf5c92092d11884a0d934590ac00bf18f
PoW: true

Prev. hash: 000000ca03afb7aab594372670c5b0daf5c92092d11884a0d934590ac00bf18f
Data: Send 2 more BTC to Ivan
Timestamp: 5a658fed
Hash: 000000622e11eb48cb7ea0b9c76fceadeec0733bfb820915fedef6ba7c19fe94
PoW: true

在这个进阶的代码中,新增了一个结构ProofOfWork,在上一节使用setHash方法哈希后就直接出块了,在这里则通过ProofOfWork来通过算法的运算增加出块的难度(也就是共识机制,其本质是通过消耗系统外的熵来减少系统本身的熵);

ProofOfWork这个数据结构有三个方法NewProofOfWork、prepareData、Run,其中Run方法就是实现了挖矿的逻辑(在比特币中消耗现实中的电量等要素转化为比特币系统的熵减)。NewProofOfWork方法中先根据预先设定的targetBits计算出一个目标哈希值,prepareData准备每一轮要给哈希提供的弹药数据,最后run哈希prepareData的数据后与NewProofOfWork中的进行比较,小于则成功大于则nonce改变下一轮计算。

最后的Validate方法对整个业务做了一次校验。

转载于:https://my.oschina.net/u/568367/blog/1611261

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值