aelf区块生产调度(共识)
共识模块回答五个问题:
这个节点什么时候能出块?
能出块的节点要在区块头(Block Header)中添加什么信息?
能出块的节点要在区块中添加什么交易?
节点接到一个区块,区块头里什么样的共识信息是合规的?
节点接到一个区块,区块里的交易执行完毕后,共识合约的状态要转变成什么样是合规的?
这篇文章主要描述前三个问题的询问时机,以及节点得到共识模块的回答之后如何处理。
共识机制的触发
一共有四种触发共识机制的逻辑。触发的位置不一定是直接调用ConsensusService.TriggerConsensusAsync方法,而是从业务逻辑角度入手,寻找的位置。
共识的多次有效触发并不会引发Bug:比如完成一次触发后,共识模块告知节点10s后可以出块,过了2s后再次触发,共识模块会告知节点8s后可以出块,并重置时间调度器。如果再过4s后重新触发,共识也许会告知节点20s后才可以出块,这在当前的实现中是有可能的(发生在额外时间槽的补位逻辑)。
节点启动时触发共识机制
触发位置:BlockchainNodeContextService.StartAsync。
在aelf节点启动的过程中,共识模块的存在感出现在确认本地ChainDb中有一个Chain类型的数据之后。
在此之前,节点试探ChainDb中是否能获取到Chain结构。如果能,则回滚到lib,开始基于lib同步区块;如果不能,说明此前ChainDb是空的,此时节点的使命是根据自己选择的AElf.Blockchains.*项目,自己构造一个Genesis区块,然后把Chain结构初始化好,放进ChainDb。
紧接着就开始询问共识模块第一个问题了。
完成区块同步后触发共识机制
触发位置:FullBlockchainService.SetBestChain。
此前有两种路径:
节点从网络上收到一个区块,完成了验证、执行、再验证后,这个区块即将确认同步到本地,此时试图将Best Chain信息设置到Chain结构上。
参考路径(不止这一个):GrpcServerService.BlockBroadcastStream -> BlockReceivedEvent -> BlockReceivedEventHandler.HandleEventAsync -> BlockSyncService.SyncByBlockAsync -> EnqueueAttachBlockJob -> BlockSyncAttachService.AttachBlockWithTransactionsAsync,把验证块的逻辑放入队列UpdateChainQueue -> BlockAttachService.AttachBlockAsync -> BlockExecutionResultProcessingService.ProcessBlockExecutionResultAsync -> FullBlockchainService.SetBestChain
节点自己生产了一个区块,但是依然需要完成验证、执行、再验证,才能同步到本地。
参考路径:ConsensusService.TriggerConsensusAsync -> ConsensusRequestMiningEventData -> ConsensusRequestMiningEventHandler.HandleEventAsync -> 产生区块之后(无论成功还是失败)
生成区块的过程中发生异常后重新触发共识机制
触发位置:ConsensusRequestMiningEventHandler.HandleEventAsync,如果没有产生区块,会重新触发共识。
同上述的第二种路径。
共识验证失败后重新触发共识机制
触发位置:
ConsensusService.ValidateConsensusBeforeExecutionAsync
ConsensusService.ValidateConsensusAfterExecutionAsync
以上验证过程中,如果发生验证失败,会重新触发共识。如果共识信息验证失败了,那就重新触发一下看看。
区块生产的时间调度
目前时间调度(IConsensusScheduler接口)提供了两个实现,Rx.Net和FluentScheduler。主网上使用的是Rx.Net实现,IConsensusScheduler接口提供两个方法:
NewEvent,参数为倒计时毫秒数和一个包含了区块产生需要用到的指令的结构:ConsensusRequestMiningEventData
CancelCurrentEvent,用来取消目前正处于倒计时的出块任务
调用NewEvent,就会挂载一个用于生产区块的定时任务,进入倒计时。倒计时完成后,会Publish一个ConsensusRequestMiningEventData事件,由ConsensusRequestMiningEventHandler处理。
NewEvent的参数是从AEDPoS合约中获取到的,详情见AEDPoS合约 中关于GetConsensusCommand方法的实现。
区块生产
区块生产的入口是MiningRequestService.RequestMiningAsync。
Last updated