Dual-VM方案讨论
背景
Starcoin main网络这里简称为Starcoin 1.0, 需要向Starcoin 2.0做资产隐射,资产隐射当中会有些问题需要处理(StarcoinFramework 2.0 资产映射工作清单) ,能否将Starcoin 1.0和2.0都做到一个链当中,执行不同的VM处理不同类型的交易。 @Bob @hui jiao 讨论有如下想法
设计想法
1.交易类型添加
支持不同的交易类型,交易类型里面添加扩展字段,以前交易叫做Legacy交易,和新交易类型两种类型
Legacy交易基于以前逻辑来处理也就是master分支
新交易类型基于新的dag-master分支处理
2.状态树的实现
状态树的处理需要涉及到Block miner的逻辑,miner会将Legacy txn和txn一起打包,
执行的时候会产生Legacy txn执行,这里就说是VM1.0, txn执行这里简称为VM2.0
VM1.0产生state_root1, VM2.0产生state_root2,将state_root1, state_root2,新生成
state_root (需要设计下生成state_root的逻辑, 这里再设计一层smt tree3, 设置特殊key, value为(state_root1, state_root2) ),将key,value插入到stm tree3, 由二层存储结构变成3层)
3.模块相关
OpenBlock以及miner相关模块
BlockHeader保持结构体不变,兼容1.0区块,BlockBody中填充新旧两种交易
BlockInfo中添加一个字段保存2.0 vm的state_root2,用于创建StateDB2时使用。
现有流程从BlockHeader中获取state_root1,为了保持兼容和减少工作量,保持不变。
BlockInfoStore trait在多个流程中使用,比较容易通过block_id获取到blockInfo,进而获取到state_root2。如TxPoolService/WriteBlockChainService
BlockInfo的更新不影响state_root1,比较容易处理
新的交易在执行后,会被添加到BlockHeader中的txn_accumulator,需要对两种HashValue进行转换
gas_used通过TransactionOutput进行统计,并与block_gas_limit进行比较
交易execution模块的处理,
StarcoinVM 1.0和2.0相关抽象和重写
movevm 需要引用不同版本的move, 新的move repo引用都需要重命名
由于有些逻辑有相似之处,可能的对接口进行抽象,方便两个vm实现有太多重复冗余代码
Storage存储相关,由于状态里面有state_root1和state_root2, 对应物理存储是放到一个文件夹还是不同文件夹
Storage存储里面column family对应的schema也不一样,也需要对实现进行抽象
storage instance可以复用现有的代码,包括cache和cf,复用transaction output处理流程
ChainStateDB是用于更新stateroot的结构体,为了支持resource/resource_group tree,需要新的结构体和流程,包括Reader/Writer。
需要新的Super Trait - StarcoinMoveResolver,有许多基于StateView auto-implement trait
更新链上resource path,move vm解析时需要新的路径
不同vm之间使用StorageAdapter layer作为访问资源的统一入口
StarcoinFramework相关处理
物理隔离:将1.0 与 2.0 放置在不同文件夹
加载方式:在加载处增加封装,根据参数采用不同加载方式
gas计费:参考aptos,GasSchedule 抽象出来,采用不同的计费对象处理不同的场景
链上对象和模型:目前包含 Balance、Account 这些模型,将其转移到对应的版本framework文件夹中
目前StarcoinFramework是放到0x1账号下面的,如果放到同一文件夹,2.0的starcoinFramework需要放到另一个文件夹上(从vm加载流程来看,framework编译为mv/blob文件,vm执行genesis或者部署contract时根据版本目录选择加载)
同样需要处理的的基金会和一些链上资源 (Legacy vm和new vm合约部署,需要更新rpc接口, 合约部署到不同的状态, Legacy需要后面设置为freezing状态?)
rpc相关和starmask处理,由于有1.0和2.0两个状态,需要获取两个余额,这里需要加上新的rpc api获取新状态的余额
rpc service相关需要新老都添加一份
p2p相关处理,这里p2p同步不仅涉及到Legacy同步处理,还涉及新的
ABI相关,ABI也需要支持新老
sync相关处理,由于Legacy txn和new txn打包到一个Block中,Legacy和new需要使用相同consenus, 不能consensus 1使用POW, consensus使用FlexiDag (consensus用同一个)
剩下的问题 (这些不用考虑)
老token和新token需要交互吗,如何交互
如果有交互是否需要类似bridge功能
BlockMetaData交易生成作用在Legacy状态还是new状态?
设计思路2 -Multi Framework方案
用单一 compiler-v2 来支持不同的framework,参考以下的图示
之前的Multi-VM方案如下图
两类方案均需要满足的目标:
旧区块可以查询
基于旧数据的数据可以执行交易并修改
Framework 1.0 的数据与Framework 2.0 的数据需要进行隔离
Framework 2.0 作以下修改:
Framework 搬回工程,包含native、gas_schedule、 on_chain_config、stdlib、starcoin-framework
DB部分,与现有的区块做物理隔离,根据选择的DB方案做不同的处理
存储方案 | 出块 | 调用和查询 | 执行流程 |
---|---|---|---|
统一存储 | 保持原状,但是需要区分开framework的模块名称,另外可增加framework版本号 | 调用时,需要根据传入的framework版本号来区分,如果是版本号<=v12的调用,去调用新模块,则拒绝调用 | 根据调用版本号来处理 |
分开存储(假设分别为state tree v1 和v2) | 增加一个总的statetree,合并v1和v2作为总的statetree的最新区块 | 根据版本号区分,选择对应的statetree,并选择对应的调用流程 | 根据调用版本号来处理 |
rpc处理,旧的保持不变,新的在head里面增加framework版本号,若检测不到版本号按照默认处理
所有流程和共识按照2.0交易处理,sync的时也按照Framework2.0处理
升级2.0是基于1.0的代码做升级,可以在0x1下开辟新路径以解决模块名称冲突的问题,如 0x1/v13/coin/CoinStore,原有的数据保持不变(选择统一存储的情况下)
0x12345
0x1/Account/Balance
0x1/v13/Account/Balance