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

如何通过web3.py获取Solidity合约调用函数时的事件数据?

使用web3.py捕获Solidity合约事件数据的完整方案

嘿,我来帮你搞定这个问题!首先先修正你的Solidity合约(补全了pragma后面的分号,不然编译会报错):

pragma solidity ^0.4.17;
contract Test {
    event greeting(string name);
    function say() pure public {
        greeting('jack');
    }
}

接下来咱们完善你的web3.py代码,实现捕获greeting事件里的'jack'数据。我会把完整代码写出来,再一步步解释关键部分:

from web3 import Web3
import time

# 初始化web3连接,这里以本地Ganache节点为例,根据你的实际节点修改
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:7545'))

# 合约地址和ABI(确保ABI和你编译合约得到的完全一致)
contractAddress = '0x345ca3e014aaf5dca488057592ee47305d9b3e10'
abiJson = {
    "abi": [
        {
            "anonymous": False,
            "inputs": [{"indexed": False, "name": "name", "type": "string"}],
            "name": "greeting",
            "type": "event"
        },
        {
            "constant": True,
            "inputs": [],
            "name": "say",
            "outputs": [],
            "payable": False,
            "stateMutability": "pure",
            "type": "function"
        }
    ]
}

# 实例化合约对象
contract = w3.eth.contract(address=contractAddress, abi=abiJson['abi'])
accounts = w3.eth.accounts

# 处理事件的函数:这里提取事件中的name参数
def handle_event(event):
    # 直接从event的args里取name,就是我们要的'jack'
    captured_name = event['args']['name']
    print(f"成功捕获greeting事件!传递的name值是:{captured_name}")
    # 如果想查看完整事件结构,可以取消下面的注释
    # print("完整事件详情:", event)

# 事件监听循环:持续轮询获取新事件
def log_loop(event_filter, poll_interval):
    while True:
        # 获取所有新增的事件条目
        for event in event_filter.get_new_entries():
            handle_event(event)
        # 每隔指定秒数轮询一次,避免频繁请求节点
        time.sleep(poll_interval)

# 创建greeting事件的过滤器,从最新区块开始监听
event_filter = contract.events.greeting.create_filter(fromBlock='latest')

# 启动监听循环,这里设置每隔2秒轮询一次
log_loop(event_filter, 2)

关键部分解释:

  1. 事件过滤器创建:contract.events.greeting.create_filter(fromBlock='latest') 指定监听greeting事件,并且只关注最新区块之后的事件。你也可以指定具体区块号,比如fromBlock=123456。
  2. 事件数据提取:在handle_event函数里,event['args']['name']直接对应Solidity事件中定义的name参数,也就是触发事件时传入的'jack'。
  3. 触发事件(可选):如果需要主动调用say()函数来触发事件,可以添加这段代码(放在启动循环之前):
    # 调用say函数触发事件,用第一个账户发送交易
    tx_hash = contract.functions.say().transact({'from': accounts[0]})
    # 等待交易上链,确保事件被记录
    w3.eth.wait_for_transaction_receipt(tx_hash)
    print("交易已上链,事件已触发!")
    

注意事项:

  • 确保你的web3节点连接正常,比如Ganache、Infura或者本地Geth节点。
  • ABI必须和你编译Solidity合约后得到的ABI完全一致,不然无法正确解析事件。
  • 如果是在公网测试链或主网,要确保发送交易的账户有足够的Gas费(虽然say()是pure函数,但发送交易仍需要Gas来记录事件日志)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:09:40