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

举报
Regan Yue 发表于 2021/11/07 09:45:36 2021/11/07
【摘要】 区块链之共识算法系列——PoW本专栏会讲述区块链共识算法以及以太坊智能合约、超级账本智能合约、EOS智能合约相关知识,还会详细的介绍几个实战项目。如果有可能的话,我们还能一起来阅读以太坊的源码。有兴趣的话我们一起来学习区块链技术吧~一、前言说到区块链我们先要了解什么是P2P,这个P2P不是金融方面的名词,而是指对等网络。在中本聪的白皮书中提出了像微信支付、支付宝这样的需要经过第三方的点对点支...

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

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

一、前言

说到区块链我们先要了解什么是P2P,这个P2P不是金融方面的名词,而是指对等网络。在中本聪的白皮书中提出了像微信支付、支付宝这样的需要经过第三方的点对点支付系统是没有任何意义的。

而我们的P2P,就是这样一个不需要经过第三方的概念,其之所以会出现的一个重要原因就是避免有第三方和中心。

在P2P对等网络中所有的节点功能都是一样的,没有哪一个节点是特殊的,他们之间互相提供服务。

因为没有第三方,没有中心,所以保证了数据的透明、自由、平等。

我们常听说的比特币就是使用PoW共识算法的。PoW是Proof-of-Work的简称,即工作量证明。就是计算一个数值,使得和数据合并后的值满足要求后,就马上广播全网打包区块,全网的节点收到广播之后,就会验证其正确性。如果节点有作弊行为,那么就不会通过验证,这个打包的区块会被丢弃,无法记录到账本,挖矿成本这么高,如果作弊导致区块被丢弃,比特币也拿不到了,岂不是还得亏本。所以矿工都愿意遵守比特币系统的共识协议。

二、生成创世区块

我们先定义区块的结构体:

type Block struct {
    //上一个区块的哈希值
    PreHash string
    //当前区块的哈希值
    HashCode string
    //时间戳
    TimeStamp string
    //难度系数
    Diff int
    //交易信息
    Data string
    //区块高度
    Index int
    //随机值
    Nonce int
}

根据比特币,我们将这个区块的信息设置为以下几点:上一个区块的哈希值、当前区块的哈希值、时间戳、难度系数、交易信息、区块高度、随机值。

然后我们来建立一个创世区块。

//创世区块
func GneFirBlock(data string) Block {
    //创建第一个区块
    var firstblock Block
    firstblock.PreHash = ""
    firstblock.TimeStamp = time.Now().String()
    firstblock.Diff = 3
    firstblock.Index = 1
    firstblock.Nonce = 0
    //通过sha256计算哈希值
    firstblock.HashCode =GneHashValue(firstblock)
    return firstblock
}

因为是第一个区块,所以前一个区块是为空,时间戳我们使用现在的时间,难度我们暂时设置为3,因为是第一个区块,所以区块高度为1,随机值可以随便搞一个,我们就用0吧。然后我们得计算当前区块的hash值,我们要使用sha256来计算。

三、生成哈希值

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值变化。

image-20211106215025924

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。