ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

经典共识PoW的原理及实现

2021-10-02 00:00:59  阅读:206  来源: 互联网

标签:0000 target PoW 共识 proofOfWork 经典 hash 区块


经典共识PoW的原理及实现

一、PoW简介

PoW(Proof of Work)是工作量证明的简称,最早使用在防止拒绝服务攻击以及过滤垃圾邮件,现在成为区块链公链中最常见也是最有效的共识算法之一,当下最流行的比特币、以太坊等公链目前均使用PoW共识。

​ PoW是通过对一个复杂难题的求解,来保证区块链交易打包出块的公平性,即最先解决难题的矿工,可以获得记账权,并将打包好的区块发送至其他节点验证上链,从而获得激励。在保证能够在不可信的环境下创造可信的同时,运用PoW还可以天然的防御女巫攻击等针对区块链的攻击。

​ 由于PoW要求所有矿工节点都解决无意义的复杂难题,导致了巨大的资源浪费,因此,最新的以太坊版本考虑使用PoS代替PoW成为其共识算法。

二、PoW原理及实现

​ 在介绍PoW原理之前,需要先了解一些知识。

2.1 区块头

​ 在区块链中,区块分为区块头和区块体两部分,区块体以默克尔树的数据结构存储了交易数据,区块头存储了上一个区块的Hash、默克尔树树根值、时间戳、难度值、区块高度等等非交易数据信息。

2.2 哈希计算

​ 哈希计算实际上就是使用哈希函数(散列函数)对不同长度的数据都能计算出等长的输出,而且对数据微小差距都十分敏感,比如"hello world"和"Hello world"的哈希值差距都是巨大的。

2.3 原理及实现

​ PoW的原理十分简单,实际上就是计算一个随机数Nounce,要求这个Nounce和区块头拼接后做的哈希值小于我们预设的值。具体实现如下:

​ 1.预设一个难度值targetBit,比如我们想PoW计算出的Hash值最前面开始有16个0,则设置该值为16。

​ 2.找到判断是否找出正确Nounce值的临界值target,在比特币中,PoW使用的是SHA256,输出的哈希值都是256位的,比如设置的难度值是16,那么我们最终应该得到的值的形式应该是 0000 0000 0000 0000 xxxx…xxxx(共256位),那么我们可以得知,当我得到的值小于0000 0000 0000 0001 0000…0000(共256位)时,该值合法,因为这个值已经小于了前面有15个0的最小值,那么其前面一定有16个0。

​ 所以我们只要将临界值target先设置为1,二进制表示为0000 0000…0001(共256位),再将这个值左移256-targetBit = 256 - 16 = 240位,即可得到前面有15个0的最小值,即0000 0000 0000 0001 0000…0000(共256位)。

​ 3.将随机数Nounce置为0,再拼接上区块头的内容,计算其哈希值,如果大于了我们的目标值target,则将Nounce加1,再拼接区块头的内容计算哈希。重复上述过程,直到计算出小于target的哈希值,此时的Nounce就是最终的解。

三、PoW的go语言实现

1.首先定义工作量证明对象

type ProofOfWork struct {
   Block  *Block   //当前要验证的区块
   target *big.Int //大数存储
}

2.定义难度值

//256位hash里面至少有16个零
const targetBit = 16

3.初始化工作量证明对象,计算出临界值target

func NewProofOfWork(block *Block) *ProofOfWork {
   //创建一个初始值为1的target
   target := big.NewInt(1)
   //左移256-targetBit
   target = target.Lsh(target, 256-targetBit)
   return &ProofOfWork{
      block,
      target,
   }
}

4.拼接Nounce值和区块头中的内容

func (proofOfWork *ProofOfWork) prepareData(nonce int) []byte {
   join := bytes.Join(
      [][]byte{
         proofOfWork.Block.PreBlockHash,//前一个区块的hash
         proofOfWork.Block.HashTransactions(),//默克尔树根
         Utils.IntToHex(proofOfWork.Block.TimeStamp),//时间戳
         Utils.IntToHex(int64(targetBit)),//难度值
         Utils.IntToHex(int64(nonce)),//Nounce
         Utils.IntToHex(int64(proofOfWork.Block.Height)),//区块高度
      },
      []byte{},
   )
   return join
}

5.开始进行工作量证明计算

func (proofOfWork *ProofOfWork) Run() ([]byte, int64) {

   nonce := 0
   var hashInt big.Int //存储我们新生成的hash
   var hash [32]byte
   for {
      // 将BLOCK属性拼接成字节数组
      dataBytes := proofOfWork.prepareData(nonce)
      // 生成hash, sum256返回32位需要转换为64位
      hash = sha256.Sum256(dataBytes)
      // 将hash存储到hashInt,采取hash[:]将切片转换为64位
      hashInt.SetBytes(hash[:])
      fmt.Printf("\r%x", hash)
      // 判断hashInt是否小于Block里面的target
      // x < y -1
      // x == y 0
      // x > y 1
      if proofOfWork.target.Cmp(&hashInt) == 1 {
         //判断有效性,如果满足条件,跳出循环
         break
      }
      nonce = nonce + 1
   }
   return hash[:], int64(nonce)
}

6.编写当需要验证Nounce值是否合法时的验证函数

func (proofOfWork *ProofOfWork) IsValid() bool {
	var hashInt big.Int
	hashInt.SetBytes(proofOfWork.Block.Hash)
  //判断提供的hash是否小于target
	if proofOfWork.target.Cmp(&hashInt) == 1 {
		return true
	}
	return false
}

标签:0000,target,PoW,共识,proofOfWork,经典,hash,区块
来源: https://blog.csdn.net/weixin_42195126/article/details/120582124

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有