区块交易执行流程

概述

 

  1. 在阅读本文档之前,请确保拥有了Actor和Starcoin Service的知识,相关知识请参考starcoin 异步模型分析

  2. 本文结合代码阅读体验更佳

阅读完本文档可以大概了解一个block是如何被提交到区块链上的。本文档主要从几个场景描述了交易的执行过程,不管是哪个场景,最终都会到Block执行那一步。

  1. 通过远程节点同步区块到本地之后的交易过程

  2. 本地发起交易之后的执行过程。

  3. 创世交易

这里与之相关的流程为 同步服务、本地提交。

整体代码结构

TODO

远程同步

SystemStarted

当系统启动时会广播一次SystemStarted系统通知(关于Starcoin注册服务,可参考TODO),SyncService通过实现EventHandle<SystemStarted>来处理该消息,它会往context中广播一次CheckSyncEvent事件。同样的还 是它自己再捕获了这个事件,这里使用了广播事件通知了一次,看起来多此一举,实际是方便外面其它服务得知这个状态。在CheckSyncEvent通知之后捕获了这个事件之后调用了 check_and_start_sync 函数。

check_and_start_sync

  1. 从本地(SyncService成员)中获取同步参数

  2. 生成一个实际的Future并将其放入到ctx执行器中,该Future实现了同步的完整流程

    1. 构造RpcClient:根据选择策略选择策略WeightdRandom(关于选择策略部分,可以参考 Starcoin区块同步) 拿到了一个远程节点的列表且构建它们的荣誉值(Reputation Value),根据荣誉值构建一个PeerSelector,将其传入到RpcClient,用来获取最好的远程节点。

    2. 调用full_sync_task

full_sync_task

  1. 根据远程节点的区块高度,构建FindAncestorTask

  2. 通过第一步的任务找到上一个区块的区块号,并根据其找到区块信息,准备好所有信息后,调用了生成InnerSyncTask,并调用InnerSyncTask::do_sync函数。

  3. 根据传入的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,这里分成了两种情况

  1. chainInfo存在,从路径中读取genesis信息,并将genesis.block_hash()中的信息与当前chaininfo中的genesis_hash比较,如果不一致则说明配置路径中的创世块跟内存中加载的创世块不一致,则不会被继续执行。

  2. chainInfo不存在,则根据network id去调用Genesis::build_genesis_block生成一个新的genesis (测试网络总是生成新的genesis)

 

Genesis::build_genesis_block会生成新的创世块,它有以下流程

  1. 执行build_genesis_transaction ,该函数会编译stdlib,将其打包成move的链上二进制可发布版本,最终输出为一个RawTransaction

  2. 调用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

  1. Basic,验证区块高度,前一个区块高度,时间戳,epoch,gas上限、区块根hash;

  2. Consensus,根据使用的共识算法对header进行验证,目前用的是CryptoNight

  3. Full,对区块进行Basic和Consensus验证;

  4. None,不做任何验证。

验证完成Header会验证Body和Uncle block

Execute

execute_block_and_save在区块被验证通过后调用,它执行了以下动作

  1. 将区块内所有的交易全部取出,调用starcoin_executor::block_executor 执行所有的交易

  2. 将执行过的txn的所有hash包含到当前txn_accumulator中,并计算其roothash,之后将与传过来的block.header中的roothash比较,若不一致则报错。

  3. 将新的block_id包含到当前block_accumulator

  4. 根据新的block_id, txn_accumulator_info与block_accumulator_info生成新的block_info。

  5. 保存所有的交易信息到数据库

  6. 将新生成的block_info和传入的block作为结果返回给调用方

Connect

这里是将执行之后的txn accumulator info和block accumulator info 合并到现有的accumulator tree中

相关链接