OpenAtomFoundation / xupercore

The kernel of xuperchain.
Apache License 2.0
61 stars 47 forks source link

只读、读写交易顺序可能导致区块执行失败 #351

Closed godeamon closed 1 year ago

godeamon commented 2 years ago

【问题介绍】超级链采用UXTO模型,在合约数据上使用XModel模型,即所有的key都有唯一的版本,版本由refTxid+offset组成,因此所有的交易可以组成一个DAG。一个合约调用的交易的 input 中会包括引用的key以及版本,output 中会包括key以及value,如果交易中对某些key是只读的,那么只会在input中出现,不会在output中出现,同时此时key的版本也不会改变。 在未确认交易池中就可能出现这种情况:交易A的output包括key:a,交易B中引用了交易A的key:a,交易C中引用了交易A中的key:a同时将key:a的value修改,此时交易B只读依赖于交易A,交易C读写依赖于交易A。这三笔交易在未确认交易池中也会建立对应关系。

【问题详细描述】矿工打包区块时需要从未确认交易池中获取一批交易,且交易要按照依赖关系排序,其他节点执行这个区块时需要按照顺序执行。目前在打包区块时,对交易A、B、C进行打包时,会先打包交易A,因为交易B、C都依赖于交易A,但是对于交易B、C的打包顺序是不确定的,如果先打包了交易C再打包交易B,那么其他节点执行此区块时会失败,因为交易C将key:a的版本从交易A改到了交易C,验证交易B时版本不对导致区块执行失败。

【解决方案】打包区块交易时,对于上述情况,需要保证打包顺序为:A->B->C,在目前未确认交易池中遍历交易时区分只读、读写关系。

【设计方案】

  1. 打包交易:目前交易提交到链上后,交易会在mempool中根据读写集进行排序并建立依赖关系,但没有区分只读依赖和读写依赖,因此在打包时可能导致先打包只读交易后打包读写交易,所以,在交易进入mempool后需要区分只读依赖和读写依赖,并且在打包遍历交易时,需要判断当前交易是否有兄弟只读交易,需要保证所有只读交易先打包完再打包写交易;
  2. 同步区块:非矿工节点同步区块时,需要判断区块内的交易和自己的mempool中的交易是否有冲突,此时也要判断自己mempool中的只读交易是否和区块内的读写交易冲突,如果冲突则需要回滚掉;
  3. 兼容问题:目前所有的区块内的交易,对于只读和读写交易都可能是乱序的,尤其在开放网络上,因此如果一个新的节点想加入进来并且同步区块,那么很可能会因为这个问题导致失败。 解决方案:1、 同步区块验证区块内交易时,放宽检查条件,对于只读读写乱序的交易同样可以验证通过,但是矿工作恶时会检查不出来;2、对于开放网络来说,如果新的节点想加入进来,开放一个账本下载功能,从新的区块开始直接同步。
godeamon commented 2 years ago

评审结论:按照上面方案执行。