区块链之共识算法系列——PoW(二)

260 阅读2分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」。

区块链之共识算法系列——PoW(二)

本文收录于我的专栏:细讲区块链

本专栏会讲述区块链共识算法以及以太坊智能合约、超级账本智能合约、EOS智能合约相关知识,还会详细的介绍几个实战项目。如果有可能的话,我们还能一起来阅读以太坊的源码。有兴趣的话我们一起来学习区块链技术吧~

接上一篇区块链之共识算法系列——PoW(一)哦,上一篇我们介绍了什么是P2P、介绍了一下PoW算法是什么,然后说明了区块的结构,并生成了一个创世区块,哦对了,生成哈希值的模块还没有搭建好。我先来搭建这个生成哈希值的模块。

一、生成哈希值

func GneHashValue(block Block) string {
   var hashdata = strconv.Itoa(block.Index) + strconv.Itoa(block.Nonce) + strconv.Itoa(block.Diff) +
      block.TimeStamp + block.PreHash
​
   var sha = sha256.New()
   sha.Write([]byte(hashdata))
   hashed := sha.Sum(nil)
   return hex.EncodeToString(hashed)
}

我们这个区块链是仿的比特币的区块,所以我们要将所有数据拼接在一起然后再求哈希值。这里我们使用的是sha256加密算法。这里先使用sha256.New,这个方法会返回一个hash.Hash。这个Hash实现了encoding.BinaryMarshaler和encoding.BinaryUnmarshaler,可以对哈希的内部状态进行编组和解组。然后使用Write将数据写入底层数据流,它会返回写入的字节数或者错误,这里我们不需要它的返回值。Sum方法我们这的参数是nil,这就说明我们要将当前的哈希值追加到nil,并返回生成的一个slice,这个方法不会改变哈希值的底层状态。EncodeToString返回hashed的十六进制编码。

二、看一看创世区块

我们来看一看创世区块。

func main() {
    var firstBlock = GneFirBlock("Regan Yue")
    fmt.Println(firstBlock)
    fmt.Println(firstBlock.Data)
}
{ e42d311dd9ba42d8f1907ba60a7c1112c1720ccbdad938aaad91b4990089ece8 2021-11-06 21:34:32.3711993 +0800 CST m=+0.023002101 3 Regan Yue 1 0}
Regan Yue
​

我们可以看到,创世区块的数据就保存好了,然后我们来写生成新的区块。

三、生成新区块

func GneNewBlock(data string, oldBlock Block) Block {
    var newBlock Block
    newBlock.TimeStamp = time.Now().String()
    newBlock.Diff = 3
    newBlock.Index = 2
    newBlock.Data = data
    newBlock.PreHash = oldBlock.HashCode
    newBlock.Nonce = 0
    newBlock.HashCode = pow(newBlock.Diff, &newBlock)
​
    return newBlock
}
​

接下来我们要生成一个新的区块,这里区块高度要为2,新区块的PreHash要为前一个区块的哈希值,然后我们计算这个区块的哈希值,这里我们模仿比特币,算前导0的个数。

func pow(diff int, block *Block) string {
    for {
        hashValue := GneHashValue(*block)
        fmt.Println(hashValue)
        if strings.HasPrefix(hashValue, strings.Repeat("0", diff)) {
            //成功
            fmt.Println("success")
            return hashValue
        } else {
            block.Nonce++
        }
​
    }
}

如果生成的哈希值前导0的个数等于难度值就返回哈希值,否则Nonce值变化。