go语言模拟区块链step2

工作量证明机制和工作量验证机制

在这一步加入工作量证明机制和工作量验证机制
在这里插入图片描述

实现工作量证明
定义实现工作量证明的结构
//实现挖矿功能 pow

// 字段:
// 	区块:block
// 	目标值:target
// 方法:
// 	run计算
// 	功能:找到nonce,从而满足哈希币目标值小

type ProofOfWork struct {
	// 区块:block
	block *Block
	// 目标值:target,这个目标值要与生成哈希值比较
	target *big.Int //结构,提供了方法:比较,把哈希值设置为big.Int类型
}

定义对应的初始化函数

//创建ProofOfWork
//block由用户提供
//target目标值由系统提供
func NewProofOfWork(block *Block) *ProofOfWork {
	pow := ProofOfWork{
		block: block,
	}

	//难度值先写死,不去推导,后面补充推导方式
	targetStr := "0000100000000000000000000000000000000000000000000000000000000000"
	tmpBigInt := new(big.Int)
	//将我们的难度值赋值给bigint,是16进制,4位可以确定一个16进制数,所以我们需要64个16进制数,这样正好256位
	tmpBigInt.SetString(targetStr, 16)

	pow.target = tmpBigInt
	return &pow
}

因为要进行hash运算,定义一个准备数据的方法

//拼接nonce和block数据
func (pow *ProofOfWork) PrepareData(nonce uint64) []byte {
	b := pow.block

	tmp := [][]byte{
		uintToByte(b.Version), //将uint64转换为[]byte
		b.PrevHash,
		b.MerkleRoot,
		uintToByte(b.TimeStamp),
		uintToByte(b.Bits),
		uintToByte(nonce),
    	//uintToByte(b.Nonce),  <<<<=====不要忘记修改,否则nonce不会产生作用
		//b.Hash,	<<<<=====不要忘记区块本身的hash不应该参与hash运算,否则此时hash为nil,之后不为nil,验证时肯定会不同
		b.Data,
	}
	//使用join方法,将二维切片转为1维切片
	data := bytes.Join(tmp, []byte{})
	return data
}
定义Run方法

开始挖矿吧

//挖矿函数,不断变化nonce,使得sha256(数据+nonce) < 难度值
//返回:区块哈希,nonce
func (pow *ProofOfWork) Run() ([]byte, uint64) {
	//定义随机数
	var nonce uint64
	var hash [32]byte
	//这里定义长度为32的数组,是因为,一个字节是8位,32字节正好是256位
	for {
		// 1. 拼接字符串 + nonce
		data := pow.PrepareData(nonce)
		// 2. 哈希值 = sha256(data)
		hash = sha256.Sum256(data)//[32]byte

		//将hash转换为bigInt类型
		tmpInt := new(big.Int)
		tmpInt.SetBytes(hash[:])

		//   -1 if x <  y
		//    0 if x == y
		//   +1 if x >  y
		//当前计算的哈希.Cmp(难度值)
		if tmpInt.Cmp(pow.target) == -1 {
			fmt.Printf("挖矿成功,hash :%x, nonce :%d\n", hash[:], nonce)
			break
		} else {
			//如果不小于难度值
			nonce++
		}
  } //for, 如果嵌套层级过多,可以使用在闭合}位置写上嵌套的类型

	// 	return 哈希,nonce
	return hash[:], nonce
}
验证区块
  1. 获取区块
  2. 拼装数据(block + nonce)
  3. 计算sha256
  4. 与难度值比较
定义一个验证区块的方法
func (pow *ProofOfWork) IsValid() bool {
	// 	1. 获取区块
	// 2. 拼装数据(block + nonce)
	data := pow.PrepareData(pow.block.Nonce)
	// 3. 计算sha256
	hash := sha256.Sum256(data)
	// 4. 与难度值比较
	tmpInt := new(big.Int)
	tmpInt.SetBytes(hash[:])

	// if tmpInt.Cmp(pow.target) == -1 {
	// 	return true
	// }
	// return false

	//满足条件,返回true
	return tmpInt.Cmp(pow.target) == -1
}

可以看出来,虽然在生成哈希值的时候是很麻烦的,但是在验证的时候却非常方便,只需一次运算。

集成到整体结构

此时在创建新区块的时候应该加上工作量证明机制

func NewBlock(data string, prevHash []byte) *Block {
	b := Block{
		...
	}

	//计算哈希值
	// b.setHash()

	//将POW集成到Block中
	pow := NewProofOfWork(&b)
	hash, nonce := pow.Run()
	b.Hash = hash
	b.Nonce = nonce

	return &b
}

在遍历区块链上的区块数据时,加上验证的步骤

func main() {
	bc := NewBlockChain()
	...
	for i, block := range bc.Blocks {
		...
        //验证区块
		pow := NewProofOfWork(block)
		fmt.Printf("IsValid: %v\n", pow.IsValid())
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值