EIP7511 最小代理合约解析
时间:2023 年 9 月 9 日
作者:33357
EIP7511 优化了 EIP1167,实现了更加节省 GAS 的代理合约。提案地址:https://eips.ethereum.org/EIPS/eip-7511
想要从字节码的层面理解智能合约,就必须先了解 堆栈
、内存
、存储
、OPCODE
等概念,这里推荐 https://www.evm.codes/ 和 https://www.wtf.academy/en/evm-opcodes-101 了解。
365f5f375f5f365f73bebebebebebebebebebebebebebebebebebebebe5af43d5f5f3e5f3d91602a57fd5bf3
执行位置 | 字节码 | 操作名 | 堆栈 | 内存 | 说明 | |
---|---|---|---|---|---|
00 | 36 | CALLDATASIZE | cds | 将 calldatasize 计为 cds,并压入堆栈 | |
01 | 5f | PUSH0 | 0 cds | 将 0 压入堆栈 | |
02 | 5f | PUSH0 | 0 0 cds | 将 0 压入堆栈 | |
03 | 37 | CALLDATACOPY | calldata | 将 0 - cds 的 calldata 复制到从 0 开始的内存空间 |
执行位置 | 字节码 | 操作名 | 堆栈 | 内存 | 说明 | |
---|---|---|---|---|---|
04 | 5f | PUSH0 | 0 | calldata | 将 0 压入堆栈 |
05 | 5f | PUSH0 | 0 0 | calldata | 将 0 压入堆栈 |
06 | 36 | CALLDATASIZE | cds 0 0 | calldata | 将 calldatasize 计为 cds,并压入堆栈 |
07 | 5f | PUSH0 | 0 cds 0 0 | calldata | 将 0 压入堆栈 |
08 | 73bebe. | PUSH20 0xbebe. | 0xbebe. 0 cds 0 0 | calldata | 将 20 个字节的数据压入堆栈 |
1d | 5a | GAS | gas 0xbebe. 0 cds 0 0 | calldata | 将 gas 压入堆栈 |
1e | f4 | DELEGATECALL | suc | calldata | 将 0 - cds 的内存数据作为参数执行 0xbebe. 地址的代码,将执行是否成功计为 suc,并压入堆栈 |
执行位置 | 字节码 | 操作名 | 堆栈 | 内存 | 说明 | |
---|---|---|---|---|---|
1f | 3d | RETURNDATASIZE | rds suc | calldata | 将 returndatasize 计为 rds,并压入堆栈 |
20 | 5f | PUSH0 | 0 rds suc | calldata | 将 0 压入堆栈 |
21 | 5f | PUSH0 | 0 0 rds suc | calldata | 将 0 压入堆栈 |
22 | 3e | RETURNDATACOPY | suc | returndata | 将 0 - rds 的 returndata 复制到从 0 开始的内存空间 |
执行位置 | 字节码 | 操作名 | 堆栈 | 内存 | 说明 | |
---|---|---|---|---|---|
23 | 5f | PUSH0 | 0 suc | returndata | 将 0 压入堆栈 |
24 | 3d | RETURNDATASIZE | rds 0 suc | returndata | 将 returndatasize 计为 rds,并压入堆栈 |
25 | 91 | SWAP2 | suc 0 rds | returndata | 将堆栈第一个元素和第三个元素互换 |
26 | 602a | PUSH1 0x2a | 0x2a suc 0 rds | returndata | 将 1 个字节的数据压入堆栈 |
27 | 57 | JUMPI | 0 rds | returndata | 如果 suc 不为 0 则执行位置跳转到 2a |
29 | fd | REVERT | 返回 0 - rds 的内存数据并回滚状态 | ||
2a | 5b | JUMPDEST | 0 rds | returndata | 跳转标记 | |
2b | f3 | RETURN | 返回 0 - rds 的内存数据 |
部署合约字节码需要了解 initcode
和 runtimecode
的区别。
部署合约时会先执行 initcode
,initcode
执行后返回的结果就是 runtimecode
,真正被部署在合约上的字节码。
602c8060095f395ff3365f5f375f5f365f73bebebebebebebebebebebebebebebebebebebebe5af43d5f5f3e5f3d91602a57fd5bf3
执行位置 | 字节码 | 操作名 | 堆栈 | 内存 | 说明 |
---|---|---|---|---|---|
00 | 602c | PUSH1 2c | 2c | 将 1 个字节的数据压入堆栈 | |
02 | 80 | DUP1 | 2c 2c | 复制堆栈第一个元素并压入堆栈 | |
03 | 6009 | PUSH1 09 | 09 2c 2c | 将 1 个字节的数据压入堆栈 | |
05 | 5f | PUSH0 | 0 09 2c 2c | 将 0 压入堆栈 | |
06 | 39 | CODECOPY | 365f5f375f5f365f73be...be5af43d5f5f3e5f3d91602a57fd5bf3 | 将 09 - 2c 的 code 复制到从 0 开始的内存空间 | |
07 | 5f | PUSH0 | 0 2c | 365f5f375f5f365f73be...be5af43d5f5f3e5f3d91602a57fd5bf3 | 将 0 压入堆栈 |
08 | f3 | RETURN | 365f5f375f5f365f73be...be5af43d5f5f3e5f3d91602a57fd5bf3 | 将 0 - 2c 的内存数据返回 |
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!