diff --git a/boa/contracts/vyper/vyper_contract.py b/boa/contracts/vyper/vyper_contract.py index 24ed9bd9..b0c39301 100644 --- a/boa/contracts/vyper/vyper_contract.py +++ b/boa/contracts/vyper/vyper_contract.py @@ -169,6 +169,7 @@ def __init__( override_address=None, blueprint_preamble=b"\xFE\x71\x00", filename=None, + gas=None, ): # note slight code duplication with VyperContract ctor, # maybe use common base class? @@ -186,7 +187,7 @@ def __init__( deploy_bytecode += blueprint_bytecode addr, computation = self.env.deploy( - bytecode=deploy_bytecode, override_address=override_address + bytecode=deploy_bytecode, override_address=override_address, gas=gas ) if computation.is_error: raise computation.error @@ -494,6 +495,7 @@ def __init__( skip_initcode=False, created_from: Address = None, filename: str = None, + gas=None, ): super().__init__(compiler_data, env, filename) @@ -518,7 +520,9 @@ def __init__( raise Exception("nonzero value but initcode is being skipped") addr = Address(override_address) else: - addr = self._run_init(*args, value=value, override_address=override_address) + addr = self._run_init( + *args, value=value, override_address=override_address, gas=gas + ) self._address = addr for fn_name, fn in external_fns.items(): @@ -537,14 +541,14 @@ def __init__( self.env.register_contract(self._address, self) - def _run_init(self, *args, value=0, override_address=None): + def _run_init(self, *args, value=0, override_address=None, gas=None): encoded_args = b"" if self._ctor: encoded_args = self._ctor.prepare_calldata(*args) initcode = self.compiler_data.bytecode + encoded_args address, computation = self.env.deploy( - bytecode=initcode, value=value, override_address=override_address + bytecode=initcode, value=value, override_address=override_address, gas=gas ) self._computation = computation self.bytecode = computation.output diff --git a/boa/network.py b/boa/network.py index 5e347e1d..2e252178 100644 --- a/boa/network.py +++ b/boa/network.py @@ -512,6 +512,8 @@ def _send_txn(self, from_, to=None, gas=None, value=None, data=None): print(f"tx broadcasted: {tx_hash}") receipt = self._rpc.wait_for_tx_receipt(tx_hash, self.tx_settings.poll_timeout) + if receipt.get("status") != "0x1": + raise Exception(f"txn failed: {receipt}") trace = self._debug_tt(tx_hash) diff --git a/tests/integration/network/anvil/test_network_env.py b/tests/integration/network/anvil/test_network_env.py index 13ad59d5..c544ed13 100644 --- a/tests/integration/network/anvil/test_network_env.py +++ b/tests/integration/network/anvil/test_network_env.py @@ -56,4 +56,11 @@ def test_raise_exception(simple_contract, t): simple_contract.raise_exception(t) +def test_failed_transaction(): + with pytest.raises(Exception) as ctx: + boa.loads(code, STARTING_SUPPLY, gas=149377) + error = str(ctx.value) + assert error.startswith("txn failed:") + + # XXX: probably want to test deployment revert behavior diff --git a/tests/unitary/jupyter/test_browser.py b/tests/unitary/jupyter/test_browser.py index a76090ec..1ec2d821 100644 --- a/tests/unitary/jupyter/test_browser.py +++ b/tests/unitary/jupyter/test_browser.py @@ -210,6 +210,7 @@ def dummy() -> bool: "blockHash": "0x123", "blockNumber": "0x123", "contractAddress": "0x520c4BbBb1153fBB42742fEf935283e19Bb2a2e0", + "status": "0x1", }, ) mock_callback("debug_traceTransaction", error={"message": "error"})