From 3ce518cfb6bb0aec83e224ea32e633af7a2b818f Mon Sep 17 00:00:00 2001 From: Karl Bartel Date: Mon, 24 Feb 2020 17:22:22 +0100 Subject: [PATCH 01/23] Parse revert reason when `call` fails Solidity allows messages in `require` statements which can help a lot when debugging. This commit parses the revert reasons from failing `call`s and raises them as `SolidityError` exceptions. Closes https://github.com/ethereum/web3.py/issues/941. --- newsfragments/941.feature.rst | 1 + .../core/utilities/test_method_formatters.py | 65 +++++++++++++++++++ web3/_utils/method_formatters.py | 53 ++++++++++++++- web3/exceptions.py | 8 +++ web3/manager.py | 2 +- web3/types.py | 1 + 6 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 newsfragments/941.feature.rst create mode 100644 tests/core/utilities/test_method_formatters.py diff --git a/newsfragments/941.feature.rst b/newsfragments/941.feature.rst new file mode 100644 index 0000000000..9c0f4764fe --- /dev/null +++ b/newsfragments/941.feature.rst @@ -0,0 +1 @@ +Raise `SolidityError` exceptions that contain the revert reason when a `call` fails. diff --git a/tests/core/utilities/test_method_formatters.py b/tests/core/utilities/test_method_formatters.py new file mode 100644 index 0000000000..2bd50cb279 --- /dev/null +++ b/tests/core/utilities/test_method_formatters.py @@ -0,0 +1,65 @@ +import pytest + +from web3._utils.method_formatters import ( + get_error_formatters, + get_revert_reason, +) +from web3._utils.rpc_abi import ( + RPC, +) +from web3.exceptions import ( + SolidityError, +) +from web3.types import ( + RPCResponse, +) + +REVERT_WITH_MSG = RPCResponse({ + 'jsonrpc': '2.0', + 'error': { + 'code': -32015, + 'message': 'VM execution error.', + 'data': ( + 'Reverted ' + '0x08c379a' + '00000000000000000000000000000000000000000000000000000000000000020' + '0000000000000000000000000000000000000000000000000000000000000016' + '6e6f7420616c6c6f77656420746f206d6f6e69746f7200000000000000000000' + ), + }, + 'id': 2987, +}) + +REVERT_WITHOUT_MSG = RPCResponse({ + 'jsonrpc': '2.0', + 'error': { + 'code': -32015, + 'message': 'VM execution error.', + 'data': 'Reverted 0x', + }, + 'id': 2987, +}) + +OTHER_ERROR = RPCResponse({ + "jsonrpc": "2.0", + "error": { + "code": -32601, + "message": "Method not found", + }, + "id": 1, +}) + + +def test_get_revert_reason() -> None: + assert get_revert_reason(REVERT_WITH_MSG) == 'not allowed to monitor' + assert get_revert_reason(REVERT_WITHOUT_MSG) == '' + assert get_revert_reason(OTHER_ERROR) is None + + +def test_get_error_formatters() -> None: + formatters = get_error_formatters(RPC.eth_call) + with pytest.raises(SolidityError, match='not allowed to monitor'): + formatters(REVERT_WITH_MSG) + with pytest.raises(SolidityError): + formatters(REVERT_WITHOUT_MSG) + assert formatters(OTHER_ERROR) == OTHER_ERROR diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py index 092282a520..d53223eb47 100644 --- a/web3/_utils/method_formatters.py +++ b/web3/_utils/method_formatters.py @@ -75,11 +75,13 @@ ) from web3.exceptions import ( BlockNotFound, + SolidityError, TransactionNotFound, ) from web3.types import ( BlockIdentifier, RPCEndpoint, + RPCResponse, TReturn, _Hash32, ) @@ -465,7 +467,6 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]: RPC.net_peerCount: to_integer_if_hex, } - ATTRDICT_FORMATTER = { '*': apply_formatter_if(is_dict and not_attrdict, AttributeDict.recursive) } @@ -486,6 +487,54 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]: ABI_REQUEST_FORMATTERS = abi_request_formatters(STANDARD_NORMALIZERS, RPC_ABIS) +def get_revert_reason(response: RPCResponse) -> str: + """ + Parse revert reason from response, return None if no revert happened. + + If a revert happened, but no message has been given, return an empty string. + + Reverts contain a `data` attribute with the following layout: + "Reverted " + Function selector for Error(string): 08c379a (4 bytes) + Data offset: 32 (32 bytes) + String length (32 bytes) + Reason strong (padded, use string length from above to get meaningful part) + + See also https://solidity.readthedocs.io/en/v0.6.3/control-structures.html#revert + """ + assert 'error' in response + if not isinstance(response['error'], dict): + return None + + data = response['error'].get('data', '') + + if data == 'Reverted 0x': + return '' + + # "Reverted", function selector and offset are always the same for revert errors + prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' + if not data.startswith(prefix): + return None + + reason_length = int(data[len(prefix):len(prefix) + 64], 16) + reason = data[len(prefix) + 64:len(prefix) + 64 + reason_length * 2] + return bytes.fromhex(reason).decode('utf8') + + +def raise_solidity_error_on_revert(response: RPCResponse) -> RPCResponse: + revert_reason = get_revert_reason(response) + if revert_reason is None: + return response + if revert_reason == '': + raise SolidityError() + raise SolidityError(revert_reason) + + +ERROR_FORMATTERS: Dict[RPCEndpoint, Callable[..., Any]] = { + RPC.eth_call: raise_solidity_error_on_revert, +} + + @to_tuple def combine_formatters( formatter_maps: Collection[Dict[RPCEndpoint, Callable[..., TReturn]]], method_name: RPCEndpoint @@ -570,7 +619,7 @@ def get_result_formatters( def get_error_formatters( method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]] -) -> Dict[str, Callable[..., Any]]: +) -> Callable[..., Any]: # Note error formatters work on the full response dict error_formatter_maps = (NULL_RESULT_FORMATTERS,) formatters = combine_formatters(error_formatter_maps, method_name) diff --git a/web3/exceptions.py b/web3/exceptions.py index 194f714f0c..833e33f2c0 100644 --- a/web3/exceptions.py +++ b/web3/exceptions.py @@ -192,3 +192,11 @@ class InvalidEventABI(ValueError): Raised when the event ABI is invalid. """ pass + + +class SolidityError(ValueError): + # Inherits from ValueError for backwards compatibility + """ + Raised on a solidity require/revert + """ + pass diff --git a/web3/manager.py b/web3/manager.py index 9402096397..d40266fc74 100644 --- a/web3/manager.py +++ b/web3/manager.py @@ -154,7 +154,7 @@ def request_blocking( response = self._make_request(method, params) if "error" in response: - apply_error_formatters(error_formatters, response) + response = apply_error_formatters(error_formatters, response) raise ValueError(response["error"]) elif response['result'] is None: apply_error_formatters(error_formatters, response, params) diff --git a/web3/types.py b/web3/types.py index 0c8c94dd84..5cb3c0e8d6 100644 --- a/web3/types.py +++ b/web3/types.py @@ -116,6 +116,7 @@ class EventData(TypedDict): class RPCError(TypedDict): code: int message: str + data: Optional[str] class RPCResponse(TypedDict, total=False): From 952c4c3bc09826bf023e115283fcd2f6c532a22c Mon Sep 17 00:00:00 2001 From: Keri Date: Mon, 24 Feb 2020 13:42:51 -0700 Subject: [PATCH 02/23] Add test for revert interface --- tests/core/contracts/conftest.py | 76 +++++++++++++++++++ .../contracts/test_contract_call_interface.py | 21 +++++ 2 files changed, 97 insertions(+) diff --git a/tests/core/contracts/conftest.py b/tests/core/contracts/conftest.py index ca8ed0d6e5..5d7cec5a57 100644 --- a/tests/core/contracts/conftest.py +++ b/tests/core/contracts/conftest.py @@ -893,6 +893,82 @@ def CallerTesterContract(web3, CALLER_TESTER_CONTRACT): return web3.eth.contract(**CALLER_TESTER_CONTRACT) +REVERT_CONTRACT_SOURCE = """ +pragma solidity ^0.6.1; + +contract RevertContract { + function normalFunction() public pure returns (bool) { + return true; + } + + function revertFunction() public pure { + revert('Function has been reverted.'); + } +} +""" + + +REVERT_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b5061010c806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806383fcb85e146037578063d67e4b8414603f575b600080fd5b603d605f565b005b604560cd565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b6000600190509056fea26469706673582212206b3e8456a530e8c500866943d9e7c5e083be8e70bfd6f57502e9cb19b9ef3e4464736f6c63430006010033" # noqa: E501 + + +REVERT_CONTRACT_RUNTIME_CODE = "6080604052348015600f57600080fd5b506004361060325760003560e01c806383fcb85e146037578063d67e4b8414603f575b600080fd5b603d605f565b005b604560cd565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b6000600190509056fea26469706673582212206b3e8456a530e8c500866943d9e7c5e083be8e70bfd6f57502e9cb19b9ef3e4464736f6c63430006010033" # noqa: E501 + + +_REVERT_CONTRACT_ABI = json.loads('''[ + { + "inputs": [], + "name": "normalFunction", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "revertFunction", + "outputs": [], + "stateMutability": "pure", + "type": "function" + } +]''') # noqa: E501 + + +@pytest.fixture() +def REVERT_CONTRACT_CODE(): + return REVERT_CONTRACT_BYTECODE + + +@pytest.fixture() +def REVERT_CONTRACT_RUNTIME(): + return REVERT_CONTRACT_RUNTIME_CODE + + +@pytest.fixture() +def REVERT_CONTRACT_ABI(): + return _REVERT_CONTRACT_ABI + + +@pytest.fixture() +def REVERT_FUNCTION_CONTRACT(REVERT_CONTRACT_CODE, + REVERT_CONTRACT_RUNTIME, + REVERT_CONTRACT_ABI): + return { + 'bytecode': REVERT_CONTRACT_CODE, + 'bytecode_runtime': REVERT_CONTRACT_RUNTIME, + 'abi': REVERT_CONTRACT_ABI, + } + + +@pytest.fixture() +def RevertContract(web3, REVERT_FUNCTION_CONTRACT): + return web3.eth.contract(**REVERT_FUNCTION_CONTRACT) + + class LogFunctions: LogAnonymous = 0 LogNoArguments = 1 diff --git a/tests/core/contracts/test_contract_call_interface.py b/tests/core/contracts/test_contract_call_interface.py index 2e5d668210..bd9dedd0c1 100644 --- a/tests/core/contracts/test_contract_call_interface.py +++ b/tests/core/contracts/test_contract_call_interface.py @@ -30,6 +30,7 @@ MismatchedABI, NoABIFound, NoABIFunctionsFound, + SolidityError, ValidationError, ) @@ -120,6 +121,19 @@ def payable_tester_contract(web3, PayableTesterContract, address_conversion_func return deploy(web3, PayableTesterContract, address_conversion_func) +@pytest.fixture() +def revert_contract(web3, RevertContract, address_conversion_func): + return deploy(web3, RevertContract, address_conversion_func) + + +@pytest.fixture() +def call_transaction(): + return { + 'data': '0x61bc221a', + 'to': '0xc305c901078781C232A2a521C2aF7980f8385ee9' + } + + @pytest.fixture(params=[ '0x0406040604060406040604060406040604060406040604060406040604060406', '0406040604060406040604060406040604060406040604060406040604060406', @@ -855,3 +869,10 @@ def test_call_tuple_contract(tuple_contract, method_input, expected): def test_call_nested_tuple_contract(nested_tuple_contract, method_input, expected): result = nested_tuple_contract.functions.method(method_input).call() assert result == expected + + +def test_call_revert_contract(revert_contract): + with pytest.raises(SolidityError): + result = revert_contract.functions.revertFunction().call() + # TODO - figure out what result actually is and what we'll need to do to parse out the string + assert "Function has been reverted." in result From 1579b71c34c49d55ee09bca9a61f3fd1fd5a3787 Mon Sep 17 00:00:00 2001 From: Karl Bartel Date: Tue, 3 Mar 2020 17:13:58 +0100 Subject: [PATCH 03/23] Convert TransactionFailed into SolidityError In an effort to be backend-agnostic eth-tester changes errors that are specific to one EVM (like Revert) to a TransactionFailed error. This is useful when using only eth-tester. But as web3.py also works directly with other eth clients, we have to abstract over the different revert behaviors ourselves. --- web3/manager.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/web3/manager.py b/web3/manager.py index d40266fc74..54f8c1ec38 100644 --- a/web3/manager.py +++ b/web3/manager.py @@ -14,6 +14,7 @@ import uuid from uuid import UUID +import eth_tester from eth_utils.toolz import ( pipe, ) @@ -28,6 +29,9 @@ from web3.datastructures import ( NamedElementOnion, ) +from web3.exceptions import ( + SolidityError, +) from web3.middleware import ( abi_middleware, attrdict_middleware, @@ -151,7 +155,10 @@ def request_blocking( """ Make a synchronous request using the provider """ - response = self._make_request(method, params) + try: + response = self._make_request(method, params) + except eth_tester.exceptions.TransactionFailed as e: + raise SolidityError(*e.args) if "error" in response: response = apply_error_formatters(error_formatters, response) From b5190a5176ec1dfcf7d228adc75e669c321caed7 Mon Sep 17 00:00:00 2001 From: Karl Bartel Date: Tue, 3 Mar 2020 17:41:49 +0100 Subject: [PATCH 04/23] Check revert reason in test --- tests/core/contracts/test_contract_call_interface.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/core/contracts/test_contract_call_interface.py b/tests/core/contracts/test_contract_call_interface.py index bd9dedd0c1..60af5646b9 100644 --- a/tests/core/contracts/test_contract_call_interface.py +++ b/tests/core/contracts/test_contract_call_interface.py @@ -872,7 +872,8 @@ def test_call_nested_tuple_contract(nested_tuple_contract, method_input, expecte def test_call_revert_contract(revert_contract): - with pytest.raises(SolidityError): - result = revert_contract.functions.revertFunction().call() - # TODO - figure out what result actually is and what we'll need to do to parse out the string - assert "Function has been reverted." in result + with pytest.raises(SolidityError, match="Function has been reverted."): + # eth-tester will do a gas estimation if we don't submit a gas value, + # which does not contain the revert reason. Avoid that by giving a gas + # value. + revert_contract.functions.revertFunction().call({'gas': 100000}) From 039e1f03c37aed74ccc1ece023ce58813e21bfcb Mon Sep 17 00:00:00 2001 From: Karl Bartel Date: Tue, 3 Mar 2020 17:44:00 +0100 Subject: [PATCH 05/23] fixup! Add test for revert interface Fix linting errors --- tests/core/contracts/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/contracts/conftest.py b/tests/core/contracts/conftest.py index 5d7cec5a57..f7925ebd23 100644 --- a/tests/core/contracts/conftest.py +++ b/tests/core/contracts/conftest.py @@ -955,8 +955,8 @@ def REVERT_CONTRACT_ABI(): @pytest.fixture() def REVERT_FUNCTION_CONTRACT(REVERT_CONTRACT_CODE, - REVERT_CONTRACT_RUNTIME, - REVERT_CONTRACT_ABI): + REVERT_CONTRACT_RUNTIME, + REVERT_CONTRACT_ABI): return { 'bytecode': REVERT_CONTRACT_CODE, 'bytecode_runtime': REVERT_CONTRACT_RUNTIME, From d4abc76606122a18a7420350b57f5b459da487af Mon Sep 17 00:00:00 2001 From: Keri Date: Wed, 29 Apr 2020 10:50:34 -0600 Subject: [PATCH 06/23] Revert contract working in geth fixture --- tests/core/contracts/conftest.py | 50 ++------------- .../contracts/test_contract_call_interface.py | 2 +- web3/_utils/module_testing/revert_contract.py | 62 +++++++++++++++++++ 3 files changed, 68 insertions(+), 46 deletions(-) create mode 100644 web3/_utils/module_testing/revert_contract.py diff --git a/tests/core/contracts/conftest.py b/tests/core/contracts/conftest.py index f7925ebd23..cf3619688e 100644 --- a/tests/core/contracts/conftest.py +++ b/tests/core/contracts/conftest.py @@ -36,6 +36,11 @@ CONTRACT_RECEIVE_FUNCTION_CODE, CONTRACT_RECEIVE_FUNCTION_RUNTIME, ) +from web3._utils.module_testing.revert_contract import ( + _REVERT_CONTRACT_ABI, + REVERT_CONTRACT_BYTECODE, + REVERT_CONTRACT_RUNTIME_CODE, +) CONTRACT_NESTED_TUPLE_SOURCE = """ pragma solidity >=0.4.19 <0.6.0; @@ -893,51 +898,6 @@ def CallerTesterContract(web3, CALLER_TESTER_CONTRACT): return web3.eth.contract(**CALLER_TESTER_CONTRACT) -REVERT_CONTRACT_SOURCE = """ -pragma solidity ^0.6.1; - -contract RevertContract { - function normalFunction() public pure returns (bool) { - return true; - } - - function revertFunction() public pure { - revert('Function has been reverted.'); - } -} -""" - - -REVERT_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b5061010c806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806383fcb85e146037578063d67e4b8414603f575b600080fd5b603d605f565b005b604560cd565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b6000600190509056fea26469706673582212206b3e8456a530e8c500866943d9e7c5e083be8e70bfd6f57502e9cb19b9ef3e4464736f6c63430006010033" # noqa: E501 - - -REVERT_CONTRACT_RUNTIME_CODE = "6080604052348015600f57600080fd5b506004361060325760003560e01c806383fcb85e146037578063d67e4b8414603f575b600080fd5b603d605f565b005b604560cd565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b6000600190509056fea26469706673582212206b3e8456a530e8c500866943d9e7c5e083be8e70bfd6f57502e9cb19b9ef3e4464736f6c63430006010033" # noqa: E501 - - -_REVERT_CONTRACT_ABI = json.loads('''[ - { - "inputs": [], - "name": "normalFunction", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "revertFunction", - "outputs": [], - "stateMutability": "pure", - "type": "function" - } -]''') # noqa: E501 - - @pytest.fixture() def REVERT_CONTRACT_CODE(): return REVERT_CONTRACT_BYTECODE diff --git a/tests/core/contracts/test_contract_call_interface.py b/tests/core/contracts/test_contract_call_interface.py index 60af5646b9..af50991f4e 100644 --- a/tests/core/contracts/test_contract_call_interface.py +++ b/tests/core/contracts/test_contract_call_interface.py @@ -876,4 +876,4 @@ def test_call_revert_contract(revert_contract): # eth-tester will do a gas estimation if we don't submit a gas value, # which does not contain the revert reason. Avoid that by giving a gas # value. - revert_contract.functions.revertFunction().call({'gas': 100000}) + revert_contract.functions.revertWithMessage().call({'gas': 100000}) diff --git a/web3/_utils/module_testing/revert_contract.py b/web3/_utils/module_testing/revert_contract.py new file mode 100644 index 0000000000..e8f37211c1 --- /dev/null +++ b/web3/_utils/module_testing/revert_contract.py @@ -0,0 +1,62 @@ +import json + +REVERT_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b5060f08061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b8414604f575b600080fd5b60476069565b005b6047603c565b605560b6565b604080519115158252519081900360200190f35b6040805162461bcd60e51b815260206004820152601b60248201527f46756e6374696f6e20686173206265656e2072657665727465642e0000000000604482015290519081900360640190fd5b60019056fea265627a7a723158202b5d1c5df2d5450324be8ee1af3ef7098f4b4acf5df16b1cb3cc86d4c48aa95664736f6c63430005100032" + + +REVERT_CONTRACT_RUNTIME_CODE = "6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b8414604f575b600080fd5b60476069565b005b6047603c565b605560b6565b604080519115158252519081900360200190f35b6040805162461bcd60e51b815260206004820152601b60248201527f46756e6374696f6e20686173206265656e2072657665727465642e0000000000604482015290519081900360640190fd5b60019056fea26469706673582212204e6819701a04acfefd5a4b75221d095cac98d0a467116e264d73f1b3dc239b9064736f6c63430006010033" # noqa: E501 + + +_REVERT_CONTRACT_ABI = json.loads('''[ + { + "constant": true, + "inputs": [], + "name": "normalFunction", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "revertWithMessage", + "outputs": [], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "revertWithoutMessage", + "outputs": [], + "payable": false, + "stateMutability": "pure", + "type": "function" + } +]''') + + +REVERT_CONTRACT_SOURCE = """ +pragma solidity ^0.6.1; + +contract RevertContract { + function normalFunction() public pure returns (bool) { + return true; + } + + function revertWithMessage() public pure { + revert('Function has been reverted.'); + } + + function revertWithoutMessage() public pure { + revert(); + } +} +""" From 2bb0ec6114d02dd8a3dde690b58062fa8303e997 Mon Sep 17 00:00:00 2001 From: Keri Date: Wed, 29 Apr 2020 16:33:31 -0600 Subject: [PATCH 07/23] Beginnings of Geth integration test --- .../contracts/test_contract_call_interface.py | 4 +++ tests/integration/conftest.py | 10 +++++++ .../generate_fixtures/go_ethereum.py | 30 +++++++++++++++++++ tests/integration/go_ethereum/conftest.py | 15 ++++++++++ web3/_utils/module_testing/eth_module.py | 8 +++++ 5 files changed, 67 insertions(+) diff --git a/tests/core/contracts/test_contract_call_interface.py b/tests/core/contracts/test_contract_call_interface.py index af50991f4e..ebf1e7c363 100644 --- a/tests/core/contracts/test_contract_call_interface.py +++ b/tests/core/contracts/test_contract_call_interface.py @@ -189,6 +189,10 @@ def nested_tuple_contract(web3, NestedTupleContract, address_conversion_func): return deploy(web3, NestedTupleContract, address_conversion_func) +@pytest.fixture() +def revert_contract(web3, RevertContract, address_conversion_func): + return deploy(web3, RevertContract, address_conversion_func) + def test_invalid_address_in_deploy_arg(web3, WithConstructorAddressArgumentsContract): with pytest.raises(InvalidAddress): WithConstructorAddressArgumentsContract.constructor( diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 0b50516ceb..5b997ddecc 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -9,6 +9,10 @@ MATH_ABI, MATH_BYTECODE, ) +from web3._utils.module_testing.revert_contract import ( + _REVERT_CONTRACT_ABI, + REVERT_CONTRACT_BYTECODE, +) @pytest.fixture(scope="module") @@ -28,3 +32,9 @@ def event_loop(request): loop = asyncio.get_event_loop_policy().new_event_loop() yield loop loop.close() + + +@pytest.fixture(scope="module") +def revert_contract_factory(web3): + contract_factory = web3.eth.contract(abi=_REVERT_CONTRACT_ABI, bytecode=REVERT_CONTRACT_BYTECODE) + return contract_factory diff --git a/tests/integration/generate_fixtures/go_ethereum.py b/tests/integration/generate_fixtures/go_ethereum.py index 5bfc3b55dc..c5eb7568b2 100644 --- a/tests/integration/generate_fixtures/go_ethereum.py +++ b/tests/integration/generate_fixtures/go_ethereum.py @@ -363,6 +363,36 @@ def setup_chain_state(web3): block_with_log = web3.eth.getBlock(txn_receipt_with_log['blockHash']) print('BLOCK_HASH_WITH_LOG:', block_with_log['hash']) + # + # Revert Contract + # + revert_contract_factory = web3.eth.contract( + abi=_REVERT_CONTRACT_ABI, + bytecode=REVERT_CONTRACT_BYTECODE, + ) + revert_deploy_receipt = deploy_contract(web3, 'revert', revert_contract_factory) + revert_contract = revert_contract_factory(revert_deploy_receipt['contractAddress']) + + txn_hash_normal_function = revert_contract.functions.normalFunction().transact( + {'gas': 320000, 'from': web3.eth.coinbase} + ) + print('TXN_HASH_REVERT_NORMAL:', txn_hash_normal_function) + txn_hash_revert_with_msg = revert_contract.functions.revertWithMessage().transact( + {'gas': 320000, 'from': web3.eth.coinbase} + ) + print('TXN_HASH_REVERT_WITH_MSG:', txn_hash_revert_with_msg) + txn_receipt_revert_with_msg = mine_transaction_hash(web3, txn_hash_revert_with_msg) + block_hash_revert_with_msg = web3.eth.getBlock(txn_receipt_revert_with_msg['blockHash']) + print('BLOCK_HASH_REVERT_WITH_MSG:', block_hash_revert_with_msg['hash']) + + txn_hash_revert_with_no_msg = revert_contract.functions.revertWithoutMessage().transact( + {'gas': 320000, 'from': web3.eth.coinbase} + ) + print('TXN_HASH_REVERT_WITH_NO_MSG:', txn_hash_revert_with_no_msg) + txn_receipt_revert_with_no_msg = mine_transaction_hash(web3, txn_hash_revert_with_no_msg) + block_hash_revert_no_msg = web3.eth.getBlock(txn_receipt_revert_with_no_msg['blockHash']) + print('BLOCK_HASH_REVERT_NO_MSG:', block_hash_revert_no_msg['hash']) + # # Empty Block # diff --git a/tests/integration/go_ethereum/conftest.py b/tests/integration/go_ethereum/conftest.py index 4c567ab6aa..8c2d963c04 100644 --- a/tests/integration/go_ethereum/conftest.py +++ b/tests/integration/go_ethereum/conftest.py @@ -226,3 +226,18 @@ def block_with_txn_with_log(web3, geth_fixture_data): @pytest.fixture(scope="module") def txn_hash_with_log(geth_fixture_data): return geth_fixture_data['txn_hash_with_log'] + + +@pytest.fixture(scope="module") +def block_hash_revert_no_msg(geth_fixture_data): + return geth_fixture_data['block_hash_revert_no_msg'] + + +@pytest.fixture(scope="module") +def block_hash_revert_with_msg(geth_fixture_data): + return geth_fixture_data['block_hash_revert_with_msg'] + + +@pytest.fixture(scope="module") +def revert_contract(web3, revert_contract_factory, geth_fixture_data): + return revert_contract_factory(address=geth_fixture_data['revert_address']) diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 709d76846a..5895db2003 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -741,6 +741,14 @@ def test_eth_call_with_0_result( result = web3.codec.decode_single('uint256', call_result) assert result == 0 + def test_eth_call_with_revert(self, web3: "Web3", revert_contract: "Contract") -> None: + coinbase = web3.eth.coinbase + txn_params = revert_contract._prepare_transaction(fn_name='normalFunction', transaction={'from': coinbase, 'to': revert_contract.address}) + call_result = web3.eth.call(txn_params) + assert is_string(call_result) + result = web3.codec.decode_single('bool', call_result) + assert result is True + def test_eth_estimateGas( self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress ) -> None: From c78774bec5c3b7e62b96402b07e9e89d2c39963f Mon Sep 17 00:00:00 2001 From: Keri Date: Thu, 30 Apr 2020 11:41:06 -0600 Subject: [PATCH 08/23] Minor refactoring, eth-tester tests passing --- tests/integration/conftest.py | 12 ++--- tests/integration/test_ethereum_tester.py | 31 +++++++++++++ web3/_utils/module_testing/eth_module.py | 6 ++- web3/_utils/module_testing/revert_contract.py | 46 +++++++++---------- 4 files changed, 63 insertions(+), 32 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 5b997ddecc..43650e43b1 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -27,14 +27,14 @@ def emitter_contract_factory(web3): return contract_factory +@pytest.fixture(scope="module") +def revert_contract_factory(web3): + contract_factory = web3.eth.contract(abi=_REVERT_CONTRACT_ABI, bytecode=REVERT_CONTRACT_BYTECODE) + return contract_factory + + @pytest.yield_fixture(scope="module") def event_loop(request): loop = asyncio.get_event_loop_policy().new_event_loop() yield loop loop.close() - - -@pytest.fixture(scope="module") -def revert_contract_factory(web3): - contract_factory = web3.eth.contract(abi=_REVERT_CONTRACT_ABI, bytecode=REVERT_CONTRACT_BYTECODE) - return contract_factory diff --git a/tests/integration/test_ethereum_tester.py b/tests/integration/test_ethereum_tester.py index b7ad3524ec..fc46c96fa4 100644 --- a/tests/integration/test_ethereum_tester.py +++ b/tests/integration/test_ethereum_tester.py @@ -21,6 +21,9 @@ from web3._utils.module_testing.emitter_contract import ( EMITTER_ENUM, ) +from web3.exceptions import ( + SolidityError, +) from web3.providers.eth_tester import ( EthereumTesterProvider, ) @@ -135,6 +138,30 @@ def txn_hash_with_log(block_with_txn_with_log): return block_with_txn_with_log['transactions'][0] +# +# Revert Contract Setup +# +@pytest.fixture(scope="module") +def revert_contract_deploy_txn_hash(web3, revert_contract_factory): + deploy_txn_hash = revert_contract_factory.constructor().transact({'from': web3.eth.coinbase}) + return deploy_txn_hash + + +@pytest.fixture(scope="module") +def revert_contract(web3, revert_contract_factory, revert_contract_deploy_txn_hash): + deploy_receipt = web3.eth.waitForTransactionReceipt(revert_contract_deploy_txn_hash) + assert is_dict(deploy_receipt) + contract_address = deploy_receipt['contractAddress'] + assert is_checksum_address(contract_address) + return revert_contract_factory(contract_address) + + +@pytest.fixture(scope="module") +def revert_contract_address(revert_contract, address_conversion_func): + return address_conversion_func(revert_contract.address) + + + UNLOCKABLE_PRIVATE_KEY = '0x392f63a79b1ff8774845f3fa69de4a13800a59e7083f5187f1558f0797ad0f01' @@ -309,6 +336,10 @@ def test_eth_chainId(self, web3): def test_eth_getTransactionReceipt_mined(self, web3, block_with_txn, mined_txn_hash): super().test_eth_getTransactionReceipt_mined(web3, block_with_txn, mined_txn_hash) + def test_eth_call_revert_with_msg(self, web3: "Web3", revert_contract: "Contract") -> None: + with pytest.raises(SolidityError, match='foo'): + super().test_eth_call_with_revert(web3, revert_contract) + class TestEthereumTesterVersionModule(VersionModuleTest): pass diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 5895db2003..87a7070a6f 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -741,9 +741,11 @@ def test_eth_call_with_0_result( result = web3.codec.decode_single('uint256', call_result) assert result == 0 - def test_eth_call_with_revert(self, web3: "Web3", revert_contract: "Contract") -> None: + def test_eth_call_revert_with_msg(self, web3: "Web3", revert_contract: "Contract", unlocked_account_dual_type: ChecksumAddress) -> None: coinbase = web3.eth.coinbase - txn_params = revert_contract._prepare_transaction(fn_name='normalFunction', transaction={'from': coinbase, 'to': revert_contract.address}) + txn_params = revert_contract._prepare_transaction(fn_name='revertWithMessage', transaction={'from': unlocked_account_dual_type, 'to': revert_contract.address}) + foo = revert_contract.functions.revertWithMessage().transact({'from': coinbase, 'to': revert_contract.address, 'gas': 320000}) + import pdb; pdb.set_trace() call_result = web3.eth.call(txn_params) assert is_string(call_result) result = web3.codec.decode_single('bool', call_result) diff --git a/web3/_utils/module_testing/revert_contract.py b/web3/_utils/module_testing/revert_contract.py index e8f37211c1..0623737cb9 100644 --- a/web3/_utils/module_testing/revert_contract.py +++ b/web3/_utils/module_testing/revert_contract.py @@ -1,14 +1,33 @@ import json -REVERT_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b5060f08061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b8414604f575b600080fd5b60476069565b005b6047603c565b605560b6565b604080519115158252519081900360200190f35b6040805162461bcd60e51b815260206004820152601b60248201527f46756e6374696f6e20686173206265656e2072657665727465642e0000000000604482015290519081900360640190fd5b60019056fea265627a7a723158202b5d1c5df2d5450324be8ee1af3ef7098f4b4acf5df16b1cb3cc86d4c48aa95664736f6c63430005100032" + +REVERT_CONTRACT_SOURCE = """ +pragma solidity ^0.6.1; + +contract RevertContract { + function normalFunction() public pure returns (bool) { + return true; + } + + function revertWithMessage() public pure { + revert('Function has been reverted.'); + } + + function revertWithoutMessage() public pure { + revert(); + } +} +""" + + +REVERT_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b50610123806100206000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b84146051575b600080fd5b60476071565b005b604f60df565b005b605760e4565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b600080fd5b6000600190509056fea264697066735822122062c811906544562ea796d11199e2d956938f2a76c2aa3053dc7ab2470d854c0a64736f6c63430006060033" -REVERT_CONTRACT_RUNTIME_CODE = "6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b8414604f575b600080fd5b60476069565b005b6047603c565b605560b6565b604080519115158252519081900360200190f35b6040805162461bcd60e51b815260206004820152601b60248201527f46756e6374696f6e20686173206265656e2072657665727465642e0000000000604482015290519081900360640190fd5b60019056fea26469706673582212204e6819701a04acfefd5a4b75221d095cac98d0a467116e264d73f1b3dc239b9064736f6c63430006010033" # noqa: E501 +REVERT_CONTRACT_RUNTIME_CODE = "6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b84146051575b600080fd5b60476071565b005b604f60df565b005b605760e4565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b600080fd5b6000600190509056fea264697066735822122062c811906544562ea796d11199e2d956938f2a76c2aa3053dc7ab2470d854c0a64736f6c63430006060033" # noqa: E501 _REVERT_CONTRACT_ABI = json.loads('''[ { - "constant": true, "inputs": [], "name": "normalFunction", "outputs": [ @@ -23,7 +42,6 @@ "type": "function" }, { - "constant": true, "inputs": [], "name": "revertWithMessage", "outputs": [], @@ -32,7 +50,6 @@ "type": "function" }, { - "constant": true, "inputs": [], "name": "revertWithoutMessage", "outputs": [], @@ -41,22 +58,3 @@ "type": "function" } ]''') - - -REVERT_CONTRACT_SOURCE = """ -pragma solidity ^0.6.1; - -contract RevertContract { - function normalFunction() public pure returns (bool) { - return true; - } - - function revertWithMessage() public pure { - revert('Function has been reverted.'); - } - - function revertWithoutMessage() public pure { - revert(); - } -} -""" From 34206eaad72a6b2294ef99a5408741d617ae1dae Mon Sep 17 00:00:00 2001 From: Keri Date: Fri, 8 May 2020 16:08:03 -0600 Subject: [PATCH 09/23] Add parity fixture with revert contract --- .../generate_fixtures/go_ethereum.py | 13 +++++-- tests/integration/generate_fixtures/parity.py | 4 +-- tests/integration/parity/conftest.py | 34 ++++++++++++++----- web3/_utils/module_testing/eth_module.py | 1 - web3/_utils/module_testing/parity_module.py | 2 +- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/tests/integration/generate_fixtures/go_ethereum.py b/tests/integration/generate_fixtures/go_ethereum.py index c5eb7568b2..43db377b4b 100644 --- a/tests/integration/generate_fixtures/go_ethereum.py +++ b/tests/integration/generate_fixtures/go_ethereum.py @@ -39,6 +39,10 @@ MATH_ABI, MATH_BYTECODE, ) +from web3._utils.module_testing.revert_contract import ( + _REVERT_CONTRACT_ABI, + REVERT_CONTRACT_BYTECODE, +) COINBASE = '0xdc544d1aa88ff8bbd2f2aec754b1f1e99e1812fd' COINBASE_PK = '0x58d23b55bc9cdce1f18c2500f40ff4ab7245df9a89505e9b1fa4851f623d241d' @@ -370,7 +374,7 @@ def setup_chain_state(web3): abi=_REVERT_CONTRACT_ABI, bytecode=REVERT_CONTRACT_BYTECODE, ) - revert_deploy_receipt = deploy_contract(web3, 'revert', revert_contract_factory) + revert_deploy_receipt = common.deploy_contract(web3, 'revert', revert_contract_factory) revert_contract = revert_contract_factory(revert_deploy_receipt['contractAddress']) txn_hash_normal_function = revert_contract.functions.normalFunction().transact( @@ -381,7 +385,7 @@ def setup_chain_state(web3): {'gas': 320000, 'from': web3.eth.coinbase} ) print('TXN_HASH_REVERT_WITH_MSG:', txn_hash_revert_with_msg) - txn_receipt_revert_with_msg = mine_transaction_hash(web3, txn_hash_revert_with_msg) + txn_receipt_revert_with_msg = common.mine_transaction_hash(web3, txn_hash_revert_with_msg) block_hash_revert_with_msg = web3.eth.getBlock(txn_receipt_revert_with_msg['blockHash']) print('BLOCK_HASH_REVERT_WITH_MSG:', block_hash_revert_with_msg['hash']) @@ -389,7 +393,7 @@ def setup_chain_state(web3): {'gas': 320000, 'from': web3.eth.coinbase} ) print('TXN_HASH_REVERT_WITH_NO_MSG:', txn_hash_revert_with_no_msg) - txn_receipt_revert_with_no_msg = mine_transaction_hash(web3, txn_hash_revert_with_no_msg) + txn_receipt_revert_with_no_msg = common.mine_transaction_hash(web3, txn_hash_revert_with_no_msg) block_hash_revert_no_msg = web3.eth.getBlock(txn_receipt_revert_with_no_msg['blockHash']) print('BLOCK_HASH_REVERT_NO_MSG:', block_hash_revert_no_msg['hash']) @@ -430,6 +434,9 @@ def setup_chain_state(web3): 'empty_block_hash': empty_block['hash'], 'mined_txn_hash': mined_txn_hash, 'block_with_txn_hash': block_with_txn['hash'], + 'revert_address': revert_deploy_receipt['contractAddress'], + 'block_hash_revert_with_msg': block_hash_revert_with_msg['hash'], + 'block_hash_revert_no_msg': block_hash_revert_no_msg['hash'], } return geth_fixture diff --git a/tests/integration/generate_fixtures/parity.py b/tests/integration/generate_fixtures/parity.py index 373b1e3786..bd8ec43e0b 100644 --- a/tests/integration/generate_fixtures/parity.py +++ b/tests/integration/generate_fixtures/parity.py @@ -208,8 +208,8 @@ def generate_parity_fixture(destination_dir): genesis_file_path, geth_ipc_path, geth_port, - str(CHAIN_CONFIG['params']['networkID'])) - ) + str(CHAIN_CONFIG['params']['networkID']) + )) # set up fixtures common.wait_for_socket(geth_ipc_path) web3_geth = Web3(Web3.IPCProvider(geth_ipc_path)) diff --git a/tests/integration/parity/conftest.py b/tests/integration/parity/conftest.py index af762d419f..83e375622c 100644 --- a/tests/integration/parity/conftest.py +++ b/tests/integration/parity/conftest.py @@ -22,18 +22,20 @@ PARITY_2_5_13_FIXTURE = { 'zip': 'parity-2.5.13-fixture.zip', 'coinbase': 'dc544d1aa88ff8bbd2f2aec754b1f1e99e1812fd', - 'block_hash_with_log': '0xbeb77df6226309c33a8d70cb824ecda43c42a9c24bd587a500af717ba102a812', - 'block_with_txn_hash': '0xe7bca75ebc85d0f360c76732cee48384fffa9a9e58a272d62c14f6ea146086ac', + 'block_hash_revert_no_msg': '0x3244617196b9467687cbab23798c00077954452771d38d05d3b8d484b83c5de5', + 'block_hash_revert_with_msg': '0x7d7917231f1a9e816f11ff93842d543c35075a7cd5d75854f28324409910836c', + 'block_hash_with_log': '0x19947203802e02d4659698c5684322ef67c4146fb1f420a6da371116be78047c', + 'block_with_txn_hash': '0xc26f5610ddbfd6fbe179110e09af6df06c2998ed0c9c623417480b2c795a6f01', 'emitter_address': '0x4aA591a07989b4F810E2F5cE97e769D60710f168', - 'emitter_deploy_txn_hash': '0xef44cd36d86c41640c710026acf45f3b63731f72ac2a1744a005f6690bfa7613', - 'empty_block_hash': '0xb62b8317a7a36b4f77aaad39fd95be2932e47a8e9e5c3ea49559fc747ade047a', + 'emitter_deploy_txn_hash': '0xbd4ca1b3cdb6bd711aec67dbb5a90c4d8f7910dab5bde70e5b8a9f8ad689b373', + 'empty_block_hash': '0x7a877c858e2d5447305e0901580022553cab34fdbc78c22c33b627e2a6a9ba5a', 'keyfile_pw': 'web3py-test', 'math_address': '0xd794C821fCCFF5D96F5Db44af7e29977630A9dc2', - 'math_deploy_txn_hash': '0x356278504f40db914545888674cedc0d8ccd4a939665eb4ab83b569db0c477cb', - 'mined_txn_hash': '0x0846b46335384fd73273e1e402072a21ed2d52f5af6616e49c019d7abe511d2d', + 'math_deploy_txn_hash': '0xa266faa2c729660d88e0c72994b5cd0e85ff9fe05846a6575b9095d433f51957', + 'mined_txn_hash': '0xd9f2298f6bc02f5ede8db75eac721f2365b6d9a96e1ca1bb0724d316de8f626c', 'raw_txn_account': '0x39EEed73fb1D3855E90Cbd42f348b3D7b340aAA6', - 'txn_hash_with_log': '0x1407ae0fbc79622e60c21b59b0cb047a5f8d0219ad95969096c8c0e23f342f5c' -} + 'revert_address': '0x14F3674571D76Bf66cA8EBD84dC02060933400b4', + 'txn_hash_with_log': '0x51c7e37746062cb7ff1f337d3ab725fa540c6d20fc9304b08dad5e80b3601511'} @pytest.fixture(scope='module') @@ -204,3 +206,19 @@ def txn_filter_params(coinbase): "toBlock": "latest", "fromAddress": [coinbase], } + + + +@pytest.fixture(scope="module") +def block_hash_revert_no_msg(parity_fixture_data): + return parity_fixture_data['block_hash_revert_no_msg'] + + +@pytest.fixture(scope="module") +def block_hash_revert_with_msg(parity_fixture_data): + return parity_fixture_data['block_hash_revert_with_msg'] + + +@pytest.fixture(scope="module") +def revert_contract(revert_contract_factory, parity_fixture_data): + return revert_contract_factory(address=parity_fixture_data['revert_address']) diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 87a7070a6f..59db5494ed 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -745,7 +745,6 @@ def test_eth_call_revert_with_msg(self, web3: "Web3", revert_contract: "Contract coinbase = web3.eth.coinbase txn_params = revert_contract._prepare_transaction(fn_name='revertWithMessage', transaction={'from': unlocked_account_dual_type, 'to': revert_contract.address}) foo = revert_contract.functions.revertWithMessage().transact({'from': coinbase, 'to': revert_contract.address, 'gas': 320000}) - import pdb; pdb.set_trace() call_result = web3.eth.call(txn_params) assert is_string(call_result) result = web3.codec.decode_single('bool', call_result) diff --git a/web3/_utils/module_testing/parity_module.py b/web3/_utils/module_testing/parity_module.py index 4d4f1a3cdb..f39a3eeeae 100644 --- a/web3/_utils/module_testing/parity_module.py +++ b/web3/_utils/module_testing/parity_module.py @@ -30,7 +30,7 @@ class ParityTraceModuleTest: def test_trace_replay_transaction( - self, web3: "Web3", parity_fixture_data: Dict[str, str] + self, web3: "Web3", parity_fixture_data: Dict[str, str], ) -> None: trace = web3.parity.traceReplayTransaction(HexStr(parity_fixture_data['mined_txn_hash'])) From 962b45781d278f67025de2ebed9619b4afa119ec Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Fri, 24 Jul 2020 09:55:46 -0600 Subject: [PATCH 10/23] address linting issues --- .../contracts/test_contract_call_interface.py | 4 ---- tests/integration/conftest.py | 8 ++++++-- tests/integration/generate_fixtures/parity.py | 3 ++- tests/integration/parity/conftest.py | 5 ++--- tests/integration/test_ethereum_tester.py | 1 - web3/_utils/module_testing/eth_module.py | 19 ++++++++++++++++--- web3/_utils/module_testing/revert_contract.py | 3 +-- 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/tests/core/contracts/test_contract_call_interface.py b/tests/core/contracts/test_contract_call_interface.py index ebf1e7c363..af50991f4e 100644 --- a/tests/core/contracts/test_contract_call_interface.py +++ b/tests/core/contracts/test_contract_call_interface.py @@ -189,10 +189,6 @@ def nested_tuple_contract(web3, NestedTupleContract, address_conversion_func): return deploy(web3, NestedTupleContract, address_conversion_func) -@pytest.fixture() -def revert_contract(web3, RevertContract, address_conversion_func): - return deploy(web3, RevertContract, address_conversion_func) - def test_invalid_address_in_deploy_arg(web3, WithConstructorAddressArgumentsContract): with pytest.raises(InvalidAddress): WithConstructorAddressArgumentsContract.constructor( diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 43650e43b1..a9ddbbd19e 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -23,13 +23,17 @@ def math_contract_factory(web3): @pytest.fixture(scope="module") def emitter_contract_factory(web3): - contract_factory = web3.eth.contract(abi=CONTRACT_EMITTER_ABI, bytecode=CONTRACT_EMITTER_CODE) + contract_factory = web3.eth.contract( + abi=CONTRACT_EMITTER_ABI, bytecode=CONTRACT_EMITTER_CODE + ) return contract_factory @pytest.fixture(scope="module") def revert_contract_factory(web3): - contract_factory = web3.eth.contract(abi=_REVERT_CONTRACT_ABI, bytecode=REVERT_CONTRACT_BYTECODE) + contract_factory = web3.eth.contract( + abi=_REVERT_CONTRACT_ABI, bytecode=REVERT_CONTRACT_BYTECODE + ) return contract_factory diff --git a/tests/integration/generate_fixtures/parity.py b/tests/integration/generate_fixtures/parity.py index bd8ec43e0b..6e2ac4c7e5 100644 --- a/tests/integration/generate_fixtures/parity.py +++ b/tests/integration/generate_fixtures/parity.py @@ -209,7 +209,8 @@ def generate_parity_fixture(destination_dir): geth_ipc_path, geth_port, str(CHAIN_CONFIG['params']['networkID']) - )) + ) + ) # set up fixtures common.wait_for_socket(geth_ipc_path) web3_geth = Web3(Web3.IPCProvider(geth_ipc_path)) diff --git a/tests/integration/parity/conftest.py b/tests/integration/parity/conftest.py index 83e375622c..0477d28ff5 100644 --- a/tests/integration/parity/conftest.py +++ b/tests/integration/parity/conftest.py @@ -22,8 +22,8 @@ PARITY_2_5_13_FIXTURE = { 'zip': 'parity-2.5.13-fixture.zip', 'coinbase': 'dc544d1aa88ff8bbd2f2aec754b1f1e99e1812fd', - 'block_hash_revert_no_msg': '0x3244617196b9467687cbab23798c00077954452771d38d05d3b8d484b83c5de5', - 'block_hash_revert_with_msg': '0x7d7917231f1a9e816f11ff93842d543c35075a7cd5d75854f28324409910836c', + 'block_hash_revert_no_msg': '0x3244617196b9467687cbab23798c00077954452771d38d05d3b8d484b83c5de5', # noqa: E501 + 'block_hash_revert_with_msg': '0x7d7917231f1a9e816f11ff93842d543c35075a7cd5d75854f28324409910836c', # noqa: E501 'block_hash_with_log': '0x19947203802e02d4659698c5684322ef67c4146fb1f420a6da371116be78047c', 'block_with_txn_hash': '0xc26f5610ddbfd6fbe179110e09af6df06c2998ed0c9c623417480b2c795a6f01', 'emitter_address': '0x4aA591a07989b4F810E2F5cE97e769D60710f168', @@ -208,7 +208,6 @@ def txn_filter_params(coinbase): } - @pytest.fixture(scope="module") def block_hash_revert_no_msg(parity_fixture_data): return parity_fixture_data['block_hash_revert_no_msg'] diff --git a/tests/integration/test_ethereum_tester.py b/tests/integration/test_ethereum_tester.py index fc46c96fa4..b0b6ce97eb 100644 --- a/tests/integration/test_ethereum_tester.py +++ b/tests/integration/test_ethereum_tester.py @@ -161,7 +161,6 @@ def revert_contract_address(revert_contract, address_conversion_func): return address_conversion_func(revert_contract.address) - UNLOCKABLE_PRIVATE_KEY = '0x392f63a79b1ff8774845f3fa69de4a13800a59e7083f5187f1558f0797ad0f01' diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 59db5494ed..1c9560363a 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -741,10 +741,23 @@ def test_eth_call_with_0_result( result = web3.codec.decode_single('uint256', call_result) assert result == 0 - def test_eth_call_revert_with_msg(self, web3: "Web3", revert_contract: "Contract", unlocked_account_dual_type: ChecksumAddress) -> None: + def test_eth_call_revert_with_msg( + self, + web3: "Web3", + revert_contract: "Contract", + unlocked_account_dual_type: ChecksumAddress, + ) -> None: coinbase = web3.eth.coinbase - txn_params = revert_contract._prepare_transaction(fn_name='revertWithMessage', transaction={'from': unlocked_account_dual_type, 'to': revert_contract.address}) - foo = revert_contract.functions.revertWithMessage().transact({'from': coinbase, 'to': revert_contract.address, 'gas': 320000}) + txn_params = revert_contract._prepare_transaction( + fn_name="revertWithMessage", + transaction={ + "from": unlocked_account_dual_type, + "to": revert_contract.address, + }, + ) + revert_contract.functions.revertWithMessage().transact( + {"from": coinbase, "to": revert_contract.address, "gas": Wei(320000)} + ) call_result = web3.eth.call(txn_params) assert is_string(call_result) result = web3.codec.decode_single('bool', call_result) diff --git a/web3/_utils/module_testing/revert_contract.py b/web3/_utils/module_testing/revert_contract.py index 0623737cb9..6a7e65ceed 100644 --- a/web3/_utils/module_testing/revert_contract.py +++ b/web3/_utils/module_testing/revert_contract.py @@ -1,6 +1,5 @@ import json - REVERT_CONTRACT_SOURCE = """ pragma solidity ^0.6.1; @@ -20,7 +19,7 @@ """ -REVERT_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b50610123806100206000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b84146051575b600080fd5b60476071565b005b604f60df565b005b605760e4565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b600080fd5b6000600190509056fea264697066735822122062c811906544562ea796d11199e2d956938f2a76c2aa3053dc7ab2470d854c0a64736f6c63430006060033" +REVERT_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b50610123806100206000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b84146051575b600080fd5b60476071565b005b604f60df565b005b605760e4565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b600080fd5b6000600190509056fea264697066735822122062c811906544562ea796d11199e2d956938f2a76c2aa3053dc7ab2470d854c0a64736f6c63430006060033" # noqa: E501 REVERT_CONTRACT_RUNTIME_CODE = "6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b84146051575b600080fd5b60476071565b005b604f60df565b005b605760e4565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b600080fd5b6000600190509056fea264697066735822122062c811906544562ea796d11199e2d956938f2a76c2aa3053dc7ab2470d854c0a64736f6c63430006060033" # noqa: E501 From bc3f918fcabe6a63e11b5cd8c8f16cbf7ddd19a4 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Mon, 27 Jul 2020 14:46:33 -0600 Subject: [PATCH 11/23] fix eth_module test and naming --- tests/integration/test_ethereum_tester.py | 8 ++----- web3/_utils/module_testing/eth_module.py | 28 ++++++++++------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/tests/integration/test_ethereum_tester.py b/tests/integration/test_ethereum_tester.py index b0b6ce97eb..eef3cf54c2 100644 --- a/tests/integration/test_ethereum_tester.py +++ b/tests/integration/test_ethereum_tester.py @@ -21,9 +21,6 @@ from web3._utils.module_testing.emitter_contract import ( EMITTER_ENUM, ) -from web3.exceptions import ( - SolidityError, -) from web3.providers.eth_tester import ( EthereumTesterProvider, ) @@ -335,9 +332,8 @@ def test_eth_chainId(self, web3): def test_eth_getTransactionReceipt_mined(self, web3, block_with_txn, mined_txn_hash): super().test_eth_getTransactionReceipt_mined(web3, block_with_txn, mined_txn_hash) - def test_eth_call_revert_with_msg(self, web3: "Web3", revert_contract: "Contract") -> None: - with pytest.raises(SolidityError, match='foo'): - super().test_eth_call_with_revert(web3, revert_contract) + def test_eth_call_revert_with_msg(self, web3, revert_contract, unlocked_account) -> None: + super().test_eth_call_revert_with_msg(web3, revert_contract, unlocked_account) class TestEthereumTesterVersionModule(VersionModuleTest): diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 1c9560363a..bc5376a49f 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -37,6 +37,7 @@ BlockNotFound, InvalidAddress, NameNotFound, + SolidityError, TransactionNotFound, ) from web3.types import ( # noqa: F401 @@ -745,23 +746,18 @@ def test_eth_call_revert_with_msg( self, web3: "Web3", revert_contract: "Contract", - unlocked_account_dual_type: ChecksumAddress, + unlocked_account: ChecksumAddress, ) -> None: - coinbase = web3.eth.coinbase - txn_params = revert_contract._prepare_transaction( - fn_name="revertWithMessage", - transaction={ - "from": unlocked_account_dual_type, - "to": revert_contract.address, - }, - ) - revert_contract.functions.revertWithMessage().transact( - {"from": coinbase, "to": revert_contract.address, "gas": Wei(320000)} - ) - call_result = web3.eth.call(txn_params) - assert is_string(call_result) - result = web3.codec.decode_single('bool', call_result) - assert result is True + with pytest.raises(SolidityError, match='foo'): + coinbase = web3.eth.coinbase + txn_params = revert_contract._prepare_transaction( + fn_name="revertWithMessage", + transaction={ + "from": unlocked_account, + "to": revert_contract.address, + }, + ) + web3.eth.call(txn_params) def test_eth_estimateGas( self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress From 256499f3b122ebe69276ea99d25cffa5dd6e475d Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Mon, 27 Jul 2020 15:32:18 -0600 Subject: [PATCH 12/23] contain eth_tester exceptions --- web3/manager.py | 11 ++--------- web3/providers/eth_tester/main.py | 6 ++++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/web3/manager.py b/web3/manager.py index 54f8c1ec38..9402096397 100644 --- a/web3/manager.py +++ b/web3/manager.py @@ -14,7 +14,6 @@ import uuid from uuid import UUID -import eth_tester from eth_utils.toolz import ( pipe, ) @@ -29,9 +28,6 @@ from web3.datastructures import ( NamedElementOnion, ) -from web3.exceptions import ( - SolidityError, -) from web3.middleware import ( abi_middleware, attrdict_middleware, @@ -155,13 +151,10 @@ def request_blocking( """ Make a synchronous request using the provider """ - try: - response = self._make_request(method, params) - except eth_tester.exceptions.TransactionFailed as e: - raise SolidityError(*e.args) + response = self._make_request(method, params) if "error" in response: - response = apply_error_formatters(error_formatters, response) + apply_error_formatters(error_formatters, response) raise ValueError(response["error"]) elif response['result'] is None: apply_error_formatters(error_formatters, response, params) diff --git a/web3/providers/eth_tester/main.py b/web3/providers/eth_tester/main.py index 4860e7cab6..f6ba672f2a 100644 --- a/web3/providers/eth_tester/main.py +++ b/web3/providers/eth_tester/main.py @@ -9,6 +9,9 @@ from web3._utils.compat import ( Literal, ) +from web3.exceptions import ( + SolidityError, +) from web3.providers import ( BaseProvider, ) @@ -84,6 +87,7 @@ def __init__( def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: namespace, _, endpoint = method.partition('_') + from eth_tester.exceptions import TransactionFailed try: delegator = self.api_endpoints[namespace][endpoint] except KeyError: @@ -97,6 +101,8 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: return RPCResponse({ "error": "RPC Endpoint has not been implemented: {0}".format(method), }) + except TransactionFailed as e: + raise SolidityError(*e.args) else: return { 'result': response, From 9ba8de48ec55e17b9f9cddfcc221d02e107d7d1b Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Tue, 28 Jul 2020 10:45:50 -0600 Subject: [PATCH 13/23] fix lint --- web3/_utils/module_testing/eth_module.py | 1 - 1 file changed, 1 deletion(-) diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index bc5376a49f..69bd04e9f9 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -749,7 +749,6 @@ def test_eth_call_revert_with_msg( unlocked_account: ChecksumAddress, ) -> None: with pytest.raises(SolidityError, match='foo'): - coinbase = web3.eth.coinbase txn_params = revert_contract._prepare_transaction( fn_name="revertWithMessage", transaction={ From e1ce1268dbc784bb8aa5162868af23366a524b30 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Fri, 31 Jul 2020 15:30:37 -0600 Subject: [PATCH 14/23] check eth_estimateGas for revert exception --- web3/_utils/method_formatters.py | 1 + web3/_utils/module_testing/eth_module.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py index d53223eb47..be0dadfeea 100644 --- a/web3/_utils/method_formatters.py +++ b/web3/_utils/method_formatters.py @@ -531,6 +531,7 @@ def raise_solidity_error_on_revert(response: RPCResponse) -> RPCResponse: ERROR_FORMATTERS: Dict[RPCEndpoint, Callable[..., Any]] = { + RPC.eth_estimateGas: raise_solidity_error_on_revert, RPC.eth_call: raise_solidity_error_on_revert, } diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 69bd04e9f9..66bbab8721 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -748,7 +748,7 @@ def test_eth_call_revert_with_msg( revert_contract: "Contract", unlocked_account: ChecksumAddress, ) -> None: - with pytest.raises(SolidityError, match='foo'): + with pytest.raises(SolidityError, match='Function has been reverted.'): txn_params = revert_contract._prepare_transaction( fn_name="revertWithMessage", transaction={ From 71975d9380e00fca5dc6d730e1501007e1340183 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Mon, 10 Aug 2020 16:23:21 -0600 Subject: [PATCH 15/23] wip: new fixture + latest geth revert messages --- tests/integration/temp.zip | Bin 0 -> 21499 bytes tests/integration/test_ethereum_tester.py | 3 +++ web3/_utils/module_testing/eth_module.py | 16 ++++++++++++++++ web3/manager.py | 6 ++++++ 4 files changed, 25 insertions(+) create mode 100644 tests/integration/temp.zip diff --git a/tests/integration/temp.zip b/tests/integration/temp.zip new file mode 100644 index 0000000000000000000000000000000000000000..6daf43d8e9fd849be2ee15b2e176c2651873cd6f GIT binary patch literal 21499 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 S0Q7hNe7n2C4p`#;zy1#l%1W64 literal 0 HcmV?d00001 diff --git a/tests/integration/test_ethereum_tester.py b/tests/integration/test_ethereum_tester.py index eef3cf54c2..503ab3ece5 100644 --- a/tests/integration/test_ethereum_tester.py +++ b/tests/integration/test_ethereum_tester.py @@ -335,6 +335,9 @@ def test_eth_getTransactionReceipt_mined(self, web3, block_with_txn, mined_txn_h def test_eth_call_revert_with_msg(self, web3, revert_contract, unlocked_account) -> None: super().test_eth_call_revert_with_msg(web3, revert_contract, unlocked_account) + def test_eth_estimateGas_revert_with_msg(self, web3, revert_contract, unlocked_account) -> None: + super().test_eth_estimateGas_revert_with_msg(web3, revert_contract, unlocked_account) + class TestEthereumTesterVersionModule(VersionModuleTest): pass diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 66bbab8721..ba2d0d3c7e 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -758,6 +758,22 @@ def test_eth_call_revert_with_msg( ) web3.eth.call(txn_params) + def test_eth_estimateGas_revert_with_msg( + self, + web3: "Web3", + revert_contract: "Contract", + unlocked_account: ChecksumAddress, + ) -> None: + with pytest.raises(SolidityError, match='Function has been reverted.'): + txn_params = revert_contract._prepare_transaction( + fn_name="revertWithMessage", + transaction={ + "from": unlocked_account, + "to": revert_contract.address, + }, + ) + web3.eth.estimateGas(txn_params) + def test_eth_estimateGas( self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress ) -> None: diff --git a/web3/manager.py b/web3/manager.py index 9402096397..448350ffc4 100644 --- a/web3/manager.py +++ b/web3/manager.py @@ -28,6 +28,9 @@ from web3.datastructures import ( NamedElementOnion, ) +from web3.exceptions import ( + SolidityError, +) from web3.middleware import ( abi_middleware, attrdict_middleware, @@ -154,6 +157,9 @@ def request_blocking( response = self._make_request(method, params) if "error" in response: + if response['error']['code'] == 3: + raise SolidityError(response['error']['message']) + apply_error_formatters(error_formatters, response) raise ValueError(response["error"]) elif response['result'] is None: From d791738a56c208f2e3ee665b5638e1abdfd5ece2 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Mon, 24 Aug 2020 14:31:57 -0600 Subject: [PATCH 16/23] update geth fixture --- tests/integration/generate_fixtures/common.py | 6 +++++- tests/integration/go_ethereum/conftest.py | 3 ++- tests/integration/temp.zip | Bin 21499 -> 0 bytes tests/integration/test.zip | Bin 0 -> 21551 bytes tests/integration/tester.zip | Bin 0 -> 18757 bytes 5 files changed, 7 insertions(+), 2 deletions(-) delete mode 100644 tests/integration/temp.zip create mode 100644 tests/integration/test.zip create mode 100644 tests/integration/tester.zip diff --git a/tests/integration/generate_fixtures/common.py b/tests/integration/generate_fixtures/common.py index 07813728cf..31b5992b88 100644 --- a/tests/integration/generate_fixtures/common.py +++ b/tests/integration/generate_fixtures/common.py @@ -34,6 +34,10 @@ "config": { "chainId": 131277322940537, # the string 'web3py' as an integer "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, @@ -213,7 +217,7 @@ def mine_block(web3): def mine_transaction_hash(web3, txn_hash): start_time = time.time() web3.geth.miner.start(1) - while time.time() < start_time + 120: + while time.time() < start_time + 240: try: receipt = web3.eth.getTransactionReceipt(txn_hash) except TransactionNotFound: diff --git a/tests/integration/go_ethereum/conftest.py b/tests/integration/go_ethereum/conftest.py index 8c2d963c04..b5e63c19c0 100644 --- a/tests/integration/go_ethereum/conftest.py +++ b/tests/integration/go_ethereum/conftest.py @@ -19,7 +19,8 @@ KEYFILE_PW = 'web3py-test' -GETH_1919_ZIP = 'geth-1.9.19-fixture.zip' +# GETH_1919_ZIP = 'geth-1.9.19-fixture.zip' +GETH_1919_ZIP = 'test.zip' @pytest.fixture(scope='module') diff --git a/tests/integration/temp.zip b/tests/integration/temp.zip deleted file mode 100644 index 6daf43d8e9fd849be2ee15b2e176c2651873cd6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21499 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 S0Q7hNe7n2C4p`#;zy1#l%1W64 diff --git a/tests/integration/test.zip b/tests/integration/test.zip new file mode 100644 index 0000000000000000000000000000000000000000..2b3dae1dbbd038fff5c0a1b3042d3202f632f55f GIT binary patch literal 21551 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 aRr`kl-mJjp8UuqK5IzPTd1vMh;sF4R8hT*> literal 0 HcmV?d00001 diff --git a/tests/integration/tester.zip b/tests/integration/tester.zip new file mode 100644 index 0000000000000000000000000000000000000000..e5f2b5845712509720ef4e27712a71bc9272eac0 GIT binary patch literal 18757 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 pM*iiCpT-!!Ktwrz+kO5&jX0#m!5>n Date: Mon, 24 Aug 2020 15:39:49 -0600 Subject: [PATCH 17/23] handle eth-tester revert messages --- web3/manager.py | 3 --- web3/providers/eth_tester/main.py | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/web3/manager.py b/web3/manager.py index 448350ffc4..0a494bf0b1 100644 --- a/web3/manager.py +++ b/web3/manager.py @@ -157,9 +157,6 @@ def request_blocking( response = self._make_request(method, params) if "error" in response: - if response['error']['code'] == 3: - raise SolidityError(response['error']['message']) - apply_error_formatters(error_formatters, response) raise ValueError(response["error"]) elif response['result'] is None: diff --git a/web3/providers/eth_tester/main.py b/web3/providers/eth_tester/main.py index f6ba672f2a..b6710e5237 100644 --- a/web3/providers/eth_tester/main.py +++ b/web3/providers/eth_tester/main.py @@ -5,6 +5,9 @@ Dict, Optional, ) +from eth_abi import ( + decode_single, +) from web3._utils.compat import ( Literal, @@ -102,7 +105,8 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: "error": "RPC Endpoint has not been implemented: {0}".format(method), }) except TransactionFailed as e: - raise SolidityError(*e.args) + revert_msg = decode_single('(string)', e.args[0].args[0][4:]) + raise SolidityError(revert_msg) else: return { 'result': response, From 53c1b2455af6afeb7755948750d435f1c319ae48 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Fri, 25 Sep 2020 16:54:34 -0600 Subject: [PATCH 18/23] wip: standardize client errors --- tests/integration/parity/common.py | 4 +++ web3/_utils/method_formatters.py | 38 ++++++++++++++++-------- web3/_utils/module_testing/eth_module.py | 4 +-- web3/providers/eth_tester/main.py | 3 +- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/tests/integration/parity/common.py b/tests/integration/parity/common.py index 148542acad..0851ee95f0 100644 --- a/tests/integration/parity/common.py +++ b/tests/integration/parity/common.py @@ -29,6 +29,10 @@ def _check_web3_clientVersion(self, client_version): class ParityEthModuleTest(EthModuleTest): + @pytest.mark.xfail(reason='Parity returns a gas value even when a function will revert') + def test_eth_estimateGas_revert_with_msg(self, web3, revert_contract, unlocked_account): + super().test_eth_estimateGas_revert_with_msg(web3, revert_contract, unlocked_account) + @pytest.mark.xfail(reason='Parity dropped "pending" option in 1.11.1') def test_eth_getBlockByNumber_pending(self, web3): super().test_eth_getBlockByNumber_pending(web3) diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py index be0dadfeea..68bfb3d55c 100644 --- a/web3/_utils/method_formatters.py +++ b/web3/_utils/method_formatters.py @@ -402,13 +402,21 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]: } +def check_for_parity_revert(response: Any) -> Any: + # Parity returns '0x' if reverted, without an exception + # TODO: false positives? + if response == '0x': + # Mirroring Geth: 'execution reverted: ' + raise SolidityError('execution reverted') + return HexBytes(response) + PYTHONIC_RESULT_FORMATTERS: Dict[RPCEndpoint, Callable[..., Any]] = { # Eth RPC.eth_accounts: apply_list_to_array_formatter(to_checksum_address), RPC.eth_blockNumber: to_integer_if_hex, RPC.eth_chainId: to_integer_if_hex, RPC.eth_coinbase: to_checksum_address, - RPC.eth_call: HexBytes, + RPC.eth_call: check_for_parity_revert, RPC.eth_estimateGas: to_integer_if_hex, RPC.eth_gasPrice: to_integer_if_hex, RPC.eth_getBalance: to_integer_if_hex, @@ -506,19 +514,25 @@ def get_revert_reason(response: RPCResponse) -> str: if not isinstance(response['error'], dict): return None - data = response['error'].get('data', '') + if 'message' in response['error']: + return response['error']['message'] - if data == 'Reverted 0x': - return '' + # TODO: by this point, all tested client's reverts have been accounted for + return '' - # "Reverted", function selector and offset are always the same for revert errors - prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' - if not data.startswith(prefix): - return None + # data = response['error'].get('data', '') + + # if data == 'Reverted 0x': + # return '' + + # # "Reverted", function selector and offset are always the same for revert errors + # prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' + # if not data.startswith(prefix): + # return None - reason_length = int(data[len(prefix):len(prefix) + 64], 16) - reason = data[len(prefix) + 64:len(prefix) + 64 + reason_length * 2] - return bytes.fromhex(reason).decode('utf8') + # reason_length = int(data[len(prefix):len(prefix) + 64], 16) + # reason = data[len(prefix) + 64:len(prefix) + 64 + reason_length * 2] + # return bytes.fromhex(reason).decode('utf8') def raise_solidity_error_on_revert(response: RPCResponse) -> RPCResponse: @@ -622,7 +636,7 @@ def get_error_formatters( method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]] ) -> Callable[..., Any]: # Note error formatters work on the full response dict - error_formatter_maps = (NULL_RESULT_FORMATTERS,) + error_formatter_maps = (NULL_RESULT_FORMATTERS, ERROR_FORMATTERS) formatters = combine_formatters(error_formatter_maps, method_name) return compose(*formatters) diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index ba2d0d3c7e..95d758b9c4 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -748,7 +748,7 @@ def test_eth_call_revert_with_msg( revert_contract: "Contract", unlocked_account: ChecksumAddress, ) -> None: - with pytest.raises(SolidityError, match='Function has been reverted.'): + with pytest.raises(SolidityError, match='execution reverted'): txn_params = revert_contract._prepare_transaction( fn_name="revertWithMessage", transaction={ @@ -764,7 +764,7 @@ def test_eth_estimateGas_revert_with_msg( revert_contract: "Contract", unlocked_account: ChecksumAddress, ) -> None: - with pytest.raises(SolidityError, match='Function has been reverted.'): + with pytest.raises(SolidityError, match='execution reverted'): txn_params = revert_contract._prepare_transaction( fn_name="revertWithMessage", transaction={ diff --git a/web3/providers/eth_tester/main.py b/web3/providers/eth_tester/main.py index b6710e5237..707bdd9d6e 100644 --- a/web3/providers/eth_tester/main.py +++ b/web3/providers/eth_tester/main.py @@ -106,7 +106,8 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: }) except TransactionFailed as e: revert_msg = decode_single('(string)', e.args[0].args[0][4:]) - raise SolidityError(revert_msg) + # Mirroring Geth: 'execution reverted: ' + raise SolidityError(f'execution reverted: {revert_msg[0]}') else: return { 'result': response, From e3a70e9f7ca5d7f805fda506ecb3963a1f91afa2 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Mon, 28 Sep 2020 10:37:53 -0600 Subject: [PATCH 19/23] lints --- web3/_utils/method_formatters.py | 7 ++++--- web3/manager.py | 3 --- web3/providers/eth_tester/main.py | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py index 68bfb3d55c..be260c5463 100644 --- a/web3/_utils/method_formatters.py +++ b/web3/_utils/method_formatters.py @@ -410,6 +410,7 @@ def check_for_parity_revert(response: Any) -> Any: raise SolidityError('execution reverted') return HexBytes(response) + PYTHONIC_RESULT_FORMATTERS: Dict[RPCEndpoint, Callable[..., Any]] = { # Eth RPC.eth_accounts: apply_list_to_array_formatter(to_checksum_address), @@ -523,12 +524,12 @@ def get_revert_reason(response: RPCResponse) -> str: # data = response['error'].get('data', '') # if data == 'Reverted 0x': - # return '' + # return '' # # "Reverted", function selector and offset are always the same for revert errors - # prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' + # prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' # noqa: 501 # if not data.startswith(prefix): - # return None + # return None # reason_length = int(data[len(prefix):len(prefix) + 64], 16) # reason = data[len(prefix) + 64:len(prefix) + 64 + reason_length * 2] diff --git a/web3/manager.py b/web3/manager.py index 0a494bf0b1..9402096397 100644 --- a/web3/manager.py +++ b/web3/manager.py @@ -28,9 +28,6 @@ from web3.datastructures import ( NamedElementOnion, ) -from web3.exceptions import ( - SolidityError, -) from web3.middleware import ( abi_middleware, attrdict_middleware, diff --git a/web3/providers/eth_tester/main.py b/web3/providers/eth_tester/main.py index 707bdd9d6e..0a14701294 100644 --- a/web3/providers/eth_tester/main.py +++ b/web3/providers/eth_tester/main.py @@ -5,6 +5,7 @@ Dict, Optional, ) + from eth_abi import ( decode_single, ) From 12aae2e6c1bee7da18153caf3119b437a9527c77 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Wed, 21 Oct 2020 15:32:07 -0600 Subject: [PATCH 20/23] upgrade parity fixture + handle parity revert --- .../core/utilities/test_method_formatters.py | 2 +- tests/integration/generate_fixtures/common.py | 26 ++-- .../generate_fixtures/go_ethereum.py | 121 ++++-------------- tests/integration/generate_fixtures/parity.py | 82 +++++++++--- tests/integration/parity-2.5.13-fixture.zip | Bin 16820280 -> 16825959 bytes tests/integration/parity/conftest.py | 18 +-- tests/integration/test_ethereum_tester.py | 4 +- web3/_utils/method_formatters.py | 40 +++--- web3/providers/eth_tester/main.py | 7 +- 9 files changed, 130 insertions(+), 170 deletions(-) diff --git a/tests/core/utilities/test_method_formatters.py b/tests/core/utilities/test_method_formatters.py index 2bd50cb279..f83611bc9a 100644 --- a/tests/core/utilities/test_method_formatters.py +++ b/tests/core/utilities/test_method_formatters.py @@ -51,7 +51,7 @@ def test_get_revert_reason() -> None: - assert get_revert_reason(REVERT_WITH_MSG) == 'not allowed to monitor' + assert get_revert_reason(REVERT_WITH_MSG) == 'execution reverted: not allowed to monitor' assert get_revert_reason(REVERT_WITHOUT_MSG) == '' assert get_revert_reason(OTHER_ERROR) is None diff --git a/tests/integration/generate_fixtures/common.py b/tests/integration/generate_fixtures/common.py index 31b5992b88..7f3cdfa947 100644 --- a/tests/integration/generate_fixtures/common.py +++ b/tests/integration/generate_fixtures/common.py @@ -36,24 +36,26 @@ "homesteadBlock": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, + # "petersburgBlock": 0, + # "istanbulBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, - "eip160Block": 0, }, "nonce": "0x0000000000000042", "alloc": { - COINBASE: { - "balance": "1000000000000000000000000000" - }, - UNLOCKABLE_ACCOUNT: { - "balance": "1000000000000000000000000000" - }, - RAW_TXN_ACCOUNT: { - "balance": "1000000000000000000000000000" - } + COINBASE: {"balance": "1000000000000000000000000000"}, + UNLOCKABLE_ACCOUNT: {"balance": "1000000000000000000000000000"}, + RAW_TXN_ACCOUNT: {"balance": "1000000000000000000000000000"}, + "0000000000000000000000000000000000000001": {"balance": "1"}, + "0000000000000000000000000000000000000002": {"balance": "1"}, + "0000000000000000000000000000000000000003": {"balance": "1"}, + "0000000000000000000000000000000000000004": {"balance": "1"}, + "0000000000000000000000000000000000000005": {"balance": "1"}, + "0000000000000000000000000000000000000006": {"balance": "1"}, + # "0000000000000000000000000000000000000007": {"balance": "1"}, + # "0000000000000000000000000000000000000008": {"balance": "1"}, + # "0000000000000000000000000000000000000009": {"balance": "1"}, }, "timestamp": "0x00", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", diff --git a/tests/integration/generate_fixtures/go_ethereum.py b/tests/integration/generate_fixtures/go_ethereum.py index 43db377b4b..4242d753b0 100644 --- a/tests/integration/generate_fixtures/go_ethereum.py +++ b/tests/integration/generate_fixtures/go_ethereum.py @@ -3,17 +3,13 @@ import os import pprint import shutil -import signal -import socket import subprocess import sys -import tempfile import time from eth_utils.curried import ( apply_formatter_if, is_bytes, - is_checksum_address, is_dict, is_same_address, remove_0x_prefix, @@ -26,6 +22,7 @@ valmap, ) +import common from tests.utils import ( get_open_port, ) @@ -89,86 +86,12 @@ } -def ensure_path_exists(dir_path): - """ - Make sure that a path exists - """ - if not os.path.exists(dir_path): - os.makedirs(dir_path) - return True - return False - - -@contextlib.contextmanager -def tempdir(): - dir_path = tempfile.mkdtemp() - try: - yield dir_path - finally: - shutil.rmtree(dir_path) - - -def get_geth_binary(): - from geth.install import ( - get_executable_path, - install_geth, - ) - - if 'GETH_BINARY' in os.environ: - return os.environ['GETH_BINARY'] - elif 'GETH_VERSION' in os.environ: - geth_version = os.environ['GETH_VERSION'] - _geth_binary = get_executable_path(geth_version) - if not os.path.exists(_geth_binary): - install_geth(geth_version) - assert os.path.exists(_geth_binary) - return _geth_binary - else: - return 'geth' - - -def wait_for_popen(proc, timeout): - start = time.time() - while time.time() < start + timeout: - if proc.poll() is None: - time.sleep(0.01) - else: - break - - -def kill_proc_gracefully(proc): - if proc.poll() is None: - proc.send_signal(signal.SIGINT) - wait_for_popen(proc, 13) - - if proc.poll() is None: - proc.terminate() - wait_for_popen(proc, 5) - - if proc.poll() is None: - proc.kill() - wait_for_popen(proc, 2) - - -def wait_for_socket(ipc_path, timeout=30): - start = time.time() - while time.time() < start + timeout: - try: - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(ipc_path) - sock.settimeout(timeout) - except (FileNotFoundError, socket.error): - time.sleep(0.01) - else: - break - - @contextlib.contextmanager def graceful_kill_on_exit(proc): try: yield proc finally: - kill_proc_gracefully(proc) + common.kill_proc_gracefully(proc) @contextlib.contextmanager @@ -235,10 +158,10 @@ def write_config_json(config, datadir): def generate_go_ethereum_fixture(destination_dir): with contextlib.ExitStack() as stack: - datadir = stack.enter_context(tempdir()) + datadir = stack.enter_context(common.tempdir()) keystore_dir = os.path.join(datadir, 'keystore') - ensure_path_exists(keystore_dir) + common.ensure_path_exists(keystore_dir) keyfile_path = os.path.join(keystore_dir, KEYFILE_FILENAME) with open(keyfile_path, 'w') as keyfile: keyfile.write(KEYFILE_DATA) @@ -246,11 +169,11 @@ def generate_go_ethereum_fixture(destination_dir): with open(genesis_file_path, 'w') as genesis_file: genesis_file.write(json.dumps(GENESIS_DATA)) - geth_ipc_path_dir = stack.enter_context(tempdir()) + geth_ipc_path_dir = stack.enter_context(common.tempdir()) geth_ipc_path = os.path.join(geth_ipc_path_dir, 'geth.ipc') geth_port = get_open_port() - geth_binary = get_geth_binary() + geth_binary = common.get_geth_binary() with get_geth_process( geth_binary=geth_binary, @@ -259,7 +182,7 @@ def generate_go_ethereum_fixture(destination_dir): geth_ipc_path=geth_ipc_path, geth_port=geth_port): - wait_for_socket(geth_ipc_path) + common.wait_for_socket(geth_ipc_path) web3 = Web3(Web3.IPCProvider(geth_ipc_path)) chain_data = setup_chain_state(web3) # close geth by exiting context @@ -275,7 +198,7 @@ def generate_go_ethereum_fixture(destination_dir): geth_ipc_path=geth_ipc_path, geth_port=geth_port): - wait_for_socket(geth_ipc_path) + common.wait_for_socket(geth_ipc_path) web3 = Web3(Web3.IPCProvider(geth_ipc_path)) verify_chain_state(web3, chain_data) @@ -299,7 +222,7 @@ def verify_chain_state(web3, chain_data): def mine_transaction_hash(web3, txn_hash): web3.geth.miner.start(1) try: - return web3.eth.waitForTransactionReceipt(txn_hash, timeout=60) + return web3.eth.waitForTransactionReceipt(txn_hash, timeout=180) finally: web3.geth.miner.stop() @@ -309,7 +232,7 @@ def mine_block(web3): start_time = time.time() web3.geth.miner.start(1) - while time.time() < start_time + 60: + while time.time() < start_time + 120: block_number = web3.eth.blockNumber if block_number > origin_block_number: web3.geth.miner.stop() @@ -320,16 +243,16 @@ def mine_block(web3): raise ValueError("No block mined during wait period") -def deploy_contract(web3, name, factory): - web3.geth.personal.unlock_account(web3.eth.coinbase, KEYFILE_PW) - deploy_txn_hash = factory.constructor().transact({'from': web3.eth.coinbase}) - print('{0}_CONTRACT_DEPLOY_HASH: '.format(name.upper()), deploy_txn_hash) - deploy_receipt = mine_transaction_hash(web3, deploy_txn_hash) - print('{0}_CONTRACT_DEPLOY_TRANSACTION_MINED'.format(name.upper())) - contract_address = deploy_receipt['contractAddress'] - assert is_checksum_address(contract_address) - print('{0}_CONTRACT_ADDRESS:'.format(name.upper()), contract_address) - return deploy_receipt +# def deploy_contract(web3, name, factory): + # web3.geth.personal.unlock_account(web3.eth.coinbase, KEYFILE_PW) + # deploy_txn_hash = factory.constructor().transact({'from': web3.eth.coinbase}) + # print('{0}_CONTRACT_DEPLOY_HASH: '.format(name.upper()), deploy_txn_hash) + # deploy_receipt = mine_transaction_hash(web3, deploy_txn_hash) + # print('{0}_CONTRACT_DEPLOY_TRANSACTION_MINED'.format(name.upper())) + # contract_address = deploy_receipt['contractAddress'] + # assert is_checksum_address(contract_address) + # print('{0}_CONTRACT_ADDRESS:'.format(name.upper()), contract_address) + # return deploy_receipt def setup_chain_state(web3): @@ -344,7 +267,7 @@ def setup_chain_state(web3): abi=MATH_ABI, bytecode=MATH_BYTECODE, ) - math_deploy_receipt = deploy_contract(web3, 'math', math_contract_factory) + math_deploy_receipt = common.deploy_contract(web3, 'math', math_contract_factory) assert is_dict(math_deploy_receipt) # @@ -354,7 +277,7 @@ def setup_chain_state(web3): abi=CONTRACT_EMITTER_ABI, bytecode=CONTRACT_EMITTER_CODE, ) - emitter_deploy_receipt = deploy_contract(web3, 'emitter', emitter_contract_factory) + emitter_deploy_receipt = common.deploy_contract(web3, 'emitter', emitter_contract_factory) emitter_contract = emitter_contract_factory(emitter_deploy_receipt['contractAddress']) txn_hash_with_log = emitter_contract.functions.logDouble( diff --git a/tests/integration/generate_fixtures/parity.py b/tests/integration/generate_fixtures/parity.py index 6e2ac4c7e5..927f98d413 100644 --- a/tests/integration/generate_fixtures/parity.py +++ b/tests/integration/generate_fixtures/parity.py @@ -29,23 +29,45 @@ "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", + # "blockReward": "0x4563918244F40000", # homestead + # "blockReward": "0x29a2241af62c0000", # byzantium + "blockReward": "0x1bc16d674ec80000", # constantinople + "difficultyBombDelays": { + # "0x0": "0x2dc6c0", # byzantium + "0x0": "0x1e8480", + }, "homesteadTransition": 0, + "eip100bTransition": 0, } } }, "params": { "gasLimitBoundDivisor": "0x0400", "registrar": "0x81a4b044831c4f12ba601adb9274516939e9b8a2", - "eip140Transition": 0, + # Tangerine Whistle "eip150Transition": 0, - "eip155Transition": 0, + # Spurious Dragon "eip160Transition": 0, "eip161abcTransition": 0, "eip161dTransition": 0, + "eip155Transition": 0, + # Byzantium + "eip140Transition": 0, + "eip211Transition": 0, "eip214Transition": 0, + "eip658Transition": 0, + # Constantinople + "eip145Transition": 0, "eip1014Transition": 0, "eip1052Transition": 0, + "eip1283Transition": 0, + # Petersburg + # "eip1283DisableTransition": 0, + # Istanbul + # "eip1283ReenableTransition": 0, + # "eip1344Transition": 0, + # "eip1884Transition": 0, + # "eip2028Transition": 0, "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", @@ -67,28 +89,55 @@ "gasLimit": "0x1000000" }, "accounts": { - common.COINBASE: { - "balance": "1000000000000000000000000000", - "nonce": "0", + common.COINBASE: {"balance": "1000000000000000000000000000", "nonce": "0"}, + common.UNLOCKABLE_ACCOUNT: {"balance": "1000000000000000000000000000", "nonce": "0"}, + common.RAW_TXN_ACCOUNT: {"balance": "1000000000000000000000000000", "nonce": "0"}, + "0000000000000000000000000000000000000001": { + "balance": "0x1", "builtin": { - "name": "ecrecover", "pricing": {"linear": {"base": 3000, "word": 0}} + "name": "ecrecover", + "pricing": {"linear": {"base": 3000, "word": 0}} } }, - common.UNLOCKABLE_ACCOUNT: { - "balance": "1000000000000000000000000000", - "nonce": "0", + "0000000000000000000000000000000000000002": { + "balance": "0x1", "builtin": { - "name": "sha256", "pricing": {"linear": {"base": 60, "word": 12}} + "name": "sha256", + "pricing": {"linear": {"base": 60, "word": 12}} } }, - common.RAW_TXN_ACCOUNT: { - "balance": "1000000000000000000000000000", - "nonce": "0", + "0000000000000000000000000000000000000003": { + "balance": "0x1", "builtin": { "name": "ripemd160", "pricing": {"linear": {"base": 600, "word": 120}} } - } + }, + "0000000000000000000000000000000000000004": { + "balance": "0x1", + "builtin": { + "name": "identity", + "pricing": {"linear": {"base": 15, "word": 3}} + } + }, + "0000000000000000000000000000000000000005": { + "balance": "0x1", + "builtin": { + "name": "modexp", + "pricing": {"modexp": {"divisor": 20}} + } + }, + "0000000000000000000000000000000000000006": { + "balance": "0x1", + "builtin": { + "name": "alt_bn128_add", + "activate_at": "0x7530", + "pricing": {"linear": {"base": 500, "word": 0}} + } + }, + # "0000000000000000000000000000000000000007": {}, + # "0000000000000000000000000000000000000008": {}, + # "0000000000000000000000000000000000000009": {}, } } @@ -98,7 +147,8 @@ def get_parity_binary(): If generating a fixture from a local binary, update this value to that bin, e.g., return '/Users/xzy/Downloads/openethereum-2.5.13/target/release/parity' """ - return 'parity' + return '/Users/mg/Downloads/openethereum-2.5.13/target/release/parity' + # return 'parity' @contextlib.contextmanager diff --git a/tests/integration/parity-2.5.13-fixture.zip b/tests/integration/parity-2.5.13-fixture.zip index 36da22192be13a4c724373531992502874f44053..e4e01defa0d2ea78bd67b9b885bbf2b81ed4d4e9 100644 GIT binary patch delta 40438 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 aEElbw=21dy+w(&|BqyQ4SOk6X!22Hy;h@m~ delta 34880 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 Qh5cc|Vm(R9V+QsA0F2g7@c;k- diff --git a/tests/integration/parity/conftest.py b/tests/integration/parity/conftest.py index 0477d28ff5..18b03c77e2 100644 --- a/tests/integration/parity/conftest.py +++ b/tests/integration/parity/conftest.py @@ -22,20 +22,20 @@ PARITY_2_5_13_FIXTURE = { 'zip': 'parity-2.5.13-fixture.zip', 'coinbase': 'dc544d1aa88ff8bbd2f2aec754b1f1e99e1812fd', - 'block_hash_revert_no_msg': '0x3244617196b9467687cbab23798c00077954452771d38d05d3b8d484b83c5de5', # noqa: E501 - 'block_hash_revert_with_msg': '0x7d7917231f1a9e816f11ff93842d543c35075a7cd5d75854f28324409910836c', # noqa: E501 - 'block_hash_with_log': '0x19947203802e02d4659698c5684322ef67c4146fb1f420a6da371116be78047c', - 'block_with_txn_hash': '0xc26f5610ddbfd6fbe179110e09af6df06c2998ed0c9c623417480b2c795a6f01', + 'block_hash_revert_no_msg': '0x0496eca70b312db0d7b14753f5545e48f43ad70e8a2dd4fa5dc6c6409448c394', # noqa: E501 + 'block_hash_revert_with_msg': '0xf117005506c338177df21519008e3805cb718c2cad5f4a4c07754bf59bfd996c', # noqa: E501 + 'block_hash_with_log': '0xeb1cd5061f8e8c0a1a3b75dd48600fa126b6c0e753406276f2a6a544f1e41ec1', + 'block_with_txn_hash': '0xabf9142af100741620657e5a9a46e788c776303ca4986478f892384b83d8761c', 'emitter_address': '0x4aA591a07989b4F810E2F5cE97e769D60710f168', - 'emitter_deploy_txn_hash': '0xbd4ca1b3cdb6bd711aec67dbb5a90c4d8f7910dab5bde70e5b8a9f8ad689b373', - 'empty_block_hash': '0x7a877c858e2d5447305e0901580022553cab34fdbc78c22c33b627e2a6a9ba5a', + 'emitter_deploy_txn_hash': '0xef44cd36d86c41640c710026acf45f3b63731f72ac2a1744a005f6690bfa7613', + 'empty_block_hash': '0x63b0e0f16340e65662948cde20ba93c96ae311997db672b0101357f15b071fe5', 'keyfile_pw': 'web3py-test', 'math_address': '0xd794C821fCCFF5D96F5Db44af7e29977630A9dc2', - 'math_deploy_txn_hash': '0xa266faa2c729660d88e0c72994b5cd0e85ff9fe05846a6575b9095d433f51957', - 'mined_txn_hash': '0xd9f2298f6bc02f5ede8db75eac721f2365b6d9a96e1ca1bb0724d316de8f626c', + 'math_deploy_txn_hash': '0x356278504f40db914545888674cedc0d8ccd4a939665eb4ab83b569db0c477cb', + 'mined_txn_hash': '0x86fbfe56cce542ff0a2a2716c31675a0c9c43701725c4a751d20ee2ddf8a733d', 'raw_txn_account': '0x39EEed73fb1D3855E90Cbd42f348b3D7b340aAA6', 'revert_address': '0x14F3674571D76Bf66cA8EBD84dC02060933400b4', - 'txn_hash_with_log': '0x51c7e37746062cb7ff1f337d3ab725fa540c6d20fc9304b08dad5e80b3601511'} + 'txn_hash_with_log': '0x1407ae0fbc79622e60c21b59b0cb047a5f8d0219ad95969096c8c0e23f342f5c'} @pytest.fixture(scope='module') diff --git a/tests/integration/test_ethereum_tester.py b/tests/integration/test_ethereum_tester.py index 503ab3ece5..07a6e3d78b 100644 --- a/tests/integration/test_ethereum_tester.py +++ b/tests/integration/test_ethereum_tester.py @@ -333,10 +333,10 @@ def test_eth_getTransactionReceipt_mined(self, web3, block_with_txn, mined_txn_h super().test_eth_getTransactionReceipt_mined(web3, block_with_txn, mined_txn_hash) def test_eth_call_revert_with_msg(self, web3, revert_contract, unlocked_account) -> None: - super().test_eth_call_revert_with_msg(web3, revert_contract, unlocked_account) + super().test_eth_call_revert_with_msg(web3, revert_contract, unlocked_account) def test_eth_estimateGas_revert_with_msg(self, web3, revert_contract, unlocked_account) -> None: - super().test_eth_estimateGas_revert_with_msg(web3, revert_contract, unlocked_account) + super().test_eth_estimateGas_revert_with_msg(web3, revert_contract, unlocked_account) class TestEthereumTesterVersionModule(VersionModuleTest): diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py index be260c5463..b195f5ea7f 100644 --- a/web3/_utils/method_formatters.py +++ b/web3/_utils/method_formatters.py @@ -402,22 +402,13 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]: } -def check_for_parity_revert(response: Any) -> Any: - # Parity returns '0x' if reverted, without an exception - # TODO: false positives? - if response == '0x': - # Mirroring Geth: 'execution reverted: ' - raise SolidityError('execution reverted') - return HexBytes(response) - - PYTHONIC_RESULT_FORMATTERS: Dict[RPCEndpoint, Callable[..., Any]] = { # Eth RPC.eth_accounts: apply_list_to_array_formatter(to_checksum_address), RPC.eth_blockNumber: to_integer_if_hex, RPC.eth_chainId: to_integer_if_hex, RPC.eth_coinbase: to_checksum_address, - RPC.eth_call: check_for_parity_revert, + RPC.eth_call: HexBytes, RPC.eth_estimateGas: to_integer_if_hex, RPC.eth_gasPrice: to_integer_if_hex, RPC.eth_getBalance: to_integer_if_hex, @@ -515,25 +506,24 @@ def get_revert_reason(response: RPCResponse) -> str: if not isinstance(response['error'], dict): return None - if 'message' in response['error']: - return response['error']['message'] + data = response['error'].get('data', '') - # TODO: by this point, all tested client's reverts have been accounted for - return '' + # Parity/OpenEthereum case: + if data.startswith('Reverted '): + # "Reverted", function selector and offset are always the same for revert errors + prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' # noqa: 501 + if not data.startswith(prefix): + return '' - # data = response['error'].get('data', '') + reason_length = int(data[len(prefix):len(prefix) + 64], 16) + reason = data[len(prefix) + 64:len(prefix) + 64 + reason_length * 2] + return f'execution reverted: {bytes.fromhex(reason).decode("utf8")}' - # if data == 'Reverted 0x': - # return '' - - # # "Reverted", function selector and offset are always the same for revert errors - # prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' # noqa: 501 - # if not data.startswith(prefix): - # return None + # Geth case: + if 'message' in response['error'] and response['error'].get('code', '') == 3: + return response['error']['message'] - # reason_length = int(data[len(prefix):len(prefix) + 64], 16) - # reason = data[len(prefix) + 64:len(prefix) + 64 + reason_length * 2] - # return bytes.fromhex(reason).decode('utf8') + return None def raise_solidity_error_on_revert(response: RPCResponse) -> RPCResponse: diff --git a/web3/providers/eth_tester/main.py b/web3/providers/eth_tester/main.py index 0a14701294..bbcb61de3b 100644 --- a/web3/providers/eth_tester/main.py +++ b/web3/providers/eth_tester/main.py @@ -6,10 +6,6 @@ Optional, ) -from eth_abi import ( - decode_single, -) - from web3._utils.compat import ( Literal, ) @@ -106,9 +102,8 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: "error": "RPC Endpoint has not been implemented: {0}".format(method), }) except TransactionFailed as e: - revert_msg = decode_single('(string)', e.args[0].args[0][4:]) # Mirroring Geth: 'execution reverted: ' - raise SolidityError(f'execution reverted: {revert_msg[0]}') + raise SolidityError(f'execution reverted: {e.args[0]}') else: return { 'result': response, From 3071442fcac8128b6860536a05c16b75445d195f Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Fri, 23 Oct 2020 09:53:36 -0600 Subject: [PATCH 21/23] dedupe constants, more cleanup --- .../generate_fixtures/go_ethereum.py | 76 +++--------------- tests/integration/generate_fixtures/parity.py | 3 +- tests/integration/geth-1.9.19-fixture.zip | Bin 27337 -> 33727 bytes tests/integration/go_ethereum/conftest.py | 3 +- tests/integration/test.zip | Bin 21551 -> 0 bytes 5 files changed, 11 insertions(+), 71 deletions(-) delete mode 100644 tests/integration/test.zip diff --git a/tests/integration/generate_fixtures/go_ethereum.py b/tests/integration/generate_fixtures/go_ethereum.py index 4242d753b0..6e1ddbddbf 100644 --- a/tests/integration/generate_fixtures/go_ethereum.py +++ b/tests/integration/generate_fixtures/go_ethereum.py @@ -12,10 +12,8 @@ is_bytes, is_dict, is_same_address, - remove_0x_prefix, to_hex, to_text, - to_wei, ) from eth_utils.toolz import ( merge, @@ -41,50 +39,6 @@ REVERT_CONTRACT_BYTECODE, ) -COINBASE = '0xdc544d1aa88ff8bbd2f2aec754b1f1e99e1812fd' -COINBASE_PK = '0x58d23b55bc9cdce1f18c2500f40ff4ab7245df9a89505e9b1fa4851f623d241d' - -KEYFILE_DATA = '{"address":"dc544d1aa88ff8bbd2f2aec754b1f1e99e1812fd","crypto":{"cipher":"aes-128-ctr","ciphertext":"52e06bc9397ea9fa2f0dae8de2b3e8116e92a2ecca9ad5ff0061d1c449704e98","cipherparams":{"iv":"aa5d0a5370ef65395c1a6607af857124"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"9fdf0764eb3645ffc184e166537f6fe70516bf0e34dc7311dea21f100f0c9263"},"mac":"4e0b51f42b865c15c485f4faefdd1f01a38637e5247f8c75ffe6a8c0eba856f6"},"id":"5a6124e0-10f1-4c1c-ae3e-d903eacb740a","version":3}' # noqa: E501 - -KEYFILE_PW = 'web3py-test' -KEYFILE_FILENAME = 'UTC--2017-08-24T19-42-47.517572178Z--dc544d1aa88ff8bbd2f2aec754b1f1e99e1812fd' # noqa: E501 - -RAW_TXN_ACCOUNT = '0x39EEed73fb1D3855E90Cbd42f348b3D7b340aAA6' - -UNLOCKABLE_PRIVATE_KEY = '0x392f63a79b1ff8774845f3fa69de4a13800a59e7083f5187f1558f0797ad0f01' -UNLOCKABLE_ACCOUNT = '0x12efdc31b1a8fa1a1e756dfd8a1601055c971e13' -UNLOCKABLE_ACCOUNT_PW = KEYFILE_PW - - -GENESIS_DATA = { - "nonce": "0xdeadbeefdeadbeef", - "timestamp": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", # noqa: E501 - "extraData": "0x7765623370792d746573742d636861696e", - "gasLimit": "0x47d5cc", - "difficulty": "0x01", - "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", # noqa: E501 - "coinbase": "0x3333333333333333333333333333333333333333", - "alloc": { - remove_0x_prefix(COINBASE): { - 'balance': str(to_wei(1000000000, 'ether')), - }, - remove_0x_prefix(RAW_TXN_ACCOUNT): { - 'balance': str(to_wei(10, 'ether')), - }, - remove_0x_prefix(UNLOCKABLE_ACCOUNT): { - 'balance': str(to_wei(10, 'ether')), - }, - }, - "config": { - "chainId": 131277322940537, # the string 'web3py' as an integer - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0 - }, -} - @contextlib.contextmanager def graceful_kill_on_exit(proc): @@ -120,7 +74,7 @@ def get_geth_process(geth_binary, '--gcmode', 'archive', '--nodiscover', '--port', geth_port, - '--etherbase', COINBASE[2:], + '--etherbase', common.COINBASE[2:], ) popen_proc = subprocess.Popen( @@ -162,12 +116,12 @@ def generate_go_ethereum_fixture(destination_dir): keystore_dir = os.path.join(datadir, 'keystore') common.ensure_path_exists(keystore_dir) - keyfile_path = os.path.join(keystore_dir, KEYFILE_FILENAME) + keyfile_path = os.path.join(keystore_dir, common.KEYFILE_FILENAME) with open(keyfile_path, 'w') as keyfile: - keyfile.write(KEYFILE_DATA) + keyfile.write(common.KEYFILE_DATA) genesis_file_path = os.path.join(datadir, 'genesis.json') with open(genesis_file_path, 'w') as genesis_file: - genesis_file.write(json.dumps(GENESIS_DATA)) + genesis_file.write(json.dumps(common.GENESIS_DATA)) geth_ipc_path_dir = stack.enter_context(common.tempdir()) geth_ipc_path = os.path.join(geth_ipc_path_dir, 'geth.ipc') @@ -203,8 +157,8 @@ def generate_go_ethereum_fixture(destination_dir): verify_chain_state(web3, chain_data) static_data = { - 'raw_txn_account': RAW_TXN_ACCOUNT, - 'keyfile_pw': KEYFILE_PW, + 'raw_txn_account': common.RAW_TXN_ACCOUNT, + 'keyfile_pw': common.KEYFILE_PW, } config = merge(chain_data, static_data) pprint.pprint(config) @@ -222,7 +176,7 @@ def verify_chain_state(web3, chain_data): def mine_transaction_hash(web3, txn_hash): web3.geth.miner.start(1) try: - return web3.eth.waitForTransactionReceipt(txn_hash, timeout=180) + return web3.eth.waitForTransactionReceipt(txn_hash, timeout=120) finally: web3.geth.miner.stop() @@ -243,22 +197,10 @@ def mine_block(web3): raise ValueError("No block mined during wait period") -# def deploy_contract(web3, name, factory): - # web3.geth.personal.unlock_account(web3.eth.coinbase, KEYFILE_PW) - # deploy_txn_hash = factory.constructor().transact({'from': web3.eth.coinbase}) - # print('{0}_CONTRACT_DEPLOY_HASH: '.format(name.upper()), deploy_txn_hash) - # deploy_receipt = mine_transaction_hash(web3, deploy_txn_hash) - # print('{0}_CONTRACT_DEPLOY_TRANSACTION_MINED'.format(name.upper())) - # contract_address = deploy_receipt['contractAddress'] - # assert is_checksum_address(contract_address) - # print('{0}_CONTRACT_ADDRESS:'.format(name.upper()), contract_address) - # return deploy_receipt - - def setup_chain_state(web3): coinbase = web3.eth.coinbase - assert is_same_address(coinbase, COINBASE) + assert is_same_address(coinbase, common.COINBASE) # # Math Contract @@ -333,7 +275,7 @@ def setup_chain_state(web3): # # Block with Transaction # - web3.geth.personal.unlock_account(coinbase, KEYFILE_PW) + web3.geth.personal.unlock_account(coinbase, common.KEYFILE_PW) web3.geth.miner.start(1) mined_txn_hash = web3.eth.sendTransaction({ 'from': coinbase, diff --git a/tests/integration/generate_fixtures/parity.py b/tests/integration/generate_fixtures/parity.py index 927f98d413..c9d44e4758 100644 --- a/tests/integration/generate_fixtures/parity.py +++ b/tests/integration/generate_fixtures/parity.py @@ -147,8 +147,7 @@ def get_parity_binary(): If generating a fixture from a local binary, update this value to that bin, e.g., return '/Users/xzy/Downloads/openethereum-2.5.13/target/release/parity' """ - return '/Users/mg/Downloads/openethereum-2.5.13/target/release/parity' - # return 'parity' + return 'parity' @contextlib.contextmanager diff --git a/tests/integration/geth-1.9.19-fixture.zip b/tests/integration/geth-1.9.19-fixture.zip index 13acb7b02c71ba663086c4e18511f0373dded049..16a515e6a51290ee17933b8128de9059200dd4ac 100644 GIT binary patch literal 33727 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 literal 27337 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 diff --git a/tests/integration/go_ethereum/conftest.py b/tests/integration/go_ethereum/conftest.py index b5e63c19c0..8c2d963c04 100644 --- a/tests/integration/go_ethereum/conftest.py +++ b/tests/integration/go_ethereum/conftest.py @@ -19,8 +19,7 @@ KEYFILE_PW = 'web3py-test' -# GETH_1919_ZIP = 'geth-1.9.19-fixture.zip' -GETH_1919_ZIP = 'test.zip' +GETH_1919_ZIP = 'geth-1.9.19-fixture.zip' @pytest.fixture(scope='module') diff --git a/tests/integration/test.zip b/tests/integration/test.zip deleted file mode 100644 index 2b3dae1dbbd038fff5c0a1b3042d3202f632f55f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21551 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 aRr`kl-mJjp8UuqK5IzPTd1vMh;sF4R8hT*> From 9204d8452a8ac73b8834445c991b0549ff4c42f8 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Mon, 26 Oct 2020 15:59:48 -0600 Subject: [PATCH 22/23] pr review fixes --- tests/integration/generate_fixtures/common.py | 2 +- tests/integration/generate_fixtures/parity.py | 3 --- tests/integration/test_ethereum_tester.py | 11 ----------- tests/integration/tester.zip | Bin 18757 -> 0 bytes web3/_utils/method_formatters.py | 4 +--- 5 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 tests/integration/tester.zip diff --git a/tests/integration/generate_fixtures/common.py b/tests/integration/generate_fixtures/common.py index 7f3cdfa947..871cf8719b 100644 --- a/tests/integration/generate_fixtures/common.py +++ b/tests/integration/generate_fixtures/common.py @@ -219,7 +219,7 @@ def mine_block(web3): def mine_transaction_hash(web3, txn_hash): start_time = time.time() web3.geth.miner.start(1) - while time.time() < start_time + 240: + while time.time() < start_time + 120: try: receipt = web3.eth.getTransactionReceipt(txn_hash) except TransactionNotFound: diff --git a/tests/integration/generate_fixtures/parity.py b/tests/integration/generate_fixtures/parity.py index c9d44e4758..eec2cd34af 100644 --- a/tests/integration/generate_fixtures/parity.py +++ b/tests/integration/generate_fixtures/parity.py @@ -29,11 +29,8 @@ "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - # "blockReward": "0x4563918244F40000", # homestead - # "blockReward": "0x29a2241af62c0000", # byzantium "blockReward": "0x1bc16d674ec80000", # constantinople "difficultyBombDelays": { - # "0x0": "0x2dc6c0", # byzantium "0x0": "0x1e8480", }, "homesteadTransition": 0, diff --git a/tests/integration/test_ethereum_tester.py b/tests/integration/test_ethereum_tester.py index 07a6e3d78b..6497e66f51 100644 --- a/tests/integration/test_ethereum_tester.py +++ b/tests/integration/test_ethereum_tester.py @@ -153,11 +153,6 @@ def revert_contract(web3, revert_contract_factory, revert_contract_deploy_txn_ha return revert_contract_factory(contract_address) -@pytest.fixture(scope="module") -def revert_contract_address(revert_contract, address_conversion_func): - return address_conversion_func(revert_contract.address) - - UNLOCKABLE_PRIVATE_KEY = '0x392f63a79b1ff8774845f3fa69de4a13800a59e7083f5187f1558f0797ad0f01' @@ -332,12 +327,6 @@ def test_eth_chainId(self, web3): def test_eth_getTransactionReceipt_mined(self, web3, block_with_txn, mined_txn_hash): super().test_eth_getTransactionReceipt_mined(web3, block_with_txn, mined_txn_hash) - def test_eth_call_revert_with_msg(self, web3, revert_contract, unlocked_account) -> None: - super().test_eth_call_revert_with_msg(web3, revert_contract, unlocked_account) - - def test_eth_estimateGas_revert_with_msg(self, web3, revert_contract, unlocked_account) -> None: - super().test_eth_estimateGas_revert_with_msg(web3, revert_contract, unlocked_account) - class TestEthereumTesterVersionModule(VersionModuleTest): pass diff --git a/tests/integration/tester.zip b/tests/integration/tester.zip deleted file mode 100644 index e5f2b5845712509720ef4e27712a71bc9272eac0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18757 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 pM*iiCpT-!!Ktwrz+kO5&jX0#m!5>n str: See also https://solidity.readthedocs.io/en/v0.6.3/control-structures.html#revert """ - assert 'error' in response if not isinstance(response['error'], dict): return None - data = response['error'].get('data', '') - # Parity/OpenEthereum case: + data = response['error'].get('data', '') if data.startswith('Reverted '): # "Reverted", function selector and offset are always the same for revert errors prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' # noqa: 501 From 33b72d44f311dd6cb6ef34c102b981a35d813bf0 Mon Sep 17 00:00:00 2001 From: Marc Garreau Date: Wed, 28 Oct 2020 11:45:47 -0600 Subject: [PATCH 23/23] more pr review --- .../core/utilities/test_method_formatters.py | 23 ++++++++++++---- tests/integration/generate_fixtures/common.py | 5 ---- tests/integration/generate_fixtures/parity.py | 9 +++---- web3/_utils/method_formatters.py | 27 +++++-------------- web3/_utils/module_testing/eth_module.py | 4 +-- web3/providers/eth_tester/main.py | 11 ++++++-- 6 files changed, 39 insertions(+), 40 deletions(-) diff --git a/tests/core/utilities/test_method_formatters.py b/tests/core/utilities/test_method_formatters.py index f83611bc9a..1dd367f165 100644 --- a/tests/core/utilities/test_method_formatters.py +++ b/tests/core/utilities/test_method_formatters.py @@ -2,7 +2,7 @@ from web3._utils.method_formatters import ( get_error_formatters, - get_revert_reason, + raise_solidity_error_on_revert, ) from web3._utils.rpc_abi import ( RPC, @@ -50,10 +50,23 @@ }) -def test_get_revert_reason() -> None: - assert get_revert_reason(REVERT_WITH_MSG) == 'execution reverted: not allowed to monitor' - assert get_revert_reason(REVERT_WITHOUT_MSG) == '' - assert get_revert_reason(OTHER_ERROR) is None +@pytest.mark.parametrize( + "response,expected", + ( + (REVERT_WITH_MSG, 'execution reverted: not allowed to monitor'), + (REVERT_WITHOUT_MSG, 'execution reverted'), + ), + ids=[ + 'test-get-revert-reason-with-msg', + 'test-get-revert-reason-without-msg', + ]) +def test_get_revert_reason(response, expected) -> None: + with pytest.raises(SolidityError, match=expected): + raise_solidity_error_on_revert(response) + + +def test_get_revert_reason_other_error() -> None: + assert raise_solidity_error_on_revert(OTHER_ERROR) is OTHER_ERROR def test_get_error_formatters() -> None: diff --git a/tests/integration/generate_fixtures/common.py b/tests/integration/generate_fixtures/common.py index 871cf8719b..fdde519109 100644 --- a/tests/integration/generate_fixtures/common.py +++ b/tests/integration/generate_fixtures/common.py @@ -36,8 +36,6 @@ "homesteadBlock": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, - # "petersburgBlock": 0, - # "istanbulBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, @@ -53,9 +51,6 @@ "0000000000000000000000000000000000000004": {"balance": "1"}, "0000000000000000000000000000000000000005": {"balance": "1"}, "0000000000000000000000000000000000000006": {"balance": "1"}, - # "0000000000000000000000000000000000000007": {"balance": "1"}, - # "0000000000000000000000000000000000000008": {"balance": "1"}, - # "0000000000000000000000000000000000000009": {"balance": "1"}, }, "timestamp": "0x00", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", diff --git a/tests/integration/generate_fixtures/parity.py b/tests/integration/generate_fixtures/parity.py index eec2cd34af..ba972fa001 100644 --- a/tests/integration/generate_fixtures/parity.py +++ b/tests/integration/generate_fixtures/parity.py @@ -29,7 +29,7 @@ "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x1bc16d674ec80000", # constantinople + "blockReward": "0x1bc16d674ec80000", "difficultyBombDelays": { "0x0": "0x1e8480", }, @@ -58,9 +58,9 @@ "eip1014Transition": 0, "eip1052Transition": 0, "eip1283Transition": 0, - # Petersburg + # TODO: Petersburg # "eip1283DisableTransition": 0, - # Istanbul + # TODO: Istanbul # "eip1283ReenableTransition": 0, # "eip1344Transition": 0, # "eip1884Transition": 0, @@ -132,9 +132,6 @@ "pricing": {"linear": {"base": 500, "word": 0}} } }, - # "0000000000000000000000000000000000000007": {}, - # "0000000000000000000000000000000000000008": {}, - # "0000000000000000000000000000000000000009": {}, } } diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py index eb1df9eb8d..1167b4c3be 100644 --- a/web3/_utils/method_formatters.py +++ b/web3/_utils/method_formatters.py @@ -487,23 +487,19 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]: ABI_REQUEST_FORMATTERS = abi_request_formatters(STANDARD_NORMALIZERS, RPC_ABIS) -def get_revert_reason(response: RPCResponse) -> str: +def raise_solidity_error_on_revert(response: RPCResponse) -> RPCResponse: """ - Parse revert reason from response, return None if no revert happened. - - If a revert happened, but no message has been given, return an empty string. - Reverts contain a `data` attribute with the following layout: "Reverted " Function selector for Error(string): 08c379a (4 bytes) Data offset: 32 (32 bytes) String length (32 bytes) - Reason strong (padded, use string length from above to get meaningful part) + Reason string (padded, use string length from above to get meaningful part) See also https://solidity.readthedocs.io/en/v0.6.3/control-structures.html#revert """ if not isinstance(response['error'], dict): - return None + raise ValueError('Error expected to be a dict') # Parity/OpenEthereum case: data = response['error'].get('data', '') @@ -511,26 +507,17 @@ def get_revert_reason(response: RPCResponse) -> str: # "Reverted", function selector and offset are always the same for revert errors prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020' # noqa: 501 if not data.startswith(prefix): - return '' + raise SolidityError('execution reverted') reason_length = int(data[len(prefix):len(prefix) + 64], 16) reason = data[len(prefix) + 64:len(prefix) + 64 + reason_length * 2] - return f'execution reverted: {bytes.fromhex(reason).decode("utf8")}' + raise SolidityError(f'execution reverted: {bytes.fromhex(reason).decode("utf8")}') # Geth case: if 'message' in response['error'] and response['error'].get('code', '') == 3: - return response['error']['message'] + raise SolidityError(response['error']['message']) - return None - - -def raise_solidity_error_on_revert(response: RPCResponse) -> RPCResponse: - revert_reason = get_revert_reason(response) - if revert_reason is None: - return response - if revert_reason == '': - raise SolidityError() - raise SolidityError(revert_reason) + return response ERROR_FORMATTERS: Dict[RPCEndpoint, Callable[..., Any]] = { diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 95d758b9c4..cf8948459e 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -748,7 +748,7 @@ def test_eth_call_revert_with_msg( revert_contract: "Contract", unlocked_account: ChecksumAddress, ) -> None: - with pytest.raises(SolidityError, match='execution reverted'): + with pytest.raises(SolidityError, match='execution reverted: Function has been reverted'): txn_params = revert_contract._prepare_transaction( fn_name="revertWithMessage", transaction={ @@ -764,7 +764,7 @@ def test_eth_estimateGas_revert_with_msg( revert_contract: "Contract", unlocked_account: ChecksumAddress, ) -> None: - with pytest.raises(SolidityError, match='execution reverted'): + with pytest.raises(SolidityError, match='execution reverted: Function has been reverted'): txn_params = revert_contract._prepare_transaction( fn_name="revertWithMessage", transaction={ diff --git a/web3/providers/eth_tester/main.py b/web3/providers/eth_tester/main.py index bbcb61de3b..68097096b6 100644 --- a/web3/providers/eth_tester/main.py +++ b/web3/providers/eth_tester/main.py @@ -6,6 +6,10 @@ Optional, ) +from eth_abi import ( + decode_single, +) + from web3._utils.compat import ( Literal, ) @@ -102,8 +106,11 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: "error": "RPC Endpoint has not been implemented: {0}".format(method), }) except TransactionFailed as e: - # Mirroring Geth: 'execution reverted: ' - raise SolidityError(f'execution reverted: {e.args[0]}') + if type(e.args[0]) == str: + reason = e.args[0] + else: + reason = decode_single('(string)', e.args[0].args[0][4:])[0] + raise SolidityError(f'execution reverted: {reason}') else: return { 'result': response,