全链游戏101:预编译合约。

全链游戏101:预编合约。

什么是预编译合约?

预编译合约是以太坊虚拟机(EVM)中的一种折衷方法,用于提供更复杂的库函数,通常用于加密、散列等复杂操作。可以理解为一种特殊的合约,因为这些函数不适合编写操作码。预编译合约适用于简单但经常调用的合约,或者逻辑上固定但计算量很大的合约。预编译合约是使用节点客户端代码实现的,因此它们不需要 EVM,运行速度很快。与直接在 EVM 中运行的函数相比,预编译合约对开发人员来说成本更低。

代码中的逻辑如下图所示:

代码逻辑

在代码中,run 函数有两个分支:第一个分支根据预编译索引实例化参数以指定预编译合约;第二个分支如果不是预编译合约,则会调用 EVM。

预编译合约的瓶颈在哪里?

目前以太坊有八个预编译合约:

  1. ECRecover – 通过签名恢复对应地址
  2. SHA256 – 计算 SHA256 哈希
  3. RIPEMD160 – 计算 RIPEMD160 哈希
  4. Identity – 返回输入数据的原值
  5. ModExp – 进行模数指数运算
  6. ECAdd – 椭圆曲线点加法
  7. ECMul – 椭圆曲线点乘法
  8. ECPairing – 配对运算,验证椭圆曲线点

其中,前四个提供基础的签名和哈希等加密功能,后四个提供了与 zk-snark 相关的椭圆曲线运算。

为什么以太坊只支持了八个预编译合约?预编译合约本来是为了降低 gas 消耗的,为什么不直接将全链游戏的框架植入预编译合约中呢?

主要有以下三个原因:

  1. 过度依赖预编译合约会降低整个平台的去中心化程度。首先,预编译合约的代码需要集成在客户端节点代码中,增加了客户端的复杂性。其次,验证节点可能会过滤掉预编译合约的计算,因此大部分预编译合约的请求只能由全节点完成。目前全球以太坊全节点的数量只有4000-6000个,而验证节点有50万个,相比非预编译合约更加中心化。

  2. 新增和修改预编译合约需要进行硬分叉升级,不易灵活演进。预编译合约的支持需要进行 EIP 流程,例如,EIP-196 增加了在 alt_bn128 曲线上的 ECADD()和 ECMUL() 两个预编译合约,EIP-197 增加了在 alt_bn128 曲线上的配对运算函数。这些变动都是为了在以太坊上支持隐私,而且整个 EIP 的流程漫长而考究,等待 EIP 通过也不现实。

  3. 预编译合约之间难以进行交互和组合,扩展性差。

预编译合约在全链游戏中的角色

预编译合约可以跳过 EVM 直接通过节点执行,提高运算效率,但同时降低了全链的去中心化程度。将高频使用的游戏核心逻辑置于预编译合约中,可以优化该类游戏的性能。不同类型的游戏具有不同的关键逻辑,因此,针对某一类游戏的专用链上,预编译合约的设计可以高度优化该类型游戏的需求。在游戏迭代过程中,最高效的预编译合约组合也会逐步优化出来。