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

如何通过Etherscan API批量获取Gas耗尽的以太坊合约源码?代码卡顿

问题分析与解决方法

现有代码的问题(为什么卡住无输出)

  • 缩进错误:fetch_contract_source_code函数末尾的with open代码块缩进错误,被包含在函数内部,导致主程序逻辑完全没执行,这是代码无输出的核心原因。
  • API接口用错:你调用的getLogs接口是用来获取合约事件日志的,不包含交易的status、gas、gasUsed字段,根本无法筛选因Gas耗尽失败的交易。
  • 遍历逻辑不合理:从块0开始遍历到最新块,数据量极大,免费API速率限制(5次/秒)会导致请求频繁被限制,甚至直接卡住。
  • 判断条件无效:日志条目里没有你用来判断的status和gas/gasUsed字段,这个判断逻辑永远不会触发。

修复后的代码实现

下面是修正后的代码,改用正确的API接口获取交易数据,筛选Gas耗尽的失败交易,并获取对应合约源码:

import time
import requests

# Etherscan API密钥
API_KEY = "XXXXXXXXXXXXX"
BASE_URL = "https://api.etherscan.io/api"

def make_api_request(params):
    """处理API请求,自动处理速率限制"""
    while True:
        response = requests.get(BASE_URL, params=params)
        data = response.json()
        if data.get("status") == "0":
            error_msg = data.get("result", "未知错误")
            print(f"API错误: {error_msg}")
            if "rate limit" in error_msg.lower():
                print("触发速率限制,等待2秒后重试...")
                time.sleep(2)
                continue
            else:
                return None
        return data

def fetch_contract_source(contract_addr):
    """获取合约源码"""
    params = {
        "module": "contract",
        "action": "getsourcecode",
        "address": contract_addr,
        "apikey": API_KEY
    }
    data = make_api_request(params)
    if data and data["result"]:
        return data["result"][0]["SourceCode"]
    return "合约源码不可用"

def fetch_failed_gas_exhaust_tx(start_block, end_block):
    """获取指定块范围内因Gas耗尽失败的交易"""
    params = {
        "module": "account",
        "action": "txlist",
        "startblock": start_block,
        "endblock": end_block,
        "sort": "asc",
        "apikey": API_KEY
    }
    data = make_api_request(params)
    if not data:
        return []
    
    # 筛选:交易失败(status=0)且gasUsed等于gas(Gas耗尽)
    gas_exhaust_tx = []
    for tx in data["result"]:
        if tx["status"] == "0" and tx["gasUsed"] == tx["gas"]:
            gas_exhaust_tx.append(tx)
    return gas_exhaust_tx

if __name__ == "__main__":
    # 不要从块0开始,选最近的块范围,比如最近1000个块
    start_block = 18000000
    end_block = 18001000
    output_file = "gas_exhaust_failed_tx.txt"

    with open(output_file, "w", encoding="utf-8") as f:
        current_block = start_block
        step = 100  # 每次查询100个块,避免单次请求数据过大
        
        while current_block <= end_block:
            batch_end = min(current_block + step - 1, end_block)
            print(f"正在查询块 {current_block} 到 {batch_end}...")
            
            tx_list = fetch_failed_gas_exhaust_tx(current_block, batch_end)
            if not tx_list:
                current_block = batch_end + 1
                time.sleep(0.2)  # 控制请求速率,避免触发限制
                continue
            
            for tx in tx_list:
                tx_hash = tx["hash"]
                contract_addr = tx["to"]  # 交易调用的合约地址
                f.write(f"交易哈希: {tx_hash}\n")
                f.write(f"合约地址: {contract_addr}\n")
                if contract_addr:
                    source_code = fetch_contract_source(contract_addr)
                    f.write(f"合约源码:\n{source_code}\n")
                f.write("="*50 + "\n")
            
            current_block = batch_end + 1
            time.sleep(0.2)  # 控制请求间隔

    print(f"数据已保存到 {output_file}")

其他获取数据的方法

  • 链上数据分析平台:使用支持以太坊数据查询的分析工具,通过编写类SQL语句直接筛选"交易失败且gasUsed=gas"的记录,能快速批量获取数据,无需自己写代码遍历。
  • 运行本地以太坊节点:同步全节点后,通过节点的JSON-RPC接口直接查询交易数据,不受第三方API的速率限制,但需要足够的存储空间和带宽。
  • 付费API服务:使用专业Web3 API服务,它们的速率限制远高于免费版Etherscan API,能支持更大范围的数据查询,适合获取数千条以上的记录。

内容的提问来源于stack exchange,提问作者Maryam Massoud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 10:22:47