使用Web3.py对接本地Ganache实例时遭遇交易REVERT错误
Web3.py对接Ganache部署合约触发VM Revert错误的解决方法
问题背景
使用Web3.py对接本地Ganache实例部署合约时,持续触发VM Exception while processing transaction: revert错误。已确认:
- 可正常读取已部署合约数据
- Truffle能正常执行合约读写操作
- 测试空合约时仍出现相同错误
错误代码
from solcx import compile_source, compile_files source = ''' pragma solidity >=0.4.22 <0.9.0; contract TruffleTutorial { } ''' compiled_sol = compile_source( source, output_values=["abi", "bin-runtime"], solc_version="0.8.9") contract_id, contract_interface = compiled_sol.popitem() bytecode = contract_interface['bin-runtime'] abi = contract_interface['abi'] dummyContract = w3.eth.contract(abi=abi, bytecode=bytecode) nonce = w3.eth.getTransactionCount(Web3.toChecksumAddress(address))+1 txn = dummyContract.constructor().buildTransaction({ "chainId": 1337, "gasPrice": w3.eth.gas_price, "from": w3.eth.accounts[0], "nonce": nonce })
错误信息
PUSH1 PUSH1 MSTORE PUSH1 DUP1 REVERT < { < "id": 43, < "jsonrpc": "2.0", < "error": { < "message": "VM Exception while processing transaction: revert", < "code": -32000, < "data": { < "stack": "c: VM Exception while processing transaction: revert\n at Function.c.fromResults (/Users/me/some/path/node_modules/ganache-cli/build/ganache-core.node.cli.js:4:192416)\n at e.exports (/Users/me/some/path/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:2089395)", < "name": "c" < } < } < }
问题原因
核心错误是使用了合约运行时代码(bin-runtime)发起部署交易。bin-runtime是合约部署完成后在链上执行的代码,而部署合约需要的是合约创建字节码(bin),用运行时代码部署会直接触发VM revert。
另外,手动给nonce加1可能导致nonce值过高,引发交易失败。getTransactionCount默认会返回包含pending状态的交易数,无需额外递增。
修复方案
1. 修正字节码获取逻辑
修改编译参数和字节码变量:
- 编译时将
output_values中的bin-runtime替换为bin - 从编译结果中取
bin字段作为部署用的字节码
2. 修正nonce计算方式
直接使用getTransactionCount的返回值,不要手动加1
修复后的完整代码
from solcx import compile_source, compile_files source = ''' pragma solidity >=0.4.22 <0.9.0; contract TruffleTutorial { } ''' compiled_sol = compile_source( source, output_values=["abi", "bin"], # 替换为创建字节码标识 solc_version="0.8.9") contract_id, contract_interface = compiled_sol.popitem() bytecode = contract_interface['bin'] # 取创建字节码 abi = contract_interface['abi'] dummyContract = w3.eth.contract(abi=abi, bytecode=bytecode) # 直接获取当前账户的nonce,无需额外+1 nonce = w3.eth.getTransactionCount(Web3.toChecksumAddress(address)) txn = dummyContract.constructor().buildTransaction({ "chainId": 1337, "gasPrice": w3.eth.gas_price, "from": w3.eth.accounts[0], "nonce": nonce })
内容的提问来源于stack exchange,提问作者kliao
相关产品推荐
相关产品推荐

