Q1ngying

今朝梦醒与君别,遥盼春风寄相思

0%

EIP-1167:ERC-1167最小代理合约

ERC-1167:最小代理合约

原文章:https://eips.ethereum.org/EIPS/eip-1167

简要说明:为了以简单且廉价的方式在不可变的情况下克隆合约功能,该标准规定了一种最小字节码实现,将所有调用委托给了一个已知的固定地址。

摘要

通过在已知的最小字节码重定向实现上进行标准化,该标准允许用户和第三方工具(例如:etherscan)简单地发现一个合约将始终以已知方式重定向,并依赖于目标合约中代码的行为作为重定向合约的行文。具体而言,工具可以查询重定向地址处的字节码,以确定将运行的代码位置,并且可以依赖于关于该代码的表示(经过验证的源代码、第三方审计等)。此实现将所有调用和 100% 的 gas 转发到实际合约,然后将返回值传递回调用者。在实施出现还原时,还会传递回还原与有效负载数据(用于带有消息的还原)

动机

该标准支持这样一种情况,即希望在最小化副作用(例如内存槽覆盖)和低 Gas 成本部署重复合约的情况下克隆精确合约功能

规范:

标准克隆合约的确切字节码如下:363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3 ,其中索引10 - 29(包括 10 和 29)的字节被替换为实际合约的 20 个字节地址。

可以在optionlity/clone-factory github 仓库中找到此项参考的实现

原理

这一努力的目标是:

  • 廉价部署(低 Gas 用于部署 clons)
  • 支持在创建交易中初始化 clones (通过工厂合约模型)
  • 简单的克隆字节码,以鼓励直接进行字节码查询(参考 clone-factory 项目中的 CloneProbe.sol)
  • 可靠、锁定行为 - 这不是设计用于处理升级性问题,也不应该如此,因为我们正在寻求更强大的表示
  • 小操作开销 - 每次调用都会增加一个调用成本
  • 处理回滚消息返回错误

向后兼容性

没有向后兼容性问题。可能有一些系统正在使用早期版本的代理合约字节码。它们将不符合此标准。

测试案例

测试案例包括:

  • 无参数调用

  • 带参数调用

  • 具有固定长度返回值的调用

  • 具有可变长度返回值的调用

  • 具有回滚的调用(确认已转移回滚有效载荷)

  • 这些案例的测试包含在参考实现项目中。

实施

部署字节码不包括在此规范中。代理合约参考实现中定义了一种方法。

开始代理

标准部署的代理合约代码的反汇编(从r2中提取并编辑以包含堆栈可视化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|           0x00000000      36             calldatasize          cds
| 0x00000001 3d returndatasize 0 cds
| 0x00000002 3d returndatasize 0 0 cds
| 0x00000003 37 calldatacopy
| 0x00000004 3d returndatasize 0
| 0x00000005 3d returndatasize 0 0
| 0x00000006 3d returndatasize 0 0 0
| 0x00000007 36 calldatasize cds 0 0 0
| 0x00000008 3d returndatasize 0 cds 0 0 0
| 0x00000009 73bebebebebe. push20 0xbebebebe 0xbebe 0 cds 0 0 0
| 0x0000001e 5a gas gas 0xbebe 0 cds 0 0 0
| 0x0000001f f4 delegatecall suc 0
| 0x00000020 3d returndatasize rds suc 0
| 0x00000021 82 dup3 0 rds suc 0
| 0x00000022 80 dup1 0 0 rds suc 0
| 0x00000023 3e returndatacopy suc 0
| 0x00000024 90 swap1 0 suc
| 0x00000025 3d returndatasize rds 0 suc
| 0x00000026 91 swap2 suc 0 rds
| 0x00000027 602b push1 0x2b 0x2b suc 0 rds
| ,=< 0x00000029 57 jumpi 0 rds
| | 0x0000002a fd revert
| `-> 0x0000002b 5b jumpdest 0 rds
\ 0x0000002c f3 return

注意:为了尽可能减少燃气成本,上述字节码依赖于 EIP-211 规范,在调用框架内的任何调用之前,returndatasize 返回零。returndatasize dup* 使用更少的燃气。

虚拟地址优化

通过在以前导零字节开头的虚荣合约部署地址上安装主合约,可以进一步优化代理部署。通过生成一个包含 Z 个前导 0 字节的主合约虚荣地址,在其地址中用 pushN(其中 N 是 20 - Z)替换 push20 操作码,您可以缩短代理字节码,并在之后跟随 N 个非零地址字节。在这种情况下,还会将回退跳转地址减少 Z。以下是一个示例,其中 Z = 4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|           0x00000000      36             calldatasize          cds
| 0x00000001 3d returndatasize 0 cds
| 0x00000002 3d returndatasize 0 0 cds
| 0x00000003 37 calldatacopy
| 0x00000004 3d returndatasize 0
| 0x00000005 3d returndatasize 0 0
| 0x00000006 3d returndatasize 0 0 0
| 0x00000007 36 calldatasize cds 0 0 0
| 0x00000008 3d returndatasize 0 cds 0 0 0
| 0x00000009 6fbebebebebe. push16 0xbebebebe 0xbebe 0 cds 0 0 0
| 0x0000001a 5a gas gas 0xbebe 0 cds 0 0 0
| 0x0000001b f4 delegatecall suc 0
| 0x0000001c 3d returndatasize rds suc 0
| 0x0000001d 82 dup3 0 rds suc 0
| 0x0000001e 80 dup1 0 0 rds suc 0
| 0x0000001f 3e returndatacopy suc 0
| 0x00000020 90 swap1 0 suc
| 0x00000021 3d returndatasize rds 0 suc
| 0x00000022 91 swap2 suc 0 rds
| 0x00000023 6027 push1 0x27 0x27 suc 0 rds
| ,=< 0x00000025 57 jumpi 0 rds
| | 0x00000026 fd revert
| `-> 0x00000027 5b jumpdest 0 rds
\ 0x00000028 f3 return

这将节省4个字节的代理合约大小(每次部署都能节省),对运行时的燃气成本没有任何影响。