DavidCai1111 / my-blog

:book:My blog
https://DavidC.ai
MIT License
271 stars 24 forks source link

以太坊黄皮书公式解析(中) #54

Open DavidCai1111 opened 2 years ago

DavidCai1111 commented 2 years ago

前言与版本

笔者最近在结合以太坊黄皮书以太坊源码,结合自己的理解解析下黄皮书内的公式,与大家共同学习进步,若大家在阅读以太坊黄皮书时,对公式产生理解上的困惑,可以参阅本文一起看。文章基于当前(2022/1/10)的黄皮书,版本号为 BERLIN VERSION fabef25 ,若有不准确之处,欢迎指出。由于该黄皮书内除附录外有 183 个公式,为了让文章篇幅不过长,该解析会由三部分组成一个系列,每个系列解析约 60 个公式,本文为中篇。

公式解析

(61) (62) (63)

公式 (61) 定义了一个交易的起始状态,即会被扣除预付款(公式(62)),并且 nonce + 1 (公式(63))。

(66)

公式 (66) 定义了 g 为交易的 GasLimit 减去执行交易的基本费用。

(64) (65)

公式 (64) 表达了交易后的临时状态 σp,根据是合约创建还是普通交易,而又不同的入参。公式 (65) 定义当前入参子状态是公式 (55) 中定义的空子状态中各值与当前交易子状态中各值的与集(and)。

(67)

公式 (67) 表示,在交易过程中,调用者若有通过调用 selfdestruct(addr); 销毁合约,则合约内的以太币会累计到退还余额中。

(68)

公式 (68) 定义了总退还 Gas 数量的计算,与执行交易后剩余 Gas 数量 g' ,执行合约花费的 Gas 数量 (Tg - g')和销毁合约退还数量 A'r 相关。

(69) - (72)

公式 (69) - (72) 定义了从交易临时中间状态到预备最终状态的转换。首先在交易者的余额中加上应退还的数量(公式(70))。在矿工的余额中加上消耗的以太币数量(公式(71))。并将矿工收益记录在区块的 beneficiary 值上(公式(72))。

(73) - (75)

公式 (73) - (75) 定义了交易从预备最终状态到最终状态的转换。会先删除需要自毁的合约(公式(74)),再删除接触到的死合约(公式(75)),死合约的定义在公式 (15)。

(76) - (78)

公式 (76) - (78) 给出了三个交易相关状态的定义。

(79)

公式 (79) 定义了创建合约时的参数 salt 是可选的,若提供 slat,需要是一个长度为 32 的字节。

(80)

公式 (80) 给出了创建合约函数的定义(输入,输出)。

(81) - (83)\

公式 (81) - (83) 为合约地址的产生规则。首先定义了函数 LA ,若未提供 salt ,则输出 n 与 s 的 RLP 编码结果,否则输出 (255) · s · ζ · KEC(i)(公式(83)),这也意味着同一个账户,对于同一个合约代码,可以创建可预见的合约地址。然后将 LA 的输出结果经过 Keccak-256 哈希后,取右边 160 位(公式(82))即可得到地址(公式(82))。公式 (81) 则是描述了需带入的实际参数。

(84)

公式 (84) 则表示新创建的合约地址,会被存入 Aa 交易子状态中(于公式 (54) 中定义)。

(89)

公式 (89) 定义了 v' ,若地址在之前就有余额,则会继承。

(85) - (88)

公式 (85) 定义了新的世界状态,在创建的地址上会出现一个新的合约,nonce 为 1, 余额为 v' 加上创建交易传入的以太币,以及空的 storageRoot 和 codeHash (公式(86))。创建者的地址上会扣除发送的以太币(公式(88)),然后保存其状态(公式(87))。

(90)

公式 (90) 定义了初始化代码执行函数的输入与输出。

(91) - (99)

公式 (91) - (99) 定义了参数 I 所包含的项。

(100)

公式 (100) 表示合约创建开销,与合约代码大小成正比。

(101) - (105)

公式 (105) 定义了创建失败的一些场景:原地址不为空,且有 codeHash 或有 nonce;创建合约代码为空;gas 费不足;代码过大;

公式 (104) 定义了状态码 z ,如果创建失败,则为 0 ,成功则为 1 。

公式 (102) (103) 定义了,若创建失败,则不更新状态和子状态。

公式 (101) 定义了若创建失败,则不会收取代码创建开销。

(106)

(107)

公式 (107) 定义了 a1 这个交易中的第一个临时状态:除非发送者和接收者是同一个地址,否则跟随交易发送的以太币(msg.value)会被发送。

(108) - (113)

公式 (108) - (113) 描述的是公式 (107) 的具体流程。如果账户 a1[r] 是一个新地址,则会对账户进行状态初始化(公式(112)),并且在余额中加上交易转入的以太币(公式(113)),然后更新到临时状态(公式(111))。相应地,在发送人那边也减少对应的以太币(公式(110)),更新临时状态(公式(108))。

(114) - (128)

公式 (118) 定义了执行消息调用函数 Ξ ,将会输出 σ (执行后世界状态),g(执行后剩余 Gas),A(执行后子状态码)和 o (调用结果输出(output))。公式 (127) 描述了定义在地址 1 - 8 上的预留函数(参阅黄皮书附录 E),以及常规执行函数。公式 (120) 表达了客户端在部署完合约后,会在本地存储交易调用代码的地址及其哈希。公式 (114) - (117) 则表达了会根据 Ξ 函数输出的 σ (执行后世界状态)是否为空来判断是否要用 Ξ 函数的其他输出来更新自身对应状态。

(129)

公式 (129) 定义了公式 (127) 中的地址集合为 π 。