Brownie部署彩票合约enter函数交易失败,Remix运行正常
在持久化Ganache网络中使用Brownie操作彩票合约时,调用enter函数始终触发交易回滚,报错如下:
ValueError: Gas estimation failed: 'execution reverted: VM Exception while processing transaction: revert'. This transaction will likely revert. If you wish to broadcast, you must set the gas limit manually.
- 合约在Remix中可正常运行,转入0.04ETH(约64美元)满足5美元的费用要求
- 单独编写调用脚本或把调用逻辑加入部署脚本均无法解决
部署脚本关键代码
from brownie import lottery, accounts, config, network, MockV3Aggregator, LinkToken, VRFCoordinatorMock from scripts.helpful import get_account, deploy_mocks, LOCAL from web3 import Web3 value = Web3.toWei(0.04, "ether") def deploy_txn(): account = get_account() print(f"owner is {account}") print(f"{network.show_active()} is the current network") if network.show_active() not in LOCAL: pfaddress = config[network.show_active()]["padress"] vrf = config[network.show_active()]["vrf"] link = config[network.show_active()]["link_token"] keyhash = config[network.show_active()]["keyhash"] fee = config[network.show_active()]["fee"] else: deploy_mocks() pfaddress = MockV3Aggregator[-1].address vrf = VRFCoordinatorMock[-1].address link = LinkToken[-1].address keyhash = '0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311' fee = '100000000000000000' caddr = lottery.deploy(vrf, pfaddress, link, keyhash, fee, {"from": account}) print(caddr) def start_lottery(): account = get_account() lottery[-1].startLottery({"from": account}) def enter_lottery(): account = get_account() lottery[-1].enter({"from": account, "value": value}) def main(): deploy_txn() start_lottery() enter_lottery()
Solidity合约enter函数代码
function enter() payable public { require(ETHtoUSD(msg.value) >= usdfee, "Not enough ETH!"); require(currentstate == lotteryState.open, "Lottery isn't open yet!"); players.push(payable(msg.sender)); }
1. 检查Mock价格聚合器的初始值
本地Ganache网络中部署的MockV3Aggregator如果初始价格设置错误,会导致ETHtoUSD(msg.value)计算结果不满足5美元要求,触发第一个require回滚。比如Mock设置1ETH=100USD时,0.04ETH仅为4USD,低于阈值。
解决:
修改deploy_mocks函数中MockV3Aggregator的初始化参数,确保价格与实际匹配(以当前ETH价格约1600USD为例,传入1600 * 10^8,因为Mock的decimals通常为8):
def deploy_mocks(): if len(MockV3Aggregator) <= 0: MockV3Aggregator.deploy(8, 160000000000, {"from": get_account()})
2. 确认startLottery交易完成区块确认
Brownie脚本中交易执行是同步的,但Ganache可能存在区块确认延迟,导致调用enter时currentstate仍未切换为open,触发第二个require回滚。
解决:
在start_lottery函数中添加区块等待逻辑:
def start_lottery(): account = get_account() tx = lottery[-1].startLottery({"from": account}) tx.wait(1) # 等待1个区块确认状态变更
3. 验证get_account返回账户的余额
确认get_account()返回的账户是你转入ETH的目标账户,避免因账户不匹配导致实际余额不足(即使报错信息显示回滚,也需排除此可能)。
解决:
添加余额打印逻辑验证:
def enter_lottery(): account = get_account() print(f"Account balance: {Web3.fromWei(account.balance(), 'ether')} ETH") lottery[-1].enter({"from": account, "value": value})
4. 手动设置Gas Limit查看具体回滚原因
Gas估计失败时,可手动设置Gas Limit强制广播交易,获取更精准的回滚提示(比如明确触发哪个require):
def enter_lottery(): account = get_account() lottery[-1].enter({"from": account, "value": value, "gas_limit": 1000000})
5. 检查usdfee的初始化逻辑
确认合约构造函数中usdfee的数值与ETHtoUSD函数的计算逻辑匹配。比如如果ETHtoUSD返回的是带8位小数的美分数值,usdfee应设为5 * 10^8,而非5 * 10^18,否则会导致数值不匹配触发回滚。
内容的提问来源于stack exchange,提问作者smarsbyi

