概览

BFT的节点根据是否参与投票可以区分为验证节点和非验证节点,其中验证节点需要参与每一个区块的投票。 这里有几个关键的特定词:

  • Epoch : 每个epoch中包含多个round,单个epoch中验证者列表是固定的,这个列表不会随时变动否则会影响投票递进。
  • Round : 每一轮Round有一个Leader,这个Leader会根据收到的交易打包出新的待投票的区块。
  • Voting Power : 这个一般根据质押的代币数量来决定当前节点的VP。

共识层的代码会收到别的节点打包好发过来的消息,验证者需要单独的验证消息的内容。一般在单个节点的本地在新的Round 开始的时候会设置一个计时器,这个计时器的作用就是保证每个Round都能按照一定的周期推进。 投票的内容可以区分为3大类

  • TC : 本次Round的Leader没有在规定的时间范围之内打包好区块并且广播出去
  • NEC : 本地节点对区块的内容投票不背书
  • QC : QC的生成需要投票背书VP达到总量的>= 2/3 + 1

TC的详细流程

待添加中…

QC的详细流程

通过一段RUST实现的BFT,可以详细梳理下整个QC的流程:

pub fn process_vote<VT>(
    &mut self,
    author: &NodeId<SCT::NodeIdPubKey>,
    vote_msg: &VoteMessage<SCT>,
    validators: &VT,
    validator_mapping: &ValidatorMapping<
        SCT::NodeIdPubKey,
        SignatureCollectionKeyPairType<SCT>,
    >,
) -> (Option<QuorumCertificate<SCT>>, Vec<VoteStateCommand>)

参数内容:

  • author:这个消息的发送节点
  • vote_msg: 发送的消息内容,包含投票的Round和Vote内容
  • validators: 当前Epoch中包含的验证者列表

当本地节点收到投票消息之后:

  • 首先需要验证Round是否已经过期(由于网络延迟等原因造成),过期消息不再被处理
  • 本地节点需要存储当前Round收到的所有消息,包含节点ID(author)和投票内容
  • 然后将本次的内容插入到上诉的消息列表中,然后我们就得到了当前Round的所有投票内容
  • 这时我们就可以开始计算VP,当VP >= 总VP * 2/3 + 1的时候,当前节点就可以为本轮Round生成QC
  • 在生成QC之前本地节点还需要循环每个消息去验证签名信息,如果有非法的签名,就把这个签名的节点信息移出pending的消息列表,当移出之后再次检查VP的数量是否能够满足上诉的条件
  • 一般情况下签名的内容应该都是合法的,否则签名的节点会受到相应的处罚。
  • 当所有签名合法之后开始生成QC,并且更新本地的Round到Round+1

NEC的详细流程

待添加中…