如何通过web3.py获取Solidity合约require抛出的错误信息
核心结论
require抛出的错误信息没有被加密存储,它是作为交易回退(revert)的返回载荷直接上链的,你在Python控制台看不到提示的核心原因是:web3.py默认的交易发送、回执拉取逻辑不会自动解码回退载荷,和Remix自带自动模拟、自动解码错误的逻辑不同。
可行的错误信息获取方案
方案1:交易发送前本地预执行捕获错误(推荐)
这是开发阶段最常用的方案,不需要等交易上链打包,就能提前拿到校验失败的提示,还能省gas费:在正式签名发送交易前,用完全一致的参数、发起地址调用合约方法的call()接口,触发节点本地模拟执行,一旦触发require校验失败,会直接抛出包含错误提示的异常,示例代码:
from web3 import Web3, exceptions # 初始化web3实例、加载合约、配置签名账户的逻辑省略 burn_amount = 10**18 # 你要销毁的金额 sender_addr = "0x你的发起地址" try: # 本地模拟执行,参数和正式交易完全一致 contract.functions.burn(burn_amount).call({"from": sender_addr}) except exceptions.ContractLogicError as e: # 此处可直接拿到require定义的错误文本,比如"Not enough balance to burn" print(f"合约校验失败:{e.message}") # 校验失败直接终止流程,不需要发送交易上链 raise RuntimeError("交易预执行失败") from e # 预执行通过后再构造正式交易、签名、发送 tx = contract.functions.burn(burn_amount).build_transaction({ "from": sender_addr, "nonce": w3.eth.get_transaction_count(sender_addr), # 其余gas、chainId等参数配置省略 }) # 后续签名、发送交易逻辑省略
方案2:已上链失败交易的回退原因解析
如果交易已经打包上链、且回执状态为失败(status=0),可以通过重放对应区块高度的合约调用,拿到回退数据后解析错误信息,示例代码:
tx_hash = "0x你要查询的失败交易哈希" receipt = w3.eth.get_transaction_receipt(tx_hash) if receipt.status == 0: # 拿到原始交易参数 tx = w3.eth.get_transaction(tx_hash) # 在交易打包的区块高度重放调用,拿到回退数据 revert_data = w3.eth.call({ "to": tx["to"], "from": tx["from"], "data": tx["input"], "value": tx["value"] }, receipt.blockNumber) # web3.py 6.0+版本可直接用合约实例解码错误 try: revert_error = contract.decode_function_error(revert_data) print(f"链上交易回退原因:{revert_error.message}") except: # 兼容老版本web3.py,手动解析Error(string)类型的回退 # Error(string)的函数选择器为0x08c379a0 if revert_data[:4] == b"\x08\xc3\x79\xa0": error_msg = w3.codec.decode(["string"], revert_data[4:])[0] print(f"链上交易回退原因:{error_msg}")
注意:如果连接的第三方RPC节点截断了回退数据、或者不支持历史区块的
eth_call查询,会出现无法解析错误的情况,更换全节点RPC即可解决。
内容的提问来源于stack exchange,提问作者Synodinos Tavagios
相关产品推荐
相关产品推荐

