Web3获取交易收据:如何等待变量赋值,避免TransactionNotFound报错
我写了一段代码用来等待加密货币交易成功后的收据并提取数据,但实时运行时程序会崩溃——因为交易提交后,交易哈希transaction_tx不会立即被链上节点查到,需要几秒时间。目前我是让程序固定sleep 10秒,但想找个更靠谱的方法,能一直等到receipt变量成功赋值。当前获取收据的代码为:
receipt = web3provider.eth.getTransactionReceipt(transaction_tx)
我对async/await理解不足,觉得它不适用这种等待变量赋值的场景,想到的方案是用try-catch捕获错误,配合time.sleep(1)循环重试。请问这个方案可行吗?有没有更优的实现方式?
附相关Python代码:
import json from ast import literal_eval import time from web3 import Web3 bsc = 'https://bsc-dataseed.binance.org/' web3provider = Web3(Web3.HTTPProvider(bsc)) def getTradedAmount(tokenAddress, transaction_tx): time.sleep(10) receipt = web3provider.eth.getTransactionReceipt(transaction_tx) tx_json = Web3.toJSON(receipt) json_obj = json.loads(tx_json) log = json_obj['logs'] length = len(log) for t in range(length): dec = literal_eval(log[t]['data']) if log[t]['address'] == tokenAddress: amountData = log[t]['data'] print(amountData) tx = "0x76094c8541e318fd2fa4479d48184cd66323d63fd889a3f30b973242f55eabbe" token ="0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56" #transaction_tx = buy(tokenAddress, 0.001) getTradedAmount(token, tx)
报错信息:
web3.exceptions.TransactionNotFound: Transaction with hash: '0xfb0460c094b55f718fdf9b7fc49087d6586bfbc4886fd64e01f5eee4d11d48d5' not found.
你的方案完全可行
try-catch配合循环重试是链上开发中等待交易确认的常规操作,比固定sleep 10秒灵活得多——既不会浪费时间等待不必要的时长,也能应对网络波动导致的交易延迟。
优化后的手动重试实现
给重试逻辑加上次数上限,避免无限循环,同时简化日志解析步骤:
import json from ast import literal_eval import time from web3 import Web3 from web3.exceptions import TransactionNotFound bsc = 'https://bsc-dataseed.binance.org/' web3provider = Web3(Web3.HTTPProvider(bsc)) def getTradedAmount(tokenAddress, transaction_tx, max_retries=30, retry_interval=1): receipt = None # 循环重试,最多等30秒 for _ in range(max_retries): try: receipt = web3provider.eth.getTransactionReceipt(transaction_tx) break except TransactionNotFound: time.sleep(retry_interval) if not receipt: raise ValueError(f"交易 {transaction_tx} 超时未确认") # 直接遍历receipt的logs(无需转JSON解析,web3返回的已是字典) for log in receipt['logs']: if log['address'] == tokenAddress: amountData = log['data'] print(amountData) return amountData raise ValueError(f"未找到与代币 {tokenAddress} 相关的交易日志") tx = "0x76094c8541e318fd2fa4479d48184cd66323d63fd889a3f30b973242f55eabbe" token ="0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56" getTradedAmount(token, tx)
更优的内置工具方案
web3.py本身提供了专门等待交易收据的函数wait_for_transaction_receipt,比自己写循环更简洁可靠:
from web3 import Web3 from web3.exceptions import TransactionNotFound bsc = 'https://bsc-dataseed.binance.org/' web3provider = Web3(Web3.HTTPProvider(bsc)) def getTradedAmount(tokenAddress, transaction_tx): # 等待交易确认,默认最多等60秒,每1秒查询一次 receipt = web3provider.eth.wait_for_transaction_receipt( transaction_tx, timeout=60, poll_latency=1 # 可选:指定等待的区块确认数,比如confirmations=2,更稳妥 ) for log in receipt['logs']: if log['address'] == tokenAddress: amountData = log['data'] print(amountData) return amountData raise ValueError(f"未找到与代币 {tokenAddress} 相关的交易日志") tx = "0x76094c8541e318fd2fa4479d48184cd66323d63fd889a3f30b973242f55eabbe" token ="0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56" getTradedAmount(token, tx)
这个函数的优势:
- 内置重试逻辑,无需手动写循环
- 可自定义超时时间、查询间隔
- 支持指定等待的区块确认数,进一步保证交易的最终性
关于async/await的说明
如果你的项目是异步架构(比如使用AsyncHTTPProvider),async/await完全适用,web3.py提供了异步版本的async_web3,可以用await web3.eth.wait_for_transaction_receipt(tx_hash)实现异步等待。但如果是同步代码,用上面的同步方案就足够了。
内容的提问来源于stack exchange,提问作者Soma Juice

