区块交易执行流程
概述
在阅读本文档之前,请确保拥有了Actor和Starcoin Service的知识,相关知识请参考starcoin 异步模型分析
本文结合代码阅读体验更佳
阅读完本文档可以大概了解一个block是如何被提交到区块链上的。本文档主要从几个场景描述了交易的执行过程,不管是哪个场景,最终都会到Block执行那一步。
通过远程节点同步区块到本地之后的交易过程
本地发起交易之后的执行过程。
创世交易
这里与之相关的流程为 同步服务、本地提交。
整体代码结构
TODO
远程同步
SystemStarted
当系统启动时会广播一次SystemStarted
系统通知(关于Starcoin注册服务,可参考TODO),SyncService
通过实现EventHandle<SystemStarted>
来处理该消息,它会往context中广播一次CheckSyncEvent
事件。同样的还 是它自己再捕获了这个事件,这里使用了广播事件通知了一次,看起来多此一举,实际是方便外面其它服务得知这个状态。在CheckSyncEvent
通知之后捕获了这个事件之后调用了 check_and_start_sync
函数。
check_and_start_sync
从本地(SyncService成员)中获取同步参数
生成一个实际的
Future
并将其放入到ctx执行器中,该Future实现了同步的完整流程构造RpcClient:根据选择策略选择策略
WeightdRandom
(关于选择策略部分,可以参考 Starcoin区块同步) 拿到了一个远程节点的列表且构建它们的荣誉值(Reputation Value),根据荣誉值构建一个PeerSelector,将其传入到RpcClient,用来获取最好的远程节点。调用
full_sync_task
full_sync_task
根据远程节点的区块高度,构建
FindAncestorTask
通过第一步的任务找到上一个区块的区块号,并根据其找到区块信息,准备好所有信息后,调用了生成
InnerSyncTask
,并调用InnerSyncTask::do_sync
函数。根据传入的BlockInfo去peer同步区块(这里调用了BlockSyncTask),当BlockSyncTask将区块信息取回之后,将结果放进了结果集BlockCollector,这里的BlockCollector作为BlockSyncTask的结果收集器,拿到了对应信息之后调用了
BlockCollector::apply_block
,它直接调用了BlockChain::apply
注意:这里直接调用了blockchain的apply方法,是否违背了模块隔离原则?
本地提交
TODO
创世块
在最开始启动时,关于启动的相关流程,请参考启动流程(TODO)。NodeService 在启动时通过SystemRunner
异步阻塞调用 init_system
,其会进一步调用Genesis::init_and_check_storage
,在该函数中根据传入的 storage 和配置文件路径来获取一个chainInfo,这里分成了两种情况
chainInfo存在,从路径中读取genesis信息,并将genesis.block_hash()中的信息与当前chaininfo中的genesis_hash比较,如果不一致则说明配置路径中的创世块跟内存中加载的创世块不一致,则不会被继续执行。
chainInfo不存在,则根据network id去调用
Genesis::build_genesis_block
生成一个新的genesis (测试网络总是生成新的genesis)
Genesis::build_genesis_block
会生成新的创世块,它有以下流程
执行
build_genesis_transaction
,该函数会编译stdlib,将其打包成move的链上二进制可发布版本,最终输出为一个RawTransaction调用
Genesis::execute_genesis_txs
,该函数会调用starcoin_executor::execute_transactions
,执行完交易将其状态写入到ChainStateDB
Block执行
Bock执行的模块入口为:Chain::apply()
包括验证(Verifier)、执行(Execute)、连接(Connect)三步
Verifier
apply_with_verifier
根据传入的Verifier类型来确定如何验证,通常为Basic,Consensus,Full,None四类,默认用的FullVerifier
Basic,验证区块高度,前一个区块高度,时间戳,epoch,gas上限、区块根hash;
Consensus,根据使用的共识算法对header进行验证,目前用的是
CryptoNight
Full,对区块进行Basic和Consensus验证;
None,不做任何验证。
验证完成Header会验证Body和Uncle block
Execute
execute_block_and_save
在区块被验证通过后调用,它执行了以下动作
将区块内所有的交易全部取出,调用
starcoin_executor::block_executor
执行所有的交易将执行过的txn的所有hash包含到当前
txn_accumulator
中,并计算其roothash,之后将与传过来的block.header中的roothash比较,若不一致则报错。将新的block_id包含到当前
block_accumulator
中根据新的block_id, txn_accumulator_info与block_accumulator_info生成新的block_info。
保存所有的交易信息到数据库
将新生成的
block_info
和传入的block
作为结果返回给调用方
Connect
这里是将执行之后的txn accumulator info和block accumulator info 合并到现有的accumulator tree中
相关链接
关于Service与事件处理机制相关逻辑,可以参考starcoin 异步模型分析
关于区块同步策略等相关逻辑,可以参考区块同步代码分析