29

【go共识算法】-DPOS

 5 years ago
source link: https://studygolang.com/articles/15126?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

DPOS介绍

概念

Delegated Proof of Stake,委任权益证明。

中文名叫做股份授权证明机制(又称受托人机制),它的原理是让每一个持有比特股的人进行投票,由此产生101位代表 , 我们可以将其理解为101个超级节点或者矿池,而这101个超级节点彼此的权利是完全相等的。从某种角度来看,DPOS有点像是议会制度或人民代表大会制度。如果代表不能履行他们的职责(当轮到他们时,没能生成区块),他们会被除名,网络会选出新的超级节点来取代他们。DPOS的出现最主要还是因为矿机的产生,大量的算力在不了解也不关心比特币的人身上,类似演唱会的黄牛,大量囤票而丝毫不关心演唱会的内容。

比特股引入了见证人这个概念,见证人可以生成区块,每一个持有比特股的人都可以投票选举见证人。得到总同意票数中的前N个(N通常定义为101)候选者可以当选为见证人,当选见证人的个数(N)需满足:至少一半的参与投票者相信N已经充分地去中心化。

见证人的候选名单每个维护周期(1天)更新一次。见证人然后随机排列,每个见证人按序有2秒的权限时间生成区块,若见证人在给定的时间片不能生成区块,区块生成权限交给下一个时间片对应的见证人。DPoS的这种设计使得区块的生成更为快速,也更加节能。

DPoS充分利用了持股人的投票,以公平民主的方式达成共识,他们投票选出的N个见证人,可以视为N个矿池,而这N个矿池彼此的权利是完全相等的。持股人可以随时通过投票更换这些见证人(矿池),只要他们提供的算力不稳定,计算机宕机,或者试图利用手中的权力作恶。

应用

  • 比特股 Bitshares(提出这个概念)
  • EOS

共识算法我DPoS + BFT

  • Asch

共识算法为DPoS + PBFT, 有101个受托人, 目前正在开放竞选

go实现DPOS

package main

import (
    "time"
    "encoding/hex"
    "math/rand"
    "log"
    "sort"
    "crypto/sha256"
)
//定义区块结构体
type Block struct {
    Index int
    Timestamp string
    BPM int
    Hash string
    PrevHash string
    Delegate string
}
// 创建区块函数
func generateBlock(oldBlock Block, _BMP int, address string) (Block, error) {
    var newBlock Block
    t := time.Now()

    newBlock.Index = oldBlock.Index + 1
    newBlock.Timestamp = t.String()
    newBlock.BPM = _BMP
    newBlock.PrevHash = oldBlock.Hash
    newBlock.Hash = createBlockHash(newBlock)
    newBlock.Delegate = address

    return newBlock, nil
}
//生成区块hash
func createBlockHash(block Block) string {
    record := string(block.Index) + block.Timestamp + string(block.BPM) + block.PrevHash
    sha3 := sha256.New()
    sha3.Write([] byte(record))
    hash := sha3.Sum(nil)
    return hex.EncodeToString(hash)
}
// 简单的检验区块函数
func isBlockValid(newBlock, oldBlock Block) bool{
    if oldBlock.Index + 1 != newBlock.Index {
        return false
    }

    if newBlock.PrevHash != oldBlock.Hash {
        return false
    }
    return true
}
// 区块集合
var blockChain []Block

// dpos里的超级节点结构体(受托人)
type Trustee struct {
    name string
    votes int
}

type trusteeList [] Trustee
// 下面的三个函数是为了排序使用,大家可以查下go的排序还是很强大的
func (_trusteeList trusteeList) Len() int {
    return len(_trusteeList)
}
func (_trusteeList trusteeList) Swap(i, j int){
    _trusteeList[i], _trusteeList[j] = _trusteeList[j], _trusteeList[i]
}
func (_trusteeList trusteeList) Less(i, j int) bool {
    return _trusteeList[j].votes < _trusteeList[i].votes
}

// 选举获得投票数最高的前5节点作为超级节点,并打乱其顺序
func selectTrustee() ([]Trustee){
    _trusteeList := [] Trustee {
        {"node1", rand.Intn(100)},
        {"node2", rand.Intn(100)},
        {"node3", rand.Intn(100)},
        {"node4", rand.Intn(100)},
        {"node5", rand.Intn(100)},
        {"node6", rand.Intn(100)},
        {"node7", rand.Intn(100)},
        {"node8", rand.Intn(100)},
        {"node9", rand.Intn(100)},
        {"node10", rand.Intn(100)},
        {"node11", rand.Intn(100)},
        {"node12", rand.Intn(100)},
    }
    sort.Sort(trusteeList(_trusteeList))
    result := _trusteeList[:5]
    _trusteeList = result[1:]
    _trusteeList = append(_trusteeList, result[0])
    log.Println("当前超级节点列表是", _trusteeList)
    return _trusteeList
}

func main() {
    t := time.Now()

    // init gensis block(创建创世块,真正的可不是这么简单的,这里只做流程实现)
    genesisBlock := Block{0, t.String(), 0, createBlockHash(Block{}), "", ""}
    blockChain = append(blockChain, genesisBlock) // 这里只是完成了一次dpos的写区块操作,eos真正的是每个节点实现6个区块,并且所有超级节点(21个)轮完,之后再做选举
    var trustee Trustee
    for _, trustee = range selectTrustee() {
        _BPM := rand.Intn(100)
        blockHeight := len(blockChain)
        oldBlock := blockChain[blockHeight - 1]
        newBlock, err := generateBlock(oldBlock, _BPM, trustee.name)
        if err != nil {
            log.Println(err)
            continue
        }

        if isBlockValid(newBlock, oldBlock) {
            blockChain = append(blockChain, newBlock)
            log.Println("当前操作区块的节点是: ", trustee.name)
            log.Println("当前区块数量是: ", len(blockChain) - 1)
            log.Println("当前区块信息: ", blockChain[len(blockChain) - 1])

        }

    }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK