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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:06:32