ethereum / pytest-ethereum

MIT License
19 stars 12 forks source link

Helpful Gas Errors #22

Open fubuloubu opened 5 years ago

fubuloubu commented 5 years ago

What was wrong?

When I execute a transaction that runs out of gas, I get the not-so-helpful evm.exceptions.ValidationError: Insufficient gas error from py-evm. Can I do something to make this better? Change some parameters? Is my contract too large? Did something fail with gas estimation?

It would be helpful to have some more actionable errors here.

Some of the common ones:

  1. Constructor is too large (24kb limit to deployment bytecode, unsure what error appears as)
  2. Transaction exceeds block gas limit (currently set to something like 3.14m right?)
pipermerriam commented 5 years ago

@fubuloubu can you provide a full-ish stacktrace so we can see which library this needs to be done in. I suspect this ends up being fixed in eth-tester by beefing up how we normalize exceptions to include contextual information from the Computation object.

pipermerriam commented 5 years ago

Specific to fixing this issue, given that you're seeing a ValidationError this isn't coming from within the EVM, but rather pre-validation which suggests your transaction doesn't have enough gas for the intrinsic gas cost for the transaction meaning that it never reaches EVM execution.

fubuloubu commented 5 years ago

The second one is my error. So, basically gas cost was never set? Meaning gas estimation failed?

The contract I am deploying is quite large and exceeds the contract size limit. I wonder if that is the source of the issue?

I was going to try and patch the VM rules so it worked, the contract does some highly non-optimal things with Structs that I have a few Vyper tickets open for

fubuloubu commented 5 years ago

stack trace:

================================================================================================== ERRORS ===================================================================================================
___________________________________________________________________________________ ERROR at setup of test_challengeAfter ___________________________________________________________________________________

vy_deployer = <pytest_ethereum.deployer.Deployer object at 0x7f2bed19c160>, token = <web3.utils.datatypes.LinkableContract object at 0x7f2becbcca90>

    @pytest.fixture
    def rootchain(vy_deployer, token):
>       return vy_deployer.deploy("RootChain", token.address)[0].\
                deployments.get_contract_instance("RootChain")

tests/conftest.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/pytest_ethereum/deployer.py:29: in deploy
    return strategy(self.package)
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/pytest_ethereum/linker.py:24: in _linker
    return pipe(package, *operations)
cytoolz/functoolz.pyx:589: in cytoolz.functoolz.pipe
    ???
cytoolz/functoolz.pyx:565: in cytoolz.functoolz.c_pipe
    ???
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/pytest_ethereum/linker.py:51: in _deploy
    tx_hash = factory.constructor(*args).transact()
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/utils/decorators.py:14: in _wrapper
    return self.method(obj, *args, **kwargs)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/contract.py:842: in transact
    return self.web3.eth.sendTransaction(transact_transaction)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/eth.py:263: in sendTransaction
    get_buffered_gas_estimate(self.web3, transaction),
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/utils/transactions.py:84: in get_buffered_gas_estimate
    gas_estimate = web3.eth.estimateGas(gas_estimate_transaction)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/eth.py:304: in estimateGas
    [transaction],
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/manager.py:107: in request_blocking
    response = self._make_request(method, params)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/manager.py:90: in _make_request
    return request_func(method, params)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/gas_price_strategy.py:18: in middleware
    return make_request(method, params)
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/formatting.py:48: in apply_formatters
    response = make_request(method, formatted_params)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/attrdict.py:18: in middleware
    response = make_request(method, params)
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/formatting.py:48: in apply_formatters
    response = make_request(method, formatted_params)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/normalize_errors.py:9: in middleware
    result = make_request(method, params)
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/formatting.py:48: in apply_formatters
    response = make_request(method, formatted_params)
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/formatting.py:48: in apply_formatters
    response = make_request(method, formatted_params)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/providers/eth_tester/middleware.py:320: in middleware
    return make_request(method, [filled_transaction] + params[1:])
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/fixture.py:12: in middleware
    return make_request(method, params)
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/middleware/formatting.py:48: in apply_formatters
    response = make_request(method, formatted_params)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/providers/eth_tester/main.py:46: in make_request
    response = delegator(self.ethereum_tester, params)
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/web3/providers/eth_tester/defaults.py:36: in call_eth_tester
    return getattr(eth_tester, fn_name)(*fn_args, **fn_kwargs)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/eth_tester/main.py:466: in estimate_gas
    raw_gas_estimate = self.backend.estimate_gas(raw_transaction)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/eth_tester/utils/formatting.py:85: in wrapper
    return to_wrap(*args, **kwargs)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/eth_tester/backends/pyevm/main.py:480: in estimate_gas
    return self.chain.estimate_gas(spoofed_transaction)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/evm/chains/base.py:540: in estimate_gas
    return self.gas_estimator(state, transaction)
cytoolz/functoolz.pyx:232: in cytoolz.functoolz.curry.__call__
    ???
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/evm/estimators/gas.py:63: in binary_gas_search
    error = _get_computation_error(state, maximum_transaction)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/evm/estimators/gas.py:16: in _get_computation_error
    computation = state.execute_transaction(transaction)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/evm/vm/forks/frontier/state.py:195: in execute_transaction
    return executor(transaction)
../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/evm/vm/state.py:243: in __call__
    valid_transaction = self.validate_transaction(transaction)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <evm.vm.forks.spurious_dragon.state.SpuriousDragonTransactionExecutor object at 0x7f2becdc15c0>, transaction = <evm.utils.spoof.SpoofTransaction object at 0x7f2becdc1550>

    def validate_transaction(self, transaction):

        # Validate the transaction

        if transaction.intrinsic_gas > transaction.gas:
>           raise ValidationError("Insufficient gas")
E           evm.exceptions.ValidationError: Insufficient gas

../../../../.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/evm/vm/forks/frontier/state.py:45: ValidationError
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/home/bryant/.pyenv/versions/3.6.6/envs/plasma-cash/lib/python3.6/site-packages/vyper/optimizer.py:53: KeyboardInterrupt
(to show a full traceback on KeyboardInterrupt use --fulltrace)
========================================================================================== 1 error in 6.15 seconds ==========================================================================================
pipermerriam commented 5 years ago

Simple improvement here would be to improve the error message in that exception.

The transaction has insufficient gas to pay for it's base cost. Needed {transaction.intrinsic_gas} but only had {transaction.gas}.

fubuloubu commented 5 years ago

Yes! Love to know the amounts.