EIP2929和EIP2930

EIP2930是第一个在EIP2718的基础上,引入的交易类型。

自从有了2718,在以太坊中增加新的交易类型就简单了,目前以太坊中有三种交易类型:

const (
    LegacyTxType = iota    
    AccessListTxType    
    DynamicFeeTxType
)

其中EIP2930对应就是AccessListTxType。本文简要描述EIP2930的作用。

TL;DR

state access code消耗的gas非常便宜,导致以太坊容易早上攻击,因此EIP2929提高state初始访问(cold access)的gas费,同时引入了缓存机制,降低了后续访问(warm access)state的gas费。

EIP2929带来的问题之一是contract breakage,导致部分在合约中硬编码了gas费的合约不可用。

EIP2930修正了contract breakage问题,可以在tx中指定合约需要访问的state,evm在执行tx之前会打折预加载对应的state,后续对state的访问属于warm access,减少EIP2929带来的cold access问题。

EIP2929

EIP2930是对EIP2929打的补丁。

以太坊中合约的状态存储在磁盘中,每次读取都需要消耗一定的gas费,这些读取操作叫做state access code。问题是,state access code的gas费非常便宜。

在2016年的上海DOS攻击中,其中几个攻击的手法就是透过恶意交易大量读取帐户资讯、大量的创造合约再销毁,或是不断用 EXTCODESIZE 来读合约大小等等,让Client必须花大量的IO资源处理交易(需要读写disk的动作特别慢)。

EIP2929的思路就是提高state access code的gas消耗,比如以前读取一次state,消耗gas 800,现在提升到2100,提高了攻击成本。但是提高gas消耗对普通用户不利,因此EIP2929中引入了缓存机制,第一次读取状态,叫做cold access,收取2100,读取的状态缓存起来,后续再读取,叫做warm access,只需收取100,读区的次数越多,消耗的gas反而便宜了。

就相当于天冷了发动机第一次启动不太容易,启动后再重启就容易多了。

其中读取的状态缓存在以下存储中:

  • accessed_addresses。缓存合约地址
  • accessed_storage_keys。缓存合约数据

EIP2929的引入,会引起部分合约的gas费增高。对于普通用户还好,但以太坊中存在大量的合约调用合约,比如A合约代码中,调用了B合约,开发者往往会硬编码写死调用B合约的gas费。

这样就带来了麻烦,EIP2929的引入,比如原本B合约需要800gas,现在变成了2100gas,而A代码已经写死了B合约的调用费用为800gas,会导致B合约调用的失败,进而导致已经部署的A合约不可用,这种情况叫做contract breakage。

于是就诞生了EIP2930,缓解这种情况,叫做Contract breakage mitigation。

EIP2930

EIP2930目的是为了在Tx执行之前,预先执行cold access。解决contract breakage问题。

EIP2930新增了一种Tx类型,其中包含AccessList字段:

type AccessListTx struct {
    ChainID    *big.Int        // destination chain ID
    Nonce      uint64          // nonce of sender account
    GasPrice   *big.Int        // wei per gas
    Gas        uint64          // gas limit
    To         *common.Address `rlp:"nil"` // nil means contract creation
    Value      *big.Int        // wei amount
    Data       []byte          // contract invocation input data
    AccessList AccessList      // EIP-2930 access list
    V, R, S    *big.Int        // signature values
}

传统的Tx在执行过程中,根据实际操作执行扣除gas费。而AccessList内部包含了accessed_addresses和accessed_storage_keys,说明本Tx可能会涉及到读取哪些合约,以及合约状态。那么系统在执行Tx之前,预先把指定的状态读取出来,缓存起来,然后再正常执行Tx,执行过程中需要扣费的话,属于warm access,费用就降低了。

还是前面A合约调用B合约的例子,假设A合约在引入EIP2929之前就部署在了以太坊上,其中调用了B合约,B合约会从存储中读取状态S1,消耗800gas,于是A合约中有如下一段伪代码:

callContractB(800)

即在A合约中,硬编码了800 gas来调用B合约。

那么,在引入EIP2929之前,读取S1的gas固定为800,tx执行为步骤为:

  1. 用户发送调用A合约的tx, gas limit为3000(或者任何大于800的值)。
  2. EVM开始执行tx。
  3. A合约调用B合约,发送800gas。
  4. B合约从存储中读区状态S1,消耗800gas。执行成功。
  5. A合约执行成功。总消耗gas: 800,返回用户gas: 3000-800=2200。

引入EIP2929之后,读取S1的gas发生变化:cold access为2100,warm access为100。tx执行步骤为:

  1. 用户发送调用A合约的tx, gas limit为3000。
  2. EVM开始执行tx。
  3. A合约调用B合约,发送800gas。
  4. B合约从存储中读区状态S1,消耗2100gas(cold access)。执行失败。
  5. A合约执行失败。

可以看到,虽然用户设置了gas为3000,大于B合约需要的2100,但由于硬编码的缘故,A只给了800gas调用B,导致合约调用失败。而且这样的合约在链上大量存在。毕竟,当初A合约创建的时候,并没有EIP2929。

于是引入EIP2930,读取S1的gas依然为:cold access为2100,warm access为100,tx执行步骤为:

  1. 用户发送调用A合约的tx, gas limit为3000。并且在Tx的AccessList中指定了要访问的状态S1。
  2. EVM执行tx之前,预先往缓存中加载了S1,扣除gas 1900(没错,扣除1900,而不是2100,因为通过EIP2930的方式加载缓存比直接cold access更便宜)
  3. A合约调用B合约,发送800gas。
  4. B合约从存储中读区状态,消耗100gas(此时属于warm access,只需要100,而不是2100)。执行成功。
  5. A合约执行执行成功。总消耗gas: 1900+100=2000。返回用户gas:3000-1000=2000。

总结

  • EIP2919提高了state access code的初始访问费用,降低了多次访问费用。
  • EIP2930缓解了EIP2919带来的Contract breakage问题。

Ref



《 “EIP2929和EIP2930” 》 有 8 条评论

  1. The outer diameter at 5 mmHg was used instead of 0 mmHg to avoid the arteries collapsing dapoxetina generico Signs and risk factors for bladder spasms

  2. best site to buy priligy Upon phosphorylation, STAT3 forms a homodimer which translocates into the nucleus to bind to the promotor region of target genes and activates target gene transcription

  3. comment without information

回复 priligy 60 mg review 取消回复

您的邮箱地址不会被公开。 必填项已用 * 标注

About Me

一位程序员,会弹吉他,喜欢读诗。
有一颗感恩的心,一位美丽的妻子,两个可爱的女儿
mail: geraldlee0825@gmail.com
github: https://github.com/lisuxiaoqi
medium: https://medium.com/@geraldlee0825