Skip to content

Commit

Permalink
Add third arg state override set. Fix #1921 (#1942)
Browse files Browse the repository at this point in the history
* Add third arg state override set. Fix #1921

* add call override formatter and test

Co-authored-by: Marc Garreau <[email protected]>
  • Loading branch information
edd34 and wolovim authored Apr 23, 2021
1 parent bd6d24c commit 48b5b07
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 7 deletions.
1 change: 1 addition & 0 deletions newsfragments/1921.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Handle optional ``eth_call`` state override param.
4 changes: 4 additions & 0 deletions tests/integration/test_ethereum_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,10 @@ def test_eth_getTransactionReceipt_mined_deprecated(self, web3, block_with_txn,
block_with_txn,
mined_txn_hash)

@pytest.mark.xfail(raises=TypeError, reason="call override param not implemented on eth-tester")
def test_eth_call_with_override(self, web3, revert_contract):
super().test_eth_call_with_override(web3, revert_contract)

def test_eth_call_revert_with_msg(self, web3, revert_contract, unlocked_account):
with pytest.raises(TransactionFailed,
match='execution reverted: Function has been reverted'):
Expand Down
29 changes: 25 additions & 4 deletions web3/_utils/method_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@
)
from web3.types import (
BlockIdentifier,
CallOverrideParams,
RPCEndpoint,
RPCResponse,
TReturn,
TxParams,
_Hash32,
)

Expand Down Expand Up @@ -315,6 +317,25 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]:
)


call_without_override: Callable[
[Tuple[TxParams, BlockIdentifier]],
Tuple[Dict[str, Any], int]
]
call_without_override = apply_formatters_to_sequence([
transaction_param_formatter,
to_hex_if_integer,
])
call_with_override: Callable[
[Tuple[TxParams, BlockIdentifier, CallOverrideParams]],
Tuple[Dict[str, Any], int, Dict[str, Any]],
]
call_with_override = apply_formatters_to_sequence([
transaction_param_formatter,
to_hex_if_integer,
lambda x: x,
])


estimate_gas_without_block_id: Callable[[Dict[str, Any]], Dict[str, Any]]
estimate_gas_without_block_id = apply_formatter_at_index(transaction_param_formatter, 0)
estimate_gas_with_block_id: Callable[
Expand Down Expand Up @@ -374,10 +395,10 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]:
RPC.eth_getUncleByBlockHashAndIndex: apply_formatter_at_index(to_hex_if_integer, 1),
RPC.eth_newFilter: apply_formatter_at_index(filter_params_formatter, 0),
RPC.eth_getLogs: apply_formatter_at_index(filter_params_formatter, 0),
RPC.eth_call: apply_formatters_to_sequence([
transaction_param_formatter,
to_hex_if_integer,
]),
RPC.eth_call: apply_one_of_formatters((
(is_length(2), call_without_override),
(is_length(3), call_with_override),
)),
RPC.eth_estimateGas: apply_one_of_formatters((
(is_length(1), estimate_gas_without_block_id),
(is_length(2), estimate_gas_with_block_id),
Expand Down
22 changes: 22 additions & 0 deletions web3/_utils/module_testing/eth_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,28 @@ def test_eth_call(
result = web3.codec.decode_single('uint256', call_result)
assert result == 18

def test_eth_call_with_override(
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)
result = web3.codec.decode_single('bool', call_result)
assert result is True

# override runtime bytecode: `normalFunction` returns `false`
override_code = '0x6080604052348015600f57600080fd5b5060043610603c5760003560e01c8063185c38a4146041578063c06a97cb146049578063d67e4b84146051575b600080fd5b60476071565b005b604f60df565b005b605760e4565b604051808215151515815260200191505060405180910390f35b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f46756e6374696f6e20686173206265656e2072657665727465642e000000000081525060200191505060405180910390fd5b600080fd5b60008090509056fea2646970667358221220bb71e9e9a2e271cd0fbe833524a3ea67df95f25ea13aef5b0a761fa52b538f1064736f6c63430006010033' # noqa: E501
call_result = web3.eth.call(
txn_params,
'latest',
{revert_contract.address: {'code': override_code}}
)
result = web3.codec.decode_single('bool', call_result)
assert result is False

def test_eth_call_with_0_result(
self, web3: "Web3", math_contract: "Contract"
) -> None:
Expand Down
11 changes: 8 additions & 3 deletions web3/eth.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
ENS,
BlockData,
BlockIdentifier,
CallOverrideParams,
FilterParams,
GasPriceStrategy,
LogReceipt,
Expand Down Expand Up @@ -527,8 +528,9 @@ def sign_munger(
def call_munger(
self,
transaction: TxParams,
block_identifier: Optional[BlockIdentifier] = None
) -> Tuple[TxParams, BlockIdentifier]:
block_identifier: Optional[BlockIdentifier] = None,
state_override: Optional[CallOverrideParams] = None,
) -> Union[Tuple[TxParams, BlockIdentifier], Tuple[TxParams, BlockIdentifier, CallOverrideParams]]: # noqa-E501
# TODO: move to middleware
if 'from' not in transaction and is_checksum_address(self.default_account):
transaction = assoc(transaction, 'from', self.default_account)
Expand All @@ -537,7 +539,10 @@ def call_munger(
if block_identifier is None:
block_identifier = self.default_block

return (transaction, block_identifier)
if state_override is None:
return (transaction, block_identifier)
else:
return (transaction, block_identifier, state_override)

call: Method[Callable[..., Union[bytes, bytearray]]] = Method(
RPC.eth_call,
Expand Down
9 changes: 9 additions & 0 deletions web3/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ class LogReceipt(TypedDict):
"value": Wei,
}, total=False)


class CallOverrideParams(TypedDict):
balance: Optional[Wei]
nonce: Optional[int]
code: Optional[Union[bytes, HexStr]]
state: Optional[Dict[str, Any]]
stateDiff: Optional[Dict[Address, Dict[str, Any]]]


GasPriceStrategy = Callable[["Web3", TxParams], Wei]


Expand Down

0 comments on commit 48b5b07

Please sign in to comment.