go语言实现简易比特币系统(二):共识算法

1. 上一版本问题

  • 随机数和难度值随便填写的
  • 区块的哈希值是无规则的

2. 本版本新加内容

  • 添加POW共识算法

3. POW

3.1 POW简介

  • Proof Of Work(POW), 即工作量证明,为一种共识算法。是一种确保数字交易安全,而不依赖第三方的协议。

3.2 POW本质

  • 从本质上讲,工作量证明中的工作就是大家要共同解决的难题。要经过POW生成的数据是非常困难的、并且成本很高,但是一旦生产就很容易验证。

3.3 比特币中的POW

  • 比特币中POW的难题就是验证和确认区块,使区块内的交易得以实现。具体来讲,POW算法主要是寻找一个随机数,使得区块头的哈希值小于规定的目标值。
  • 下面是一个简单的验证区块的流程,以比特币的第二个区块为例。
    在这里插入图片描述
//1.计算哈希值

//计算区块头的哈希需要以下六个参数,然后不断的修改nonce值,
//    并对区块头进行sha256
version:	    000000001 --小端结尾--> 01000000
pre_hash(小端结尾后):6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000
merkle_root(小端结尾后): 982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e
timestamp:4966BC61--小端结尾-->61BC5549
bits:1D00FFFF ----> FFFF001D
nonce:9962E301 ----> 01E36299  //这个nonce值已经符合要求

header_hash=version+pre_hash+merkle_root+timestamp+bits+nonce

//对区块头进行两次sha256等运算并小端结尾得到:
header_hash=00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048

//2. 比较
//把计算得到的区块头哈希与目标值进行比较,
//    如果得到的哈希值比目标值小,那么代表就解出了这道数学题

//但是,我不会算目标值。计算目标值的公式为:目标值=系数*2^(8*(指数-3))次方
//还望路过的大佬指点指点


4. 实现POW

4.1 定义POW结构

type ProofOfWork struct {
    
    
	//a. 要挖矿的区块
	block *Block
	//b. 目标值
	target *big.Int
}

4.2 创建POW函数

func NewProofOfWork(block *Block) *ProofOfWork{
    
    
	pow := ProofOfWork{
    
    
		block:  block,
	}
	//目标值
	targetStr := "0000f00000000000000000000000000000000000000000000000000000000000"

	//引入辅助变量,将targetStr转换为big.int
	//因为字符串无法比较大小
	tmpInt := big.Int{
    
    }
	//把targetStr赋值给tmpInt, 格式为16进制
	tmpInt.SetString(targetStr, 16)

	pow.target = &tmpInt
	return &pow
}

4.3 挖矿方法

func (pow *ProofOfWork) Run () ([]byte, uint64) {
    
    
	//随机数
	var nonce uint64
	//要挖矿的区块
	block := pow.block
	var hash [32]byte
	
	//不断循环,增加nonce,得到比目标值小的数
	for{
    
    
		//拼装数据
		tmp := [][]byte{
    
    
			Uint64ToByte(block.Version),
			block.PrevHash,
			block.MerkelRoot,
			Uint64ToByte(block.TimeStamp),
			Uint64ToByte(block.Difficulty),
			Uint64ToByte(nonce),
			block.Data,
		}
		blockInfo := bytes.Join(tmp, []byte{
    
    })
		//做hash运算
		hash = sha256.Sum256(blockInfo)
		tmpInt := big.Int{
    
    }
		tmpInt.SetBytes(hash[:])
		
		//与目标值比较
		//Cmp比较返回值的含义
		//   -1 if x <  y
		//    0 if x == y
		//   +1 if x >  y
		if tmpInt.Cmp(pow.target) == -1{
    
    
			//找到了
			fmt.Printf("挖矿成功! hash: %x, nonce: %d\n", hash, nonce)
			return hash[:], nonce
		}else {
    
    
			//没到到 nonce加1
			nonce ++
		}

	}
}

4.4 设置nonce和区块哈希

//添加区块函数
func NewBlock (data string, prevBlockHash []byte) *Block{
    
    
	block := Block{
    
    
		Version:    00,
		PrevHash:   prevBlockHash,
		MerkelRoot: []byte{
    
    },
		TimeStamp:  uint64(time.Now().Unix()),
		Difficulty: 0,
		Nonce:      0,
		Hash:       []byte{
    
    },
		Data:       []byte(data),
	}

	//block.SetHash()
	//创建一个pow对象
	pow := NewProofOfWork(&block)
	hash, nonce := pow.Run()
	//根据挖矿结果对区块进行更新
	block.Hash= hash
	block.Nonce = nonce

	return &block
}

源码:https://gitee.com/xiaoshengdada/go_bitcoin/tree/master/v2

自此,POW算法添加完成,功能相对简单,后续会继续完善POW共识算法。下一篇博客,实现区块的持久化。

如果有任何问题可以来微信群交流,一起学习进步。
在这里插入图片描述最最后,推荐一位大佬的公众号:区块链技术栈

猜你喜欢

转载自blog.csdn.net/qq_31639829/article/details/115295812