ERC-1167: 最小代理合约
Authors | Peter Murray (@yarrumretep), Nate Welch (@flygoing), Joe Messerman (@JAMesserman) |
---|---|
Created | 2018-06-22 |
Requires | EIP-211 |
简单总结
为了以简单且廉价的方式克隆合约功能,且保证其不可变性,本标准规定了一个最小字节码实现,将所有调用委托给一个已知的、固定的地址。
摘要
通过标准化一个已知的最小字节码重定向实现,本标准允许用户和第三方工具(例如 Etherscan)(a) 简单地发现合约将始终以已知方式重定向,并且 (b) 依赖于目标合约的代码行为作为重定向合约的行为。具体来说,工具可以询问重定向地址的字节码,以确定将要运行的代码的位置——并且可以依赖于关于该代码的表示(已验证的源代码、第三方审计等)。此实现将所有调用和 100% 的 gas 转发到实现合约,然后将返回值传递回调用者。如果实现回退,则回退以及有效负载数据(用于带有消息的回退)将一起传递回去。
动机
本标准支持以下用例:期望克隆精确的合约功能,且副作用(例如,内存槽践踏)最少,并以低 gas 成本部署重复代理。
规范
标准克隆合约的确切字节码如下:363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3
,其中索引 10 - 29(包括)处的字节将替换为主功能合约的 20 字节地址。
可以在 optionality/clone-factory github 仓库中找到此规范的参考实现。
理由
这项工作的目标如下:
- 廉价部署(克隆部署的 gas 成本低)
- 支持在创建交易中初始化克隆(通过工厂合约模型)
- 简单的克隆字节码,以鼓励直接的字节码询问(请参阅 clone-factory 项目中的 CloneProbe.sol)
- 可靠的、锁定的行为 - 这不是为了处理可升级性而设计的,也不应该这样做,因为我们寻求的表示形式更强。
- 较小的运营开销 - 每次调用增加一次调用成本
- 处理回退消息的错误返回冒泡
向后兼容性
不存在向后兼容性问题。可能有些系统正在使用早期版本的代理合约字节码。它们将不符合此标准。
测试用例
测试用例包括:
- 不带参数的调用
- 带参数的调用
- 带固定长度返回值的调用
- 带可变长度返回值的调用
- 带回退的调用(确认回退的有效负载已传输)
这些案例的测试包含在参考实现项目中。
实现
部署字节码不包含在本规范中。代理合约参考实现中定义了一种方法。
标准代理
标准部署的代理合约代码的反汇编(来自 r2 并经过编辑以包含堆栈可视化)
| 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
注意:为了尽可能降低 gas 成本,上述字节码依赖于 EIP-211 规范,即 returndatasize
在调用帧内的任何调用之前返回零。returndatasize
比 dup*
少使用 1 个 gas。
靓号地址优化
通过将主合约安装到具有前导零字节的靓号合约部署地址,可以进一步优化代理部署。通过生成一个在其地址中包含 Z 个前导 0 字节的主合约靓号地址,您可以缩短代理字节码,方法是将 push20
操作码替换为 pushN
(其中 N 为 20 - Z),后跟 N 个非零地址字节。在这种情况下,回退跳转地址会减小 Z。这是一个 Z = 4 的示例:
| 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 个字节的代理合约大小(每次部署都节省),并且对运行时 gas 成本没有影响。
版权
通过 CC0 放弃版权和相关权利。
Citation
Please cite this document as:
Peter Murray (@yarrumretep), Nate Welch (@flygoing), Joe Messerman (@JAMesserman), "ERC-1167: 最小代理合约," Ethereum Improvement Proposals, no. 1167, June 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1167.