3

以太坊交易执行 ( Transaciton Execution ) 流程

 2 years ago
source link: https://nicodechal.github.io/2020/10/21/ethereum-yellow-paper-2/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

以太坊交易执行 ( Transaciton Execution ) 流程

交易执行前,首先需要进行交易验证,这个过程包括:

  1. 交易的 RLP 编码正确且尾部没有多余的字节。
  2. 交易签名验证。
  3. 交易的 nonce 个发送方的当前 nonce 相同。
  4. gaslimit 不小于交易执行的 gas g0g_0g​0​​。
  5. 交易发送方的余额满足预先支付金额要求。

上面的 g0g_0g​0​​ 表示交易执行需要提前支付的 gas 的数量(注意只是提前预支的,最终实际使用的数量要看交易执行情况),其中包括三个部分:

  1. 交易数据 data 需要的 gas,直接根据每个字节消耗 gas,非零字节 ( 68 gas/byte ) 比零字节 ( 4 gas/byte ) 稍贵。
  2. 如果是创建合约的交易,需要消耗一部分创建合约的 gas ( 32000 gas )。
  3. 交易都会消耗一个基础的 gas ( 21000 gas )。

g0≡∑i∈Ti,Td{Gtxdatazeroifi=0Gtxdatanonzerootherwise+{GtxcreateifT=∅0otherwise+Gtransaction\begin{aligned} g_0\equiv &\sum_{i\in T_\mathbf{i},T_\mathbf{d}} \left\{ \begin{array}{l} G_{txdatazero} & if\ \ i= 0 \\ G_{txdatanonzero} & otherwise \end{array} \right.\\ \\ &+ \left\{ \begin{array}{l} G_{txcreate} & if\ \ T= \emptyset \\ 0 & otherwise \end{array} \right.\\ \\ &+ G_{transaction} \end{aligned} ​g​0​​≡​​​​​​​​i∈T​i​​,T​d​​​∑​​{​G​txdatazero​​​G​txdatanonzero​​​​​if  i=0​otherwise​​​+{​G​txcreate​​​0​​​if  T=∅​otherwise​​​+G​transaction​​​​

需要预先支付的金额记为 v0v_0v​0​​,在满足上面约束以后,发送方需要预先支付:

v0≡TgTp+Tvv_0\equiv T_gT_p+T_v v​0​​≡T​g​​T​p​​+T​v​​

  1. 执行交易需要的金额上限 gaslimit * gasprice
  2. 如果有转账,还要加上转账金额 TvT_vT​v​​。

验证过程需要满足下面条件:

S(T)≠∅∧σ[S(T)]≠∅∧Tn=σ[S(T)]n∧g0≤Tg∧v0≤σ[S(T)]b∧Tg≤BHl−ℓ(BR)u\begin{aligned} S(T) &\neq \emptyset\ \wedge \\\\ \mathbf{\sigma}[S(T)] &\neq \emptyset\ \wedge \\\\ T_n &= \mathbf{\sigma}[S(T)]_n\ \wedge \\\\ g_0 &\leq T_g\ \wedge \\\\ v_0 &\leq \mathbf{\sigma}[S(T)]_b\ \wedge \\\\ T_g &\leq B_{H_l}-\ell(B_\mathbf{R})_u \end{aligned} ​S(T)​​σ[S(T)]​​T​n​​​​g​0​​​​v​0​​​​T​g​​​​​≠∅ ∧​≠∅ ∧​=σ[S(T)]​n​​ ∧​≤T​g​​ ∧​≤σ[S(T)]​b​​ ∧​≤B​H​l​​​​−ℓ(B​R​​)​u​​​​

即,发送方不为空、发送方的状态存在、交易的 nonce 和发送方的 nonce 相同、可能用到的 gas 数量不大于交易中声明的 gas 使用上限、发送方有足够的金额预付交易执行费用等。这里特别说明一下最后一条 Tg≤BHl−ℓ(BR)uT_g \leq B_{H_l}-\ell(B_\mathbf{R})_uT​g​​≤B​H​l​​​​−ℓ(B​R​​)​u​​。

ℓ(list)\ell(list)ℓ(list) 表示取 listlistlist 中的最后一个元素。

ℓ(x)≡x[∥x∥−1]\ell(\mathbf{x})\equiv\mathbf{x}[\parallel\mathbf{x}\parallel - 1] ℓ(x)≡x[∥x∥−1]

一个区块中包含多个交易,交易在打包进一个区块后,会按顺序执行每一条交易,每一条交易完成以后,都会生成一个收据 (Receipt, 用 RRR 表示),收据中包含了其对应的交易执行后的一些信息,包括:

  1. 交易完成后,交易所在区块使用的 gas 的累积量 RuR_uR​u​​。
  2. 交易日志的集合 RlR_\mathbf{l}R​l​​。
  3. 交易日志对应的布隆过滤器 RbR_bR​b​​。
  4. 一个非负整数表示交易执行的状态 RzR_zR​z​​。

ℓ(BR)u\ell(B_\mathbf{R})_uℓ(B​R​​)​u​​ 中 BRB_\mathbf{R}B​R​​ 即是目前区块中所有已经执行的交易产生的收据的集合,ℓ(BR)u\ell(B_\mathbf{R})_uℓ(B​R​​)​u​​ 就是目前区块中最后一张收据中的 RuR_uR​u​​ 即执行当前交易前已经执行的交易使用的 gas 的累积量。

例如一个区块有 10 条交易,当前即将执行第 6 条,那么 ℓ(BR)u\ell(B_\mathbf{R})_uℓ(B​R​​)​u​​ 可以得到前 5 条交易执行后实际消耗的 gas 数量和。

所以这里面最后一条表示的是当前交易的 gaslimit 和该条交易之前的交易使用的 gas 的和不超过交易所在区块的 gaslimit ( 代表了对区块使用 gas 数量的限制 )。

假设交易执行前的状态为 σ\mathbf{\sigma}σ,交易执行前首先进行下面操作:

  1. 使发送者的 nonce 加一。
  2. 使发送者的的余额减少交易声明的 gaslimit * gasprice ( TgTpT_gT_pT​g​​T​p​​ )。

这部分操作是不可逆的。假设这部分操作后的状态为 σ0\mathbf{\sigma}_0σ​0​​,则有:

σ0≡σexceptσ0[S(T)]b≡σ[S(T)]b−TgTpσ0[S(T)]n≡σ[S(T)]n+1\begin{aligned} \mathbf{\sigma}_0 &\equiv \mathbf{\sigma} \ \mathrm{except} \\\\ \mathbf{\sigma}_0[S(T)]_b &\equiv \mathbf{\sigma}[S(T)]_b-T_gT_p \\\\ \mathbf{\sigma}_0[S(T)]_n &\equiv \mathbf{\sigma}[S(T)]_n + 1 \end{aligned} ​σ​0​​​​σ​0​​[S(T)]​b​​​​σ​0​​[S(T)]​n​​​​​≡σ except​≡σ[S(T)]​b​​−T​g​​T​p​​​≡σ[S(T)]​n​​+1​​

接着就进行交易的执行,以太坊有两种交易类型:

  1. 合约创建 ( contract creation ),使用 Λ\LambdaΛ 函数表示。
  2. 消息调用 ( message call ),使用 Θ\ThetaΘ 函数表示。

交易执行会得到下面返回值:

  1. 执行完交易后的状态 σP\mathbf{\sigma}_Pσ​P​​。
  2. 执行完交易后的剩余 gas g′g'g​′​​。
  3. 交易执行后的子状态 AAA。
  4. 返回码 zzz。

这里介绍一个交易执行的子状态 AAA,它表示一个交易执行后的一些信息。包括下面几个部分:

  1. 一个集合,表示交易结束后会丢弃的账户们。AsA_\mathbf{s}A​s​​
  2. 执行日志集合。AlA_\mathbf{l}A​l​​
  3. 创建账户集合,其中的空账户在交易后会被删除。AtA_\mathbf{t}A​t​​
  4. 执行交易后可退还的 gas,ArA_rA​r​​,这部分通过 SSTORE 指令将一个非零的存储值 ( storage value ) 置为零产生,每次这样的操作返还 Rsclear=15000R_{sclear} = 15000R​sclear​​=15000 gas。

执行后,首先会对每个丢弃的账户向 ArA_rA​r​​ 中增加丢弃一个账户的 gas 收益:

Ar′≡Ar+∑i∈AsRselfdestructA'_r\equiv A_r + \sum_{i\in A_s}R_{selfdestruct} A​r​′​​≡A​r​​+​i∈A​s​​​∑​​R​selfdestruct​​

其中 Rselfdestruct=24000R_{selfdestruct} = 24000R​selfdestruct​​=24000。

此时,需要对剩余的 gas 进行退还,剩余的 gas 包括两部分,一部分是执行交易以后剩余的 gas g′g'g​′​​ 另一部分是存储值归零返还的 gas Ar′A_r'A​r​′​​。退还的部分记为 g⋆g^\starg​⋆​​,则有:

g⋆≡g′+min{⌊Tg−g′2⌋,Ar′}g^\star\equiv g' + min\left\{\left\lfloor \frac{T_g-g'}2 \right\rfloor,A_r'\right\} g​⋆​​≡g​′​​+min{⌊​2​​T​g​​−g​′​​​​⌋,A​r​′​​}

g⋆g^\starg​⋆​​ 根据 gasprice 返还给交易发起方,交易的 gaslimit 中的剩余部分都作为奖励给予挖出当前区块的矿工,这一步完成后的临时状态记为 σ⋆\mathbf{\sigma}^\starσ​⋆​​,则有:

σ⋆≡σPexceptσ⋆[S(T)]b≡σ[S(T)]b+g⋆Tpσ⋆[m]b≡σP[m]b+(Tg−g⋆)Tpm≡BHc\begin{aligned} \mathbf{\sigma}^\star &\equiv\mathbf{\sigma}_P \mathrm{except} \\\\ \mathbf{\sigma}^\star[S(T)]_b &\equiv \mathbf{\sigma}[S(T)]_b+g^\star T_p \\\\ \mathbf{\sigma}^\star[m]_b &\equiv \mathbf{\sigma}_P[m]_b+(T_g-g^\star)T_p \\\\ m &\equiv B_{H_c} \end{aligned} ​σ​⋆​​​​σ​⋆​​[S(T)]​b​​​​σ​⋆​​[m]​b​​​​m​​​≡σ​P​​except​≡σ[S(T)]​b​​+g​⋆​​T​p​​​≡σ​P​​[m]​b​​+(T​g​​−g​⋆​​)T​p​​​≡B​H​c​​​​​​

最后删除无用的账户到达交易完成后的最终状态 σ′\mathbf{\sigma}'σ​′​​。无用的账户包括所有的丢弃的账户和创建的空账户:

σ′≡σ⋆except∀i∈As:σ′=∅∀i∈At:σ′=∅ifDEAD(σ⋆,i)\begin{aligned} \mathbf{\sigma}' & \equiv \mathbf{\sigma}^\star\ \ \mathrm{except} \\\\ \forall i \in A_\mathbf{s}: \mathbf{\sigma}' &= \emptyset\\\\ \forall i \in A_\mathbf{t}: \mathbf{\sigma}' &= \emptyset\ \ \ if\ \mathtt{DEAD}(\mathbf{\sigma}^\star, i) \end{aligned} ​σ​′​​​​∀i∈A​s​​:σ​′​​​​∀i∈A​t​​:σ​′​​​​​≡σ​⋆​​  except​=∅​=∅   if DEAD(σ​⋆​​,i)​​



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK