gas优化之批量处理代替单次循环

  • iszzm123
  • 发布于 8 小时前
  • 阅读 21

1、根据EVM交易/调用的固定成本每一笔外部交易都要支付21000gas的基础成本,还不包括合约调用的额外开销(CALL操作码、输入数据解码等)。如果用户需要执行10次转账,分10次发起交易,光是基础成本就高达10×21000=210000gas。批量处理只需1

1、根据EVM交易 / 调用的固定成本

每一笔外部交易都要支付21000 gas 的基础成本,还不包括合约调用的额外开销(CALL 操作码、输入数据解码等)。如果用户需要执行 10 次转账,分 10 次发起交易,光是基础成本就高达 10 × 21000 = 210000 gas。

批量处理只需 1 笔交易,直接砍掉另外 9 笔交易的基础成本,加上调用数据(calldata)只传一次的函数选择器和参数头,节省非常可观。

2、状态变量的重复读取(SLOAD 合并)

//  批量处理,缓存费率
function batchTransfer(address[] calldata to, uint[] calldata amounts) external {
    uint _feeRate = feeRate;           // 一次 SLOAD
    uint _collected = collectedFees;   // 缓存
    for (uint i = 0; i < to.length; ) {
        uint fee = _feeRate;           // 内存读
        balances[msg.sender] -= amounts[i] + fee;
        balances[to[i]] += amounts[i];
        _collected += fee;
        unchecked { ++i; }
    }
    collectedFees = _collected;        // 一次 SSTORE
}

批量处理时,可以在内存中缓存一次这些共享状态,循环内使用内存副本,最后(如有修改)统一写回一次 SSTORE。

3、减少循环的遍历次数

合并成一个循环只遍历一次,节省大量的 CALLDATALOAD/MLOAD 和边界检查。

4、事件日志的基础开销

每发出一笔 event 都要支付 375 gas 的基础费 + 每个数据字节的费用。如果原本每个操作发一个事件,批量处理后可以改为在循环中发多个事件(此时基础费仍需每事件支付),但有时可以合并成一个包含数组的复合事件,进一步省下基础费。不过后者会增加日志数据量,需要权衡。

5、跨合约调用的削减

如果业务逻辑涉及调用另一个合约(比如多次向 AMM 兑换),每次 CALL 都有 700 gas(CALL 操作码固定开销)外加地址预热、输入输出数据等。批量处理可以将多次外部合约调用合并到同一笔交易内,复用已经预热的地址(热访问),减少每个独立调用的额外开销。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
iszzm123
iszzm123
最近有应聘的意向