基于上一篇文章中介绍了初链TrueChain共识的四个阶段,本文将从细节对第二个阶段-出块流程中交易的执行过程进行概述性说明。
一 如何从txpool选出交易来进行执行
假设在txpool中存在A,B,C,D,E五个地址,每个地址有10条交易,矿工节点(在truechain网络中是委员会的leader节点)从txpool中取出交易执行

1) 取出每个账户nonce最低的交易组成堆
从每个账户中取出nonce值最小的交易,将这些交易按gasprice进行堆化,形成大顶堆(堆顶为gasprice最大的值),如图重点第一个箭头。
2)添加交易,重新进行堆化
每次取出堆顶元素(gasprice最大的tx),进行交易的执行,流程图中执行的是A地址中nonce=1,price =11的tx,若执行正常,将A地址中nonce=2的tx补上,重新进行堆化,将tx的gasprice最大的交易置于堆顶,继续执行。直到区块的gasLimit不够执行下一个交易,或其中某个交易执行过程中出现异常,停止交易的执行。
注:1 堆图中的数字表示tx的gasPrice,为了方便理解将txpool中的每个tx的price设置为不同的值
矿工在执行交易的过程中,先是取出每个地址中nonce最小的交易,保存到一个堆中,然后从堆取出gasprice最大的交易进行执行。选用堆作为保存当前待需执行的交易组能提高程序执行效率,因为每个新的交易进入堆中,同时从堆中选出gasPrice最大的交易的时间复杂度只有logn,而如果是用数组来保存,时间复杂度最少为nlogn。
二 交易的执行
tx的主要信息有from,to,nonce,value,gasprice,gasLimit,data,主要含义依次为交易发送者,接收者,发送者的第几笔交易,发送的token数量,愿意支付的gas价格,交易的gas消耗上限,交易包含的字节码。
1)交易执行前的有效性检查
在交易执行前需保存当前世界状态的快照,防止交易在执行过程中出现异常,进行状态的回滚。
通过交易的hash和发送者签名信息得到发送者地址,比较发送者的nonce值是否关联到tx的nonce,tx.nonce =sender.nonce
判断交易消耗的gas是否不超过gasLimit,tx.gas0 <=tx.gasLimit
判断发送者已有的余额是否超过消耗的gas上限,sender.balance >= gasPrice * gasLimit
判断到此交易为止,交易消耗的gas是否超过了区块指定的gasLimit,block.gasUsed+tx.gas0 <= block.gasLimit
注:gas0,可以理解为你的合约编译之后,由编译器给出的某个函数调用的 gas estimation,就是预估的消耗。
2)不可撤销的状态修改
sender.nonce +=1
sender.balance -=tx.gas0*tx.gasPrice
无论交易在执行过程中是否出现异常,发送者nonce值和balance进行的状态修改不会发生撤销。
3)交易的执行

不管是合约创建还是消息调用,tx是基于EVM来执行的,EVM执行交易的过程中必定结束于一个正常或异常的终止,但无法用代码产生异常终止,它必定来自于某些特定的条件,如:“out of gas ”,"stack overflow"等。
关于交易在EVM执行的具体细节在本篇就不展开细说,将在下篇文章中展开说明,包括EVM的执行模型和存储结构。
网友评论