链上调用

最近看合约部署和链上调用的时候,又把 EVM 里几个概念串了一下,先简单记录。

Bytecode

Solidity 合约编译之后,最终会得到 bytecode,也就是 EVM 真正执行的字节码。

平时在区块浏览器里看到的合约代码是源码,真正部署到链上的是 bytecode。节点执行合约调用时,也是执行这段 bytecode。

Create code

部署合约时,交易里的 data 不是最终存在链上的 runtime bytecode,而是 create code。

create code 可以理解成“部署阶段要执行的代码”,它执行完之后会返回 runtime bytecode,链上最终保存的是 runtime bytecode。

所以部署合约大概是:

  1. 发一笔 to 为空的交易。
  2. data 填入 create code。
  3. EVM 执行 create code。
  4. create code 返回 runtime bytecode。
  5. 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 这些细节。