前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【共识算法(6)】-“DPOS与POS的区别与实现”

【共识算法(6)】-“DPOS与POS的区别与实现”

作者头像
帆说区块链
发布2022-04-26 19:44:37
4570
发布2022-04-26 19:44:37
举报
文章被收录于专栏:帆说区块链帆说区块链

POS

每个旷工都有出块(即挖矿)的权力,只要出块成功,就有系统给出的奖励,这里不需要通过复杂的计算来挖矿,问题只在于谁来出块,股权越大,出块的概率就越大,反之,则相反。POS有很多变种,股权可以是持有币的数量,或者支付的数量等等。

但POS的问题是,大多数的持币人没有足够的专业知识或足够的预算,无法达到高性能节点所需的计算机硬件和软件要求,这时候就有了DPOS机制。

DPOS

DPOS(Delegated Proof of Stake ,代理权益证明)这是一种基于投票选举的共识算法,有点像民主大会,持币人选出几个代表节点来运营网络,用专业运行的网络服务器来保证区块链网络的安全和性能。DPOS机制中,不需要算力解决数学难题,而是由持币者选出谁说生产者,如果生产者不称职,就有随时有可能被投票出局,这也就解决了POS的性能问题。

在DPOS机制下,算法要求系统做三件事:

第一,随机指定生产者出场顺序;第二,不按顺序生产的区块无效;第三,每过一个周期洗牌一次,打乱原有顺序;

而且,DPOS允许所有矿池每三秒钟轮换一次,并且其他人已被安排在后续进程中,于是,没有人可以在预设位置外生产区块。如果一个块生产者这么做了,就可能被投票出局。

这意味着,生产者之间没有争夺,也不会遗漏区块,每三秒会有一个区块

1. 相对于POW和POS,DPOS机制最大的优点之一是共识达成的周期要短很多。

基于POW的比特币每秒处理7笔交易;基于POW和POS的以太坊每秒处理15笔交易;而基于DPOS的比特股(BTS)每秒能处理超10万的交易量。EOS将通过并行链的方式,预计最高可达到每秒数百万币的确认速度。

2. DPOS也会将一部分奖励分给网络维护节点和投票者,作为社区维护的奖励。

比如,LBTC就是采用DPOS机制出块,LBTC的持币者投票选出101个节点,这101个节点负责出块,并获得一定的奖励,而这其中每一个节点的投票者本身也会从中获得一定的回报。

简单的来说,你只需要去给你认为能被选中并承诺分红的节点投票,这些节点被选中后便可挖矿,你就可以获得节点承诺的相应分红。而此收益不需要你真实的操作挖矿,而仅仅只需要你动动小手指去投个票。有一些钱包已经支持LBTC的投票。

还有一些钱包更简单,不需要你手动投票,只需存入LBTC即可躺赚最优收益,Cobo此前上线的LBTC智能投票系统年化最高收益最高达300%,但是,随着投票数量增加,收益率也会相对减少,目前年化收益仍然在100%以上,想省心又想赚钱的朋友可以体验一下。

DPOS与POS最大的区别在于POS每一个节点都有权利挖矿,只要出块成功都有奖励,而DPOS要从普通节点中选取超级节点,超级节点进行共识。

超级节点指DPoS共识机制下的少数有权利生成区块的节点。

超级节点的五大职责:

1、提供服务器节点,保证节点的正常运行;

2、收集网络中的交易;

3、验证交易并把交易打包到区块;

4、广播区块给其他区块,在通过验证后将区块添加到自己本地区块链上;

5、保障并促进区块链项目的发展。

以下分享以下用go实现的简易POS与DPOS。

代码语言:javascript
复制
package main

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

type block struct {
  //上一个块的hash
  prehash string
  //本块hash
  hash string
  //时间戳
  timestamp string
  //区块内容
  data string
  //区块高度
  height int
  //挖出本块的地址
  address string
}

//用于存储区块链
var blockchain []block

//代表挖矿节点
type node struct {
  //代币数量
  tokens int
  //质押时间
  days int
  //节点地址
  address string
}

//挖矿节点
var mineNodesPool []node

//概率节点池
var probabilityNodesPool []node

//初始化
func init() {
  //手动添加两个节点
  mineNodesPool = append(mineNodesPool, node{1000, 1, "AAAAAAAAAA"})
  mineNodesPool = append(mineNodesPool, node{100, 3, "BBBBBBBBBB"})
  //初始化随机节点池(挖矿概率与代币数量和币龄有关)
  for _, v := range mineNodesPool {
    for i := 0; i <= v.tokens*v.days; i++ {
      probabilityNodesPool = append(probabilityNodesPool, v)
    }
  }
}

//生成新的区块
func generateNewBlock(oldBlock block, data string, address string) block {
  newBlock := block{}
  newBlock.prehash = oldBlock.hash
  newBlock.data = data
  newBlock.timestamp = time.Now().Format("2006-01-02 15:04:05")
  newBlock.height = oldBlock.height + 1
  newBlock.address = getMineNodeAddress()
  newBlock.getHash()
  return newBlock
}

//对自身进行散列
func (b *block) getHash() {
  sumString := b.prehash + b.timestamp + b.data + b.address + strconv.Itoa(b.height)
  hash := sha256.Sum256([]byte(sumString))
  b.hash = hex.EncodeToString(hash[:])
}

//随机得出挖矿地址(挖矿概率跟代币数量与币龄有关)
func getMineNodeAddress() string {
  bInt := big.NewInt(int64(len(probabilityNodesPool)))
  //得出一个随机数,最大不超过随机节点池的大小
  rInt, err := rand.Int(rand.Reader, bInt)
  if err != nil {
    log.Panic(err)
  }
  return probabilityNodesPool[int(rInt.Int64())].address
}

func main() {
  //创建创世区块
  genesisBlock := block{"0000000000000000000000000000000000000000000000000000000000000000", "", time.Now().Format("2006-01-02 15:04:05"), "我是创世区块", 1, "0000000000"}
  genesisBlock.getHash()
  //把创世区块添加进区块链
  blockchain = append(blockchain, genesisBlock)
  fmt.Println(blockchain[0])
  i := 0
  for {
    time.Sleep(time.Second)
    newBlock := generateNewBlock(blockchain[i], "我是区块内容", "00000")
    blockchain = append(blockchain, newBlock)
    fmt.Println(blockchain[i+1])
    i++
  }
}
代码语言:javascript
复制
package main

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

const (
  voteNodeNum      = 100
  superNodeNum     = 10
  mineSuperNodeNum = 3
)

type block struct {
  //上一个块的hash
  prehash string
  //本块hash
  hash string
  //时间戳
  timestamp string
  //区块内容
  data string
  //区块高度
  height int
  //挖出本块的节点地址
  address string
}

//用于存储区块链
var blockchain []block

//普通节点
type node struct {
  //代币数量
  votes int
  //节点地址
  address string
}

//竞选节点
type superNode struct {
  node
}

//投票节点池
var voteNodesPool []node

//竞选节点池
var starNodesPool []superNode

//存放可以挖矿的超级节点池
var superStarNodesPool []superNode

//生成新的区块
func generateNewBlock(oldBlock block, data string, address string) block {
  newBlock := block{}
  newBlock.prehash = oldBlock.hash
  newBlock.data = data
  newBlock.timestamp = time.Now().Format("2006-01-02 15:04:05")
  newBlock.height = oldBlock.height + 1
  newBlock.address = address
  newBlock.getHash()
  return newBlock
}

//对自身进行散列
func (b *block) getHash() {
  sumString := b.prehash + b.timestamp + b.data + b.address + strconv.Itoa(b.height)
  hash := sha256.Sum256([]byte(sumString))
  b.hash = hex.EncodeToString(hash[:])
}

//投票
func voting() {
  for _, v := range voteNodesPool {
    rInt, err := rand.Int(rand.Reader, big.NewInt(superNodeNum+1))
    if err != nil {
      log.Panic(err)
    }
    starNodesPool[int(rInt.Int64())].votes += v.votes
  }
}

//对挖矿节点进行排序
func sortMineNodes() {
  sort.Slice(starNodesPool, func(i, j int) bool {
    return starNodesPool[i].votes > starNodesPool[j].votes
  })
  superStarNodesPool = starNodesPool[:mineSuperNodeNum]
}

//初始化
func init() {
  //初始化投票节点
  for i := 0; i <= voteNodeNum; i++ {
    rInt, err := rand.Int(rand.Reader, big.NewInt(10000))
    if err != nil {
      log.Panic(err)
    }
    voteNodesPool = append(voteNodesPool, node{int(rInt.Int64()), "投票节点" + strconv.Itoa(i)})
  }
  //初始化竞选节点
  for i := 0; i <= superNodeNum; i++ {
    starNodesPool = append(starNodesPool, superNode{node{0, "超级节点" + strconv.Itoa(i)}})
  }
}

func main() {
  fmt.Println("初始化", voteNodeNum, "个投票节点...")
  fmt.Println(voteNodesPool)
  fmt.Println("当前存在的", superNodeNum, "个竞选节点")
  fmt.Println(starNodesPool)
  fmt.Println("投票节点们开始进行投票...")
  voting()
  fmt.Println("结束投票,查看竞选节点们获得票数...")
  fmt.Println(starNodesPool)
  fmt.Println("对竞选节点按获得票数排序,前", mineSuperNodeNum, "名,当选超级节点")
  sortMineNodes()
  fmt.Println(superStarNodesPool)
  fmt.Println("开始挖矿...")
  genesisBlock := block{"0000000000000000000000000000000000000000000000000000000000000000", "", time.Now().Format("2006-01-02 15:04:05"), "我是创世区块", 1, "000000000"}
  genesisBlock.getHash()
  blockchain = append(blockchain, genesisBlock)
  fmt.Println(blockchain[0])
  i, j := 0, 0
  for {
    time.Sleep(time.Second)
    newBlock := generateNewBlock(blockchain[i], "我是区块内容", superStarNodesPool[j].address)
    blockchain = append(blockchain, newBlock)
    fmt.Println(blockchain[i+1])
    i++
    j++
    j = j % len(superStarNodesPool) //超级节点轮循获得出块权
  }
}

结果图:

(1)POS(直接进行挖矿操作)

(2)DPOS(选出超级节点后进行挖矿操作,投票节点数为100)

参考:https://baijiahao.baidu.com/s?id=1603870079950594911&wfr=spider&for=pc

https://www.zhihu.com/question/286852548

https://blog.csdn.net/baidu_27836327/article/details/104219984

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 帆说区块链 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
区块链
云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档