共识算法1--工作量证明机制简介及算法实现

共识算法1--工作量证明机制简介及算法实现

所谓“共识机制”,是通过特殊节点的投票,在很短的时间内完成对交易的验证和确认;对一笔交易,如果利益不相干的若干个节点能够达成共识,我们就可以认为全网对此也能够达成共识。[1] 当前,已有多种常见的共识机制,常见的包括PoW、PoS、DPoS、Paxos、PBFT、Raft等,其中PoW是BTC中的共识算法。笔者此处简要介绍一下PoW算法的原理和一个基于PoW算法的简单挖矿算法。

1、工作量证明机制介绍

工作量证明(Proof of Work, 以下简称PoW) 机制随着比特币的流行而广为人知。 PoW协议简述如下:[2]
1) 向所有的节点广播新的交易;
2) 每个节点把收到的交易放进块中;
3) 在每一轮中, 一个被随机选中的节点广播它所保有的块;
4) 其他节点在验证块中的所有的交易正确无误后接受该区块;
5) 其他节点将该区块的哈希值放入下一个它们创建的区块中,表示它们承认这个区块的正确性。

PoW共识协议的优点是完全去中心化, 节点自由进出。 但是依赖机器进行数学运算来获取记账权, 资源的消耗相比其他共识机制高, 可监管性弱, 同时每次达成共识需要全网共同参与运算, 性能效率比较低,容错性方面允许全网50%节点出错。

比特币网络中任何一个节点,如果想生成一个新的区块并写入区块链,必须解出比特币网络出的工作量证明的迷题。这道题关键的三个要素是工作量证明函数、区块及难度值。工作量证明函数是这道题的计算方法,区块决定了这道题的输入数据,难度值决定了这道题的所需要的计算量。

2、PoW算法实现

简单来说,用户通过前一个区块信息,使用哈希算法不停计算hash值,当hash值前面出现和难度系数值相同数量的0即为挖矿成功,挖矿成功后即可获得一定数量的奖励。

PoW算法单机版本源码:

package main

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"strconv"
	"strings"
	"time"
)

//在区块链 中应用PoW挖矿算法
//定义难度系数,此处设置为4,实际BTC中难度系数在逐渐增加
const difficulty = 4

//创建节点类型
type Block struct {
	Index      int    //区块高度,创世块为0,后面一次加1
	Timestamp  string //时间戳
	Data       int    //交易数据,实际应该为默尔棵树
	Hash       string //当前hash
	Prehash    string //上一个节点hash值
	Nonce      int    //随机值
	Difficulty int    //难度系数值
}

//创建区块链,可以用数组或者链表,btc和eth都是用数据实现的
var Blockchain []Block

//生成新区块,PoW挖矿
func generateNextBlock(oldBlock Block, data int) Block {
	var newBlock Block
	newBlock.Index = oldBlock.Index + 1
	newBlock.Data = data
	newBlock.Difficulty = difficulty
	newBlock.Prehash = oldBlock.Hash
	newBlock.Nonce = 0
	//挖矿
	for {
		//使得当前区块hash前0的系数和难度系数值相同
		newBlock.Timestamp = time.Now().String()
		newBlockHash := hex.EncodeToString(calculateHash(&newBlock))
		fmt.Println("挖矿中...", newBlockHash)
		//判断挖矿结束
		if isBlockValid(newBlockHash, difficulty) {
			fmt.Println("挖矿成功!", newBlockHash)
			newBlock.Hash = newBlockHash
			//需要将newBlock校验,然后将挖出的区块添加到区块链
			if newBlockVerify(newBlock, oldBlock) {
				//可以添加到数组中
				Blockchain = append(Blockchain, newBlock)
				return newBlock
			}
		}
		newBlock.Nonce++
	}
}

//判断挖矿结束
func isBlockValid(hash string, diff int) bool {
	hashPrefix := strings.Repeat("0", diff)
	return strings.HasPrefix(hash, hashPrefix)
}

//计算hash值
func calculateHash(block *Block) []byte {
	//利用当前区块数据,计算完成hash散列
	record := strconv.Itoa(block.Nonce) + strconv.Itoa(block.Difficulty) +
		strconv.Itoa(block.Data) + strconv.Itoa(block.Index) + block.Prehash +
		block.Timestamp
	//通过sha256实现hash散列
	h := sha256.New()
	h.Write([]byte(record))
	hashed := h.Sum(nil)
	return hashed
}

//校验新区块是否合法
func newBlockVerify(newBlock Block, oldBlock Block) bool {
	if oldBlock.Index+1 != newBlock.Index {
		return false
	}
	if newBlock.Prehash != oldBlock.Hash {
		return false
	}
	//btc中还有一个校验数据
	return true
}

//创建创世区块
func genesisBlock() Block {
	var genesisBlock = Block{Index: 0, Timestamp: time.Now().String(), Data: 0, Hash: "",
		Prehash: "0", Nonce: 0, Difficulty: difficulty}
	//计算创世区块的hash
	calculateHash(&genesisBlock)
	//将创世区块放在数组中
	Blockchain = append(Blockchain, genesisBlock)
	return genesisBlock
}

func main() {
	var genesisBlock = genesisBlock()
	generateNextBlock(genesisBlock, 1)

	var newBlock = Blockchain[1]
	fmt.Println("挖出的新区块为:", newBlock)
	fmt.Println("挖出的新区块Data为:", newBlock.Data)
	fmt.Println("挖出的新区块Hash为:", newBlock.Hash)
	fmt.Println("挖出的新区块nonce为:", newBlock.Nonce)
}

运行结果:

挖矿中... a5c1a05dff94191446d52682a2b1517115b19f8fa6b11a980f4e18b00fc7fe86
挖矿中... 0000ecea458dc96a4ffed5b75a1e207555166765f5dcb8fc3e647f98027c5bab
挖矿成功! 0000ecea458dc96a4ffed5b75a1e207555166765f5dcb8fc3e647f98027c5bab
挖出的新区块为: {1 2018-12-26 16:54:47.4450533 +0800 CST m=+0.061832601 1 0000ecea458dc96a4ffed5b75a1e207555166765f5dcb8fc3e647f98027c5bab  12841 4}
挖出的新区块Data为: 1
挖出的新区块Hash为: 0000ecea458dc96a4ffed5b75a1e207555166765f5dcb8fc3e647f98027c5bab
挖出的新区块nonce为: 12841
Success: process exited with code 0.

3、说明

本代码当前测试环境为golang1.9.2。

参考文献:

[1] 共识机制概述:https://www.chaindesk.cn/witbook/18/284

[2] 白话区块链

[3] 区块链共识算法-POW:https://www.jianshu.com/p/b23cbafbbad2

猜你喜欢

转载自blog.csdn.net/u011127242/article/details/85263998