交易验证
交易执行前,首先需要进行交易验证,这个过程包括:
- 交易的 RLP 编码正确且尾部没有多余的字节。
- 交易签名验证。
- 交易的
nonce
个发送方的当前 nonce
相同。
gaslimit
不小于交易执行的 gas g0。
- 交易发送方的余额满足预先支付金额要求。
上面的 g0 表示交易执行需要提前支付的 gas 的数量(注意只是提前预支的,最终实际使用的数量要看交易执行情况),其中包括三个部分:
- 交易数据
data
需要的 gas,直接根据每个字节消耗 gas,非零字节 ( 68 gas/byte ) 比零字节 ( 4 gas/byte ) 稍贵。
- 如果是创建合约的交易,需要消耗一部分创建合约的 gas (
32000 gas
)。
- 交易都会消耗一个基础的 gas (
21000 gas
)。
g0≡i∈Ti,Td∑{GtxdatazeroGtxdatanonzeroif i=0otherwise+{Gtxcreate0if T=∅otherwise+Gtransaction
需要预先支付的金额记为 v0,在满足上面约束以后,发送方需要预先支付:
v0≡TgTp+Tv
即:
- 执行交易需要的金额上限
gaslimit * gasprice
。
- 如果有转账,还要加上转账金额 Tv。
验证过程需要满足下面条件:
S(T)σ[S(T)]Tng0v0Tg≠∅ ∧≠∅ ∧=σ[S(T)]n ∧≤Tg ∧≤σ[S(T)]b ∧≤BHl−ℓ(BR)u
即,发送方不为空、发送方的状态存在、交易的 nonce
和发送方的 nonce
相同、可能用到的 gas 数量不大于交易中声明的 gas 使用上限、发送方有足够的金额预付交易执行费用等。这里特别说明一下最后一条 Tg≤BHl−ℓ(BR)u。
ℓ(list) 表示取 list 中的最后一个元素。
ℓ(x)≡x[∥x∥−1]
一个区块中包含多个交易,交易在打包进一个区块后,会按顺序执行每一条交易,每一条交易完成以后,都会生成一个收据 (Receipt, 用 R 表示),收据中包含了其对应的交易执行后的一些信息,包括:
- 交易完成后,交易所在区块使用的 gas 的累积量 Ru。
- 交易日志的集合 Rl。
- 交易日志对应的布隆过滤器 Rb。
- 一个非负整数表示交易执行的状态 Rz。
ℓ(BR)u 中 BR 即是目前区块中所有已经执行的交易产生的收据的集合,ℓ(BR)u 就是目前区块中最后一张收据中的 Ru 即执行当前交易前已经执行的交易使用的 gas 的累积量。
例如一个区块有 10 条交易,当前即将执行第 6 条,那么 ℓ(BR)u 可以得到前 5 条交易执行后实际消耗的 gas 数量和。
所以这里面最后一条表示的是当前交易的 gaslimit
和该条交易之前的交易使用的 gas 的和不超过交易所在区块的 gaslimit
( 代表了对区块使用 gas 数量的限制 )。
交易执行
假设交易执行前的状态为 σ,交易执行前首先进行下面操作:
- 使发送者的
nonce
加一。
- 使发送者的的余额减少交易声明的
gaslimit * gasprice
( TgTp )。
这部分操作是不可逆的。假设这部分操作后的状态为 σ0,则有:
σ0σ0[S(T)]bσ0[S(T)]n≡σ except≡σ[S(T)]b−TgTp≡σ[S(T)]n+1
接着就进行交易的执行,以太坊有两种交易类型:
- 合约创建 (
contract creation
),使用 Λ 函数表示。
- 消息调用 (
message call
),使用 Θ 函数表示。
交易执行会得到下面返回值:
- 执行完交易后的状态 σP。
- 执行完交易后的剩余 gas g′。
- 交易执行后的子状态 A。
- 返回码 z。
这里介绍一个交易执行的子状态 A,它表示一个交易执行后的一些信息。包括下面几个部分:
- 一个集合,表示交易结束后会丢弃的账户们。As
- 执行日志集合。Al
- 创建账户集合,其中的空账户在交易后会被删除。At
- 执行交易后可退还的 gas,Ar,这部分通过
SSTORE
指令将一个非零的存储值 ( storage value
) 置为零产生,每次这样的操作返还 Rsclear=15000 gas。
执行之后
执行后,首先会对每个丢弃的账户向 Ar 中增加丢弃一个账户的 gas 收益:
Ar′≡Ar+i∈As∑Rselfdestruct
其中 Rselfdestruct=24000。
此时,需要对剩余的 gas 进行退还,剩余的 gas 包括两部分,一部分是执行交易以后剩余的 gas g′ 另一部分是存储值归零返还的 gas Ar′。退还的部分记为 g⋆,则有:
g⋆≡g′+min{⌊2Tg−g′⌋,Ar′}
g⋆ 根据 gasprice
返还给交易发起方,交易的 gaslimit
中的剩余部分都作为奖励给予挖出当前区块的矿工,这一步完成后的临时状态记为 σ⋆,则有:
σ⋆σ⋆[S(T)]bσ⋆[m]bm≡σPexcept≡σ[S(T)]b+g⋆Tp≡σP[m]b+(Tg−g⋆)Tp≡BHc
最后删除无用的账户到达交易完成后的最终状态 σ′。无用的账户包括所有的丢弃的账户和创建的空账户:
σ′∀i∈As:σ′∀i∈At:σ′≡σ⋆ except=∅=∅ if DEAD(σ⋆,i)