区块链共识算法之DPOS(上)

简介

DPOS:Delegated Proof of Stake,委任权益证明。简而言之就是一群“有资格的群众”通过投票选举出少许“更有资格的大佬”来替群众“做事”。如果“更有资格的大佬”做的不好,一群“有资格的群众”通过投票也可以将这些大佬踢出“权力圈子”。一群“有资格的群众”怎么理解呢?就是你持有“某些东西”,通常又是“代币”。持有的越多,通常你的话语权就越大,也就意味着你的票“越牛批”

通常的实现一般分为2部分:

1、通过投票选举出少许“更有资格的大佬”

2、替群众“做事”

简单的代码模拟

下面用简单的代码来模拟上面所说的2部分, 代码实际比较简单,仅仅用来理解dpos的核心思想----选举+做事。另外代码是可以直接运行的,因为不熟悉所以写的一般化。。。。

package main

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"math/rand"
	"sort"
	"strconv"
	"time"
)

const (
	runForNodeNum   = 10
	superNodeMaxNum = 3
)

//节点类型
type Node struct {
	Name  string //参选节点名称
	Votes int    //获得的票数
}

type Block struct {
	Index     int
	Timestamp string
	Prehash   string
	Hash      string
	Data      []byte
	delegate  *Node //哪个节点再出块
}

func GenerateGenesisBlock() *Block {
	gene := Block{0, time.Now().String(), "0000000000000000000000000000000000000000000000000000000000000000", "", []byte("genesis block"), nil}
	gene.Hash = hex.EncodeToString(blockHash(&gene))
	return &gene
}

func blockHash(block *Block) []byte {
	record := strconv.Itoa(block.Index) + block.Timestamp + block.Prehash + hex.EncodeToString(block.Data)
	h := sha256.New()
	h.Write([]byte(record))
	hashed := h.Sum(nil)
	return hashed
}

func (node *Node) GenerateNewBlock(lastBlock *Block, data []byte) *Block {
	var newBlock = Block{lastBlock.Index + 1, time.Now().String(), lastBlock.Hash, "", data, nil}
	newBlock.Hash = hex.EncodeToString(blockHash(&newBlock))
	newBlock.delegate = node
	fmt.Printf("%s(%d) produce ", node.Name, node.Votes)
	fmt.Println(newBlock)
	return &newBlock
}

var nodeArr = make([]Node, runForNodeNum)

func CreateNode() {
	for i := 0; i < runForNodeNum; i++ {
		name := fmt.Sprintf("runForNode%d", i+1)
		nodeArr[i] = Node{name, 0}
	}
}

func Vote(nodeChan chan<- []Node) {
	for {
		for i := 0; i < runForNodeNum; i++ {
			rand.Seed(time.Now().UnixNano())
			vote := rand.Intn(100) + 1
			nodeArr[i].Votes = vote
			time.Sleep(297005 * time.Nanosecond)
		}
		nodeChan <- nodeArr
	}

}

func SortNodes(nodeArrAfterVote []Node) {
	sort.Slice(nodeArrAfterVote, func(i int, j int) bool {
		return nodeArrAfterVote[i].Votes > nodeArrAfterVote[j].Votes
	})
}

func main() {

	CreateNode()
	nodeChan := make(chan []Node)
	go Vote(nodeChan)

	gene := GenerateGenesisBlock()
	lastBlock := gene
	nodeArrAfterVote := make([]Node, runForNodeNum)
	for {
		nodeArrAfterVoteTemp := <-nodeChan
		//fmt.Println(nodeArrAfterVoteTemp)
		copy(nodeArrAfterVote, nodeArrAfterVoteTemp)
		SortNodes(nodeArrAfterVote)
		fmt.Printf("\n")
		fmt.Println(nodeArrAfterVote)
		//fmt.Printf("%p\n", &nodeArrAfterVote[0]);
		//fmt.Printf("%p\n", &nodeArr[0]);
		//fmt.Printf("%p\n", &nodeArrAfterVoteTemp[0]);

		for i := 0; i < superNodeMaxNum; i++ {
			lastBlock = nodeArrAfterVote[i].GenerateNewBlock(lastBlock, []byte(fmt.Sprintf("new block id %d", lastBlock.Index)))
			time.Sleep(1 * time.Second)
		}
	}
}

上面的代码简单的模拟了下 每轮出块完成后(3个节点轮流生产一个block/每轮),就去获取最新的投票结果(“有资格的群众”一直处于投票状态中,大佬也是要每轮竞选的,大佬压力也大啊),然后整个处于 出块->竞选->出块。。。。

最后

后面2节将详细分析著名公链EOS的源码-----dpos算法,一起探讨dpos算法不为人知的实现细节。

猜你喜欢

转载自blog.csdn.net/qq_15328161/article/details/88840669