共识算法3--委托权益证明机制简介及算法实现

共识算法3--委托权益证明机制简介及算法实现

 

在区块链中使用PoS会导致贫富差距增加的问题,为解决该问题,提出了DPoS机制,DPoS已经在EOS中得到了应用。实际区块链产品中,由x个投票主节点和y个候选节点实现共识,x个投票主节点负责共识和挖矿,当系统发现x中的某个节点有问题(如恶意破坏)则使用y中的候选节点替代x中的节点,从而继续保证系统正常运行。笔者此处简要介绍一下DPoS算法的原理和一个基于DPoS算法的简单挖矿算法。

 

1、委托权益证明介绍

委托权益证明机制( Delegated Proof of Stake, 以下简称DPoS)机制是PoS算法的改进。DPoS算法中使用见证人机制(witness)解决中心化问题。总共有N个见证人对区块进行签名。DPoS消除了交易需要等待一定数量区块被非信任节点验证的时间消耗。通过减少确认的要求,DPoS算法大大提高了交易的速度。通过信任少量的诚信节点,可以去除区块签名过程中不必要的步骤。DPoS的区块可以比PoW或者PoS容纳更多的交易数量,从而使加密数字货币的交易速度接近像Visa和Mastercard这样的中心化清算系统。[1]

DPoS使得区块链网络保留了一些中心化系统的关键优势, 同时又能保证一定的去中心化。 见证人机制使得交易只用等待少量诚信节点(见证人)的响应,而不必等待其他非信任节点的响应。其具有如下优缺点--优点:能耗更低;更加去中心化;更快的确认速度;缺点:投票的积极性不高;对坏节点的处理存在诸多困难。

DPoS的具体权益委托和选举过程可以通过EOS来体现,EOS系统中通过投票选举21个超级节点(超级节点前期一般会采用各种方式来拉票),然后由这21个节点负责系统的出块和共识。
具体的选举和出块,可以通过如下来理解:一般选举过程是这样的,首先设立一个评审委员会,全球所有节点都可以报名参加,报名的前提是交纳保证金,通过审核的最为满足条件的前N个节点将作为候选节点,进入下一轮,也就是竞选阶段。这些候选节点会将会各种演说游说其他的持币人,让他们给自己投票,这里可能场外会给投票人某些好处。最终投票总数前m名的候选节点成为公链的代理人,负责出块。每次出块时,系统会随机顺序挑选指定某个代理人出块。每次选举出来的代理人都有任期,任期期间如果被监管发现某些作恶行为将会被追责和卸任。[2]

 

 

2、DPoS算法实现

DPoS编程思路大致如下:
1)确认挖矿节点:先生成x个节点(此处暂且设置5个节点),然后通过排序或者某种方式选出y个委托的投票主节点(以下通过选举者的投票数选出3个节点挖矿);
2)生成创世区块
3)被委托的节点轮流挖矿

DPoS单机版本源码:

// c5_DPoS.go
package main

//本代码主要实现DPoS基本原理
import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

//选举结构体
type Node struct {
	Name  string //节点名称
	Votes int    //被选举的票数
}

//创建数组保存节点
var n = make([]*Node, 5)

//创建节点
func createNodes() {
	//创建随机种子
	rand.Seed(time.Now().Unix())
	node1 := Node{"node1", rand.Intn(10)}
	node2 := Node{"node2", rand.Intn(10)}
	node3 := Node{"node3", rand.Intn(10)}
	node4 := Node{"node4", rand.Intn(10)}
	node5 := Node{"node5", rand.Intn(10)}
	n[0] = &node1
	n[1] = &node2
	n[2] = &node3
	n[3] = &node4
	n[4] = &node5
}

//DPoS 中选出票数最高的前n位用户(EoS中21位)
func sortNodes() []*Node {
	//对所有选民的票数进行排序,此处选出前3个作为委托节点,实际中可以根据需要确定
	for i := 0; i < 4; i++ {
		for j := 0; j < 4-i; j++ {
			if n[j].Votes < n[j+1].Votes {
				tmp := n[j]
				n[j] = n[j+1]
				n[j+1] = tmp
			}
		}
	}
	return n[:3]
}

//定义区块结构体
type Block struct {
	Index     int
	Timestamp string
	Prehash   string
	Hash      string
	Data      int
	//增加代理
	delegate *Node //用于记录由谁挖出区块
}

var Blockchain []*Block //存放产生的区块
//产生区块
func generateNextBlock(oldBlock Block, data int) *Block {
	var newBlock = Block{oldBlock.Index + 1, time.Now().String(),
		oldBlock.Hash, "", data, &Node{"", 0}}
	calculateHash(&newBlock)
	Blockchain = append(Blockchain, &newBlock)
	return &newBlock
}

//计算区块hash
func calculateHash(block *Block) {
	record := strconv.Itoa(block.Index) + strconv.Itoa(block.Data) + block.Timestamp + block.Prehash
	h := sha256.New()
	h.Write([]byte(record))
	hashed := h.Sum(nil)
	block.Hash = hex.EncodeToString(hashed)
}

//设置代理人
func (block *Block) setDelegate(node *Node) {
	block.delegate = node
}

//生成创世区块
func genesisBlock() *Block {
	genesis := Block{0, time.Now().String(), "", "", 0, &Node{"", 0}}
	calculateHash(&genesis)
	Blockchain = append(Blockchain, &genesis)
	return &genesis
}
func main() {
	fmt.Println("Hello DPoS!")
	//创建所有选民
	createNodes()
	//确定选出的节点,然后所有挖矿均由这三个节点完成
	c := sortNodes()
	/*
		for _, v := range c {
			fmt.Println(v.Votes)
		}
	*/
	//fmt.Println(c[0])
	//创建区块
	genesisBlock := genesisBlock()
	genesisBlock.setDelegate(c[0]) //设置c[0]为创世块矿工
	fmt.Println(*genesisBlock)     //genesisBlock.delegate.Name

	//指定人员轮流挖矿,此处3个节点依次挖矿一次,可根据需要通过for循环持续挖矿
	newBlock := generateNextBlock(*genesisBlock, 0)
	newBlock.setDelegate(c[0]) //设置c[0]位当前矿工
	fmt.Println(*newBlock)

	newBlock = generateNextBlock(*newBlock, 1)
	newBlock.setDelegate(c[1]) //设置c[1]位当前矿工
	fmt.Println(*newBlock)

	newBlock = generateNextBlock(*newBlock, 2)
	newBlock.setDelegate(c[2]) //设置c[2]位当前矿工
	fmt.Println(*newBlock)

	//遍历区块数据
	for _, blockInfo := range Blockchain {
		fmt.Println("\n委托挖矿用户:", blockInfo.delegate.Name)
		fmt.Println("区块Hash值:", blockInfo.Hash)
		fmt.Println("区块数据:", blockInfo.Data)
	}
}

运行结果:

Hello DPoS!
{0 2019-01-06 19:48:08.0980002 +0800 CST m=+0.004000001  81e2657598ab5d785ad5e37ce28bdbeedde993a72959d194d569e9a781371500 0 0xc0000044a0}
{1 2019-01-06 19:48:08.1290002 +0800 CST m=+0.035000001 81e2657598ab5d785ad5e37ce28bdbeedde993a72959d194d569e9a781371500 745e932be093669729f66a3e815421db8b3a76cd3c270bf2a69e19a8d9b8e897 0 0xc0000044a0}
{2 2019-01-06 19:48:08.1290002 +0800 CST m=+0.035000001 745e932be093669729f66a3e815421db8b3a76cd3c270bf2a69e19a8d9b8e897 1b60389ee80bb5825e88018e9fed7836e549e82f09a914798db38e13d1402f32 1 0xc0000044c0}
{3 2019-01-06 19:48:08.1290002 +0800 CST m=+0.035000001 1b60389ee80bb5825e88018e9fed7836e549e82f09a914798db38e13d1402f32 8f0b799c377dfc0260859e993581b022591017a1f2507f70c05f5b3bc77cf3ea 2 0xc000004500}

委托挖矿用户: node1
区块Hash值: 81e2657598ab5d785ad5e37ce28bdbeedde993a72959d194d569e9a781371500
区块数据: 0

委托挖矿用户: node1
区块Hash值: 745e932be093669729f66a3e815421db8b3a76cd3c270bf2a69e19a8d9b8e897
区块数据: 0

委托挖矿用户: node2
区块Hash值: 1b60389ee80bb5825e88018e9fed7836e549e82f09a914798db38e13d1402f32
区块数据: 1

委托挖矿用户: node4
区块Hash值: 8f0b799c377dfc0260859e993581b022591017a1f2507f70c05f5b3bc77cf3ea
区块数据: 2
成功: 进程退出代码 0.

 

3、说明

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

参考文献:

[1] 白话区块链

[2] 什么是DPoS:https://www.chaindesk.cn/witbook/18/307

 

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昕光xg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值