Skip to content

Commit 1f2d11b

Browse files
committed
state_override docs and test improvements
Update test to pass None for block identifier so geth ignores it, per note in web3.contract.rst Update description for `state_override`` param in docs Add async test for `state_override` in estimate gas Combine logic for eth_call and eth_estimateGas mungers Mark not implemented in eth tester
1 parent f017e3b commit 1f2d11b

File tree

5 files changed

+86
-30
lines changed

5 files changed

+86
-30
lines changed

docs/web3.eth.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,9 +1064,9 @@ The following methods are available on the ``web3.eth`` namespace.
10641064
The ``transaction`` and ``block_identifier`` parameters are handled in the
10651065
same manner as the :meth:`~web3.eth.Eth.send_transaction()` method.
10661066

1067-
The ``state_override`` parameter allows gas estimation for cases when there
1068-
are multiple calls that require a specific state as a side effect of the
1069-
earlier transaction, such as an `approve` followed by a `transfer` call.
1067+
The ``state_override`` is useful when there is a chain of transaction calls.
1068+
It overrides state so that the gas estimate of a transaction is accurate in
1069+
cases where prior calls produce side effects.
10701070

10711071
.. code-block:: python
10721072

tests/integration/test_ethereum_tester.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ class TestEthereumTesterEthModule(EthModuleTest):
304304
EthModuleTest.test_eth_call_with_override_param_type_check,
305305
TypeError,
306306
)
307+
test_eth_estimate_gas_with_override_param_type_check = not_implemented(
308+
EthModuleTest.test_eth_estimate_gas_with_override_param_type_check,
309+
TypeError,
310+
)
307311
test_eth_create_access_list = not_implemented(
308312
EthModuleTest.test_eth_create_access_list,
309313
MethodUnavailable,

web3/_utils/method_formatters.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,14 +455,33 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]:
455455
estimate_gas_without_block_id: Callable[[Dict[str, Any]], Dict[str, Any]]
456456
estimate_gas_without_block_id = apply_formatter_at_index(transaction_param_formatter, 0)
457457
estimate_gas_with_block_id: Callable[
458-
[Tuple[Dict[str, Any], Union[str, int]]], Tuple[Dict[str, Any], int]
458+
[Tuple[Dict[str, Any], BlockIdentifier]], Tuple[Dict[str, Any], int]
459459
]
460460
estimate_gas_with_block_id = apply_formatters_to_sequence(
461461
[
462462
transaction_param_formatter,
463463
to_hex_if_integer,
464464
]
465465
)
466+
ESTIMATE_GAS_OVERRIDE_FORMATTERS = {
467+
"balance": to_hex_if_integer,
468+
"nonce": to_hex_if_integer,
469+
"code": to_hex_if_bytes,
470+
}
471+
estimate_gas_with_override: Callable[
472+
[Tuple[Dict[str, Any], BlockIdentifier, CallOverrideParams]],
473+
Tuple[Dict[str, Any], int, Dict[str, Any]],
474+
] = apply_formatters_to_sequence(
475+
[
476+
transaction_param_formatter,
477+
to_hex_if_integer,
478+
lambda val: type_aware_apply_formatters_to_dict_keys_and_values(
479+
to_checksum_address,
480+
type_aware_apply_formatters_to_dict(ESTIMATE_GAS_OVERRIDE_FORMATTERS),
481+
val,
482+
),
483+
]
484+
)
466485

467486
SIGNED_TX_FORMATTER = {
468487
"raw": HexBytes,
@@ -531,6 +550,7 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]:
531550
(
532551
(is_length(1), estimate_gas_without_block_id),
533552
(is_length(2), estimate_gas_with_block_id),
553+
(is_length(3), estimate_gas_with_override),
534554
)
535555
),
536556
RPC.eth_sendTransaction: apply_formatter_at_index(transaction_param_formatter, 0),

web3/_utils/module_testing/eth_module.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,39 @@ async def test_eth_estimate_gas(
813813
assert is_integer(gas_estimate)
814814
assert gas_estimate > 0
815815

816+
@pytest.mark.asyncio
817+
@pytest.mark.parametrize(
818+
"params",
819+
(
820+
{
821+
"nonce": 1, # int
822+
"balance": 1, # int
823+
"code": HexStr("0x"), # HexStr
824+
# with state
825+
"state": {HexStr(f"0x{'00' * 32}"): HexStr(f"0x{'00' * 32}")},
826+
},
827+
{
828+
"nonce": HexStr("0x1"), # HexStr
829+
"balance": HexStr("0x1"), # HexStr
830+
"code": b"\x00", # bytes
831+
# with stateDiff
832+
"stateDiff": {HexStr(f"0x{'00' * 32}"): HexStr(f"0x{'00' * 32}")},
833+
},
834+
),
835+
)
836+
async def test_eth_estimate_gas_with_override_param_type_check(
837+
self,
838+
async_w3: "AsyncWeb3",
839+
async_math_contract: "Contract",
840+
params: CallOverrideParams,
841+
) -> None:
842+
txn_params: TxParams = {"from": await async_w3.eth.coinbase}
843+
844+
# assert does not raise
845+
await async_w3.eth.estimate_gas(
846+
txn_params, None, {async_math_contract.address: params}
847+
)
848+
816849
@pytest.mark.asyncio
817850
async def test_eth_fee_history(self, async_w3: "AsyncWeb3") -> None:
818851
fee_history = await async_w3.eth.fee_history(1, "latest", [50])
@@ -4189,7 +4222,7 @@ def test_eth_estimate_gas_with_override_param_type_check(
41894222
txn_params: TxParams = {"from": w3.eth.coinbase}
41904223

41914224
# assert does not raise
4192-
w3.eth.estimate_gas(txn_params, "latest", {math_contract.address: params})
4225+
w3.eth.estimate_gas(txn_params, None, {math_contract.address: params})
41934226

41944227
def test_eth_getBlockByHash(self, w3: "Web3", empty_block: BlockData) -> None:
41954228
block = w3.eth.get_block(empty_block["hash"])

web3/eth/base_eth.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
List,
44
NoReturn,
55
Optional,
6-
Sequence,
76
Tuple,
87
Union,
98
)
@@ -94,29 +93,38 @@ def set_gas_price_strategy(
9493
) -> None:
9594
self._gas_price_strategy = gas_price_strategy
9695

97-
def estimate_gas_munger(
96+
def _eth_call_and_estimate_gas_munger(
9897
self,
9998
transaction: TxParams,
10099
block_identifier: Optional[BlockIdentifier] = None,
101100
state_override: Optional[CallOverride] = None,
102-
) -> Sequence[Union[TxParams, BlockIdentifier, CallOverride]]:
101+
) -> Union[
102+
Tuple[TxParams, BlockIdentifier], Tuple[TxParams, BlockIdentifier, CallOverride]
103+
]:
104+
# TODO: move to middleware
103105
if "from" not in transaction and is_checksum_address(self.default_account):
104106
transaction = assoc(transaction, "from", self.default_account)
105107

108+
# TODO: move to middleware
106109
if block_identifier is None:
107-
return [transaction]
110+
block_identifier = self.default_block
108111

109112
if state_override is None:
110-
return [
111-
transaction,
112-
block_identifier,
113-
]
113+
return (transaction, block_identifier)
114114
else:
115-
return [
116-
transaction,
117-
block_identifier,
118-
state_override,
119-
]
115+
return (transaction, block_identifier, state_override)
116+
117+
def estimate_gas_munger(
118+
self,
119+
transaction: TxParams,
120+
block_identifier: Optional[BlockIdentifier] = None,
121+
state_override: Optional[CallOverride] = None,
122+
) -> Union[
123+
Tuple[TxParams, BlockIdentifier], Tuple[TxParams, BlockIdentifier, CallOverride]
124+
]:
125+
return self._eth_call_and_estimate_gas_munger(
126+
transaction, block_identifier, state_override
127+
)
120128

121129
def get_block_munger(
122130
self, block_identifier: BlockIdentifier, full_transactions: bool = False
@@ -150,18 +158,9 @@ def call_munger(
150158
) -> Union[
151159
Tuple[TxParams, BlockIdentifier], Tuple[TxParams, BlockIdentifier, CallOverride]
152160
]:
153-
# TODO: move to middleware
154-
if "from" not in transaction and is_checksum_address(self.default_account):
155-
transaction = assoc(transaction, "from", self.default_account)
156-
157-
# TODO: move to middleware
158-
if block_identifier is None:
159-
block_identifier = self.default_block
160-
161-
if state_override is None:
162-
return (transaction, block_identifier)
163-
else:
164-
return (transaction, block_identifier, state_override)
161+
return self._eth_call_and_estimate_gas_munger(
162+
transaction, block_identifier, state_override
163+
)
165164

166165
def create_access_list_munger(
167166
self, transaction: TxParams, block_identifier: Optional[BlockIdentifier] = None

0 commit comments

Comments
 (0)