以太坊技术黄皮书学习笔记12:智能合约的创建
在以太坊的协议中,我们使用的钱包账号和智能合约都属于account的,因此合约的创建也属于账号的创建。符号6定义了一个合约创建函数,函数的输入表示
7:函数执行前的全局状态,
8:交易的发送者
9:最原始的交易的发起者
10:可用的gas
11:gas的价格
12:转移给新账户(合约)的账,
13:字节序列,表示合约的代码
14:当前消息调用或者创建合同的协议栈的深度
15:该标志下节再详细讲解。
函数的输出结果是:
1, 修改后的状态,
2, 剩余的gas
3, 交易的子状态集合
4, 状态码
5, 错误日志
新创建的合约地址16是根据发送者和发送者全局状态的nonce减1进行的KEC运算的出来的,注意运算17,减1表示当前账号的创建会是的S的nonce增加,因此账号的创建应该与状态修改前的nonce有关。
合约创建也是分步骤的,就像交易的创建也是分了很多子状态去处理,合约的创建也进行了细分,例如公式19表示的是状态迁移的第一步做了如下修改:
20:新建的账号的全局状态:nonce是1,表示新建的账号,balance表示发送者的转账额度加上自己账号之前的余额,因为是创建账号的第一步,因此数据存储的Merkle树根是空集合的TIRE运算结果,代码的Hash值也是空集的hash值
25:发送者的全局状态:如果发送者的余额已经为0并且发送者在函数执行前的全局状态是个空集合,那么发送者的新状态就是一个空集合。否则,修改发送者的余额,从自己的余额中减去转发的额度。
初始的状态准备好之后,通过以太坊虚拟机代码(符号13)的执行,根据一定的运行模型,为新创建的账号执行创建存储空间,计算代码的hash值等操作。符号31表示执行代码的函数,公式29表示执行创建代码之后的状态,公式30表示执行代码消耗掉gas之后的余额,公式32是执行的环境参数,其具体内容如公式35所示,其意义很多已经在签名的章节中解释过,这里不再重复解释,在后面的虚拟机执行模型中会有详细的公式定义。
在这个运算函数31执行的过程中,会消耗gas,如果gas在消耗完之后仍然没有执行完所有的代码,则状态不会发生最终的迁移,但是消耗的gas不再返还。如果允许执行完成,那么函数31消耗的gas总量如公式33所示,其值取决于代码的长度,公式34表示创建合约的代码的大小。
如果状态迁移顺利完成,那么我们就会最后得到新的状态并保存最新的状态。公式37表示最终的创建完成时的状态,公式38表示剩余的燃料,如果公式44满足条件,则没有剩余gas,公式44表示燃料耗尽的条件,45表示中间状态是空集合并且账号的代码体为空集合,46表示剩余的gas不足以支撑所有代码执行成本,公式47表示代码长大小超过24576这个最大值。如果44不满足,则剩余gas从状态准备时剩余的gas减去代码执行消耗的gas值
公式39表示创建合约的结果状态,40表示燃料耗尽异常时状态不发生变化。公式41表示最终状态与某中间状态相等,只是当中间状态下的新建账号是个DEAD类型的账号,则最终全局状态下新建账号的状态是空集合
43表示状态执行的状态码,如果中间状态是空集合或者gas燃料耗尽,状态码为0否则为1.
需要注意的是,当智能合约(账号)在生成地址,即公式16执行完成后,在执行创建合约代码之前,合约的地址是有效的但是存储和codehash还没有创建,此时如果给真个地址转移以太币,则其行为是未知的,此时往往表示代币被永久锁住无法再被使用。