aelf区块生产调度(共识)

共识模块回答五个问题:

  1. 这个节点什么时候能出块?

  2. 能出块的节点要在区块头(Block Header)中添加什么信息?

  3. 能出块的节点要在区块中添加什么交易?

  4. 节点接到一个区块,区块头里什么样的共识信息是合规的?

  5. 节点接到一个区块,区块里的交易执行完毕后,共识合约的状态要转变成什么样是合规的?

这篇文章主要描述前三个问题的询问时机,以及节点得到共识模块的回答之后如何处理。

共识机制的触发

一共有四种触发共识机制的逻辑。触发的位置不一定是直接调用ConsensusService.TriggerConsensusAsync方法,而是从业务逻辑角度入手,寻找的位置。

共识的多次有效触发并不会引发Bug:比如完成一次触发后,共识模块告知节点10s后可以出块,过了2s后再次触发,共识模块会告知节点8s后可以出块,并重置时间调度器。如果再过4s后重新触发,共识也许会告知节点20s后才可以出块,这在当前的实现中是有可能的(发生在额外时间槽的补位逻辑)。

节点启动时触发共识机制

circle-info

触发位置:BlockchainNodeContextService.StartAsync。

在aelf节点启动的过程中,共识模块的存在感出现在确认本地ChainDb中有一个Chain类型的数据之后。

在此之前,节点试探ChainDb中是否能获取到Chain结构。如果能,则回滚到lib,开始基于lib同步区块;如果不能,说明此前ChainDb是空的,此时节点的使命是根据自己选择的AElf.Blockchains.*项目,自己构造一个Genesis区块,然后把Chain结构初始化好,放进ChainDb。

紧接着就开始询问共识模块第一个问题了。

完成区块同步后触发共识机制

circle-info

触发位置:FullBlockchainService.SetBestChain。

此前有两种路径:

  1. 节点从网络上收到一个区块,完成了验证、执行、再验证后,这个区块即将确认同步到本地,此时试图将Best Chain信息设置到Chain结构上。

    1. 参考路径(不止这一个):GrpcServerService.BlockBroadcastStream -> BlockReceivedEvent -> BlockReceivedEventHandler.HandleEventAsync -> BlockSyncService.SyncByBlockAsync -> EnqueueAttachBlockJob -> BlockSyncAttachService.AttachBlockWithTransactionsAsync,把验证块的逻辑放入队列UpdateChainQueue -> BlockAttachService.AttachBlockAsync -> BlockExecutionResultProcessingService.ProcessBlockExecutionResultAsync -> FullBlockchainService.SetBestChain

  2. 节点自己生产了一个区块,但是依然需要完成验证、执行、再验证,才能同步到本地。

    1. 参考路径:ConsensusService.TriggerConsensusAsync -> ConsensusRequestMiningEventData -> ConsensusRequestMiningEventHandler.HandleEventAsync -> 产生区块之后(无论成功还是失败)

生成区块的过程中发生异常后重新触发共识机制

circle-info

触发位置:ConsensusRequestMiningEventHandler.HandleEventAsync,如果没有产生区块,会重新触发共识。

同上述的第二种路径。

共识验证失败后重新触发共识机制

circle-info

触发位置:

  • ConsensusService.ValidateConsensusBeforeExecutionAsync

  • ConsensusService.ValidateConsensusAfterExecutionAsync

以上验证过程中,如果发生验证失败,会重新触发共识。如果共识信息验证失败了,那就重新触发一下看看。

区块生产的时间调度

目前时间调度(IConsensusScheduler接口)提供了两个实现,Rx.Net和FluentScheduler。主网上使用的是Rx.Net实现,IConsensusScheduler接口提供两个方法:

  • NewEvent,参数为倒计时毫秒数和一个包含了区块产生需要用到的指令的结构:ConsensusRequestMiningEventData

  • CancelCurrentEvent,用来取消目前正处于倒计时的出块任务

调用NewEvent,就会挂载一个用于生产区块的定时任务,进入倒计时。倒计时完成后,会Publish一个ConsensusRequestMiningEventData事件,由ConsensusRequestMiningEventHandler处理。

circle-info

NewEvent的参数是从AEDPoS合约中获取到的,详情见AEDPoS合约 中关于GetConsensusCommand方法的实现。

区块生产

区块生产的入口是MiningRequestService.RequestMiningAsync。

Last updated