链上调用
最近看合约部署和链上调用的时候,又把 EVM 里几个概念串了一下,先简单记录。
Bytecode
Solidity 合约编译之后,最终会得到 bytecode,也就是 EVM 真正执行的字节码。
平时在区块浏览器里看到的合约代码是源码,真正部署到链上的是 bytecode。节点执行合约调用时,也是执行这段 bytecode。
Create code
部署合约时,交易里的 data 不是最终存在链上的 runtime bytecode,而是 create code。
create code 可以理解成“部署阶段要执行的代码”,它执行完之后会返回 runtime bytecode,链上最终保存的是 runtime bytecode。
所以部署合约大概是:
- 发一笔
to为空的交易。 data填入 create code。- EVM 执行 create code。
- create code 返回 runtime bytecode。
- runtime bytecode 被存到新合约地址上。
Keccak
链上很多地方都会用到 keccak256。
函数选择器就是对函数签名做 keccak256,然后取前 4 个字节:
1 | balanceOf(address) -> keccak256 -> 前 4 bytes |
合约调用时,calldata 前 4 个字节就是 selector,后面才是 ABI 编码后的参数。
合约地址也和 hash 有关系。普通 CREATE 部署出来的合约地址由部署者地址和 nonce 计算出来,CREATE2 则会用 deployer、salt、init code hash 来计算地址,所以可以提前预测合约地址。
小结
之前只知道调用合约就是调 ABI 方法,这次看下来更清楚了一点:
- 源码不是链上执行的东西,bytecode 才是。
- 部署交易里的 data 是 create code。
- 合约真正保存的是 runtime bytecode。
- 函数调用靠 keccak256 算出来的 selector 定位方法。
先记录这些,后面如果继续看 EVM 调用流程,再补 calldata、memory、storage 这些细节。