You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试百万级数组Solidity合约二分查找的Gas消耗?

测试100万元素数组二分查找的Gas消耗:Foundry/Forge 方案

Foundry 完全能解决你的需求,而且相比 Hardhat 速度提升非常明显——它基于本地 EVM 执行测试,没有 JS 层的通信开销,百万级数据的填充和测试效率远超 Hardhat。以下是具体实现方案:

核心思路

  1. 编写带有序数组存储和二分查找的目标合约
  2. 用 Foundry 的 Solidity 测试脚本,要么模拟真实交易分步存入数据,要么直接操作合约存储快速填充数组
  3. 在测试中直接计算二分查找的 Gas 消耗

实现步骤

1. 目标合约示例

先写一个包含数组存储和二分查找的合约(假设元素是按顺序存入的,符合二分查找的前置条件):

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SortedArray {
    uint256[] public elements;

    // 模拟外部交易存入元素
    function addElement(uint256 element) external {
        elements.push(element);
    }

    // 二分查找实现
    function binarySearch(uint256 target) external view returns (bool found, uint256 index) {
        uint256 left = 0;
        uint256 right = elements.length - 1;

        while (left <= right) {
            uint256 mid = left + (right - left) / 2;
            uint256 midElement = elements[mid];

            if (midElement == target) {
                return (true, mid);
            } else if (midElement < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return (false, type(uint256).max);
    }
}

2. Foundry 测试脚本

方案一:模拟真实交易分步存入

完全还原「不同交易逐步存入」的场景,用 vm.prank 模拟不同地址发起交易:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "../src/SortedArray.sol";

contract SortedArrayTest is Test {
    SortedArray public sortedArray;

    function setUp() public {
        sortedArray = new SortedArray();
    }

    function testBinarySearchGas() public {
        uint256 totalElements = 1_000_000;
        // 模拟100万次不同地址的存入交易
        for (uint256 i = 0; i < totalElements; i++) {
            vm.prank(address(uint160(i)));
            sortedArray.addElement(i);
        }

        // 测试查找中间元素(二分查找的典型场景)
        uint256 target = 500_000;
        uint256 gasBefore = gasleft();
        (bool found, uint256 index) = sortedArray.binarySearch(target);
        uint256 gasUsed = gasBefore - gasleft();

        assertTrue(found);
        assertEq(index, target);
        console.log("Binary search gas used for 1M elements:", gasUsed);
    }
}

方案二:快速填充数组(跳过交易模拟)

如果只关注二分查找的 Gas 消耗,不需要模拟存入交易的开销,可以直接操作合约存储快速填充:

function testBinarySearchGasFast() public {
    uint256 totalElements = 1_000_000;
    // 直接修改合约存储,设置数组长度
    bytes32 arrayLengthSlot = keccak256(abi.encode(uint256(0)));
    vm.store(address(sortedArray), arrayLengthSlot, bytes32(totalElements));

    // 批量写入数组元素
    for (uint256 i = 0; i < totalElements; i++) {
        bytes32 elementSlot = keccak256(abi.encode(uint256(0))) + i;
        vm.store(address(sortedArray), elementSlot, bytes32(i));
    }

    // 测试查找
    uint256 target = 500_000;
    uint256 gasBefore = gasleft();
    (bool found, uint256 index) = sortedArray.binarySearch(target);
    uint256 gasUsed = gasBefore - gasleft();

    assertTrue(found);
    assertEq(index, target);
    console.log("Binary search gas used (fast fill):", gasUsed);
}

3. 运行测试

执行以下命令运行测试,加上 -vv 可以看到 Gas 日志:

forge test --match-test testBinarySearchGas -vv

如果需要更详细的 Gas 报告,使用:

forge test --match-test testBinarySearchGas --gas-report

关键优势

  • 速度:Foundry 的 Solidity 测试执行速度是 Hardhat JS 测试的几十倍,百万级循环几分钟就能完成
  • 灵活:既可以模拟真实交易场景,也能快速填充数据聚焦核心测试目标
  • 精准:直接在 Solidity 测试中用 gasleft() 计算 Gas 消耗,结果准确可靠

内容的提问来源于stack exchange,提问作者David Galoyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 06:10:25