• 12. TDPoS共识
    • 12.1. 介绍
      • 12.1.1. 候选人选举
      • 12.1.2. 候选人轮值
      • 12.1.3. 技术细节

    12. TDPoS共识

    12.1. 介绍

    TDPoS是超级链的一种改进型的DPoS算法,他是在一段预设的时间长度(一轮区块生产周期)内选择若干个验证节点,同时将这样一轮区块生产周期分为N个时间段, 这若干个候选节点按照约定的时间段协议协同挖矿的一种算法。在选定验证节点集合后,TDPoS通过Chained-BFT算法来保证轮值期间的安全性。总结一下,整个TDPoS主要包括2大阶段:

    • 验证人选举:通过pos相关选举规则选出一个验证者集合;
    • 验证人轮值:验证者集合按照约定的协议规则进行区块生产;

    12.1.1. 候选人选举

    节点角色 ../_images/tdpos.png 在TDPoS中,网络中的节点有三种角色,分别是“普通选民”、“候选人”、“验证者”:

    • 选民:所有节点拥有选民的角色,可以对候选节点进行投票;
    • 候选人:需要参与验证人竞选的节点通过注册机制成为候选人,通过注销机制退出验证人竞选;
    • 验证人:每轮第一个节点进行检票,检票最高的topK候选人集合成为该轮的验证人,被选举出的每一轮区块生产周期的验证者集合,负责该轮区块的生产和验证,某个时间片内,会有一个矿工进行区块打包,其余的节点会对该区块进行验证。

    网络中的三种角色之间是可以相互转换的,转换规则如下:

    • 所有地址都具有选民的特性,可以对候选人进行投票;
    • 选民经过“候选人提名”提名接口成为候选人,参与竞选;
    • 候选人经过“候选人退选”注销接口退出竞选;
    • 候选人经过检票产出验证者,得票topK的候选人当选验证者;
    • 验证者轮值完恢复候选人或者选民角色;

    提名规则

    节点想要参与竞选,需要先被提名为候选人,只有被提名的地址才能接受投票。为了收敛候选人集合,并一定程度上增加候选人参与的门槛,提名为候选人会有很多规则,主要有以下几点:

    • 提名候选人需要冻结燃料,并且金额不小于系统总金额的十万分之一;
    • 该燃料会被一直冻结,直到节点退出竞选;
    • 提名支持自提和他提,即允许第三方节点对候选人进行提名;
    • 被提名者需要知晓自己被提名,需要对提名交易进行背书;

    选举规则

    候选人被提名后,会形成一个候选人池子,投票需要针对该池子内部的节点进行。TDPoS的投票也有很多规则,主要有以下几点:

    • 任何地址都可以进行投票,投票需要冻结燃料,投票的票数取决于共识配置中每一票的金额,票数 = 冻结金额 / 投票单价;
    • 该燃料会被一直冻结,直到该投票被撤销;
    • 投票采用博尔达计分法,支持一票多投,每一票最多投给设置的验证者个数,每一票中投给不同候选人的票数相同;

    12.1.2. 候选人轮值

    每一轮开始的第一个区块会自动触发检票的交易,该交易会进行下一轮候选人的检票,被选举出的节点会按照既定的时间片协同出块,每一个区块都会请求所有验证节点的验证。TDPoS的时间片切分如下图所示: ../_images/tdpos-slice.png 为了降低切主时容易造成分叉,TDPoS将出块间隔分成了3个,如上图所示:

    • t1:同一轮内同一个矿工的出块间隔;
    • t2:同一轮内切换矿工时的出块间隔,需要为t1的整数倍;
    • t3:不同轮间切换时的出块间隔,需要为t1的整数倍;

    拜占庭容错

    TDPoS验证节点轮值过程中,采取了 Chained-Bft 防止矿工节点的作恶。

    12.1.3. 技术细节

    TDPoS实现主要在 consensus/tdpos 路径下,其主要是通过智能合约的方式实现的,主要有以下几个合约方法:

    1. voteMethod = "vote"
    2. // 候选人投票撤销
    3. revokeVoteMethod = "revoke_vote"
    4. // 候选人提名
    5. nominateCandidateMethod = "nominate_candidate"
    6. // 候选人罢黜
    7. revokeCandidateMethod = "revoke_candidate"
    8. // 验证人生成
    9. checkvValidaterMethod = "check_validater"

    核心接口如下:

    1. func (tp *TDpos) runVote(desc *contract.TxDesc, block *pb.InternalBlock) error {
    2. // ......
    3. return nil
    4. }
    5. func (tp *TDpos) runRevokeVote(desc *contract.TxDesc, block *pb.InternalBlock) error {
    6. // ......
    7. return nil
    8. }
    9. func (tp *TDpos) runNominateCandidate(desc *contract.TxDesc, block *pb.InternalBlock) error {
    10. // ......
    11. return nil
    12. }
    13. func (tp *TDpos) runRevokeCandidate(desc *contract.TxDesc, block *pb.InternalBlock) error {
    14. // ......
    15. return nil
    16. }
    17. func (tp *TDpos) runCheckValidater(desc *contract.TxDesc, block *pb.InternalBlock) error {
    18. // ......
    19. return nil
    20. }