Skip to content

Commit

Permalink
add tests for max_priority_fee when eth_maxPriorityFeePerGas is not a…
Browse files Browse the repository at this point in the history
…vailable
  • Loading branch information
fselmo committed Feb 1, 2022
1 parent 7addd65 commit 11973e3
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 17 deletions.
28 changes: 14 additions & 14 deletions tests/core/contracts/test_contract_buildTransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ def test_build_transaction_not_paying_to_nonpayable_function(
'to': payable_tester_contract.address,
'data': '0xe4cb8f5c',
'value': 0,
'maxFeePerGas': 3750000000,
'maxPriorityFeePerGas': 2 * (10 ** 9),
'maxFeePerGas': 2750000000,
'maxPriorityFeePerGas': 10 ** 9,
'chainId': 61,
}

Expand All @@ -76,8 +76,8 @@ def test_build_transaction_with_contract_no_arguments(web3, math_contract, build
'to': math_contract.address,
'data': '0xd09de08a',
'value': 0,
'maxFeePerGas': 3750000000,
'maxPriorityFeePerGas': 2 * (10 ** 9),
'maxFeePerGas': 2750000000,
'maxPriorityFeePerGas': 10 ** 9,
'chainId': 61,
}

Expand All @@ -88,8 +88,8 @@ def test_build_transaction_with_contract_fallback_function(web3, fallback_functi
'to': fallback_function_contract.address,
'data': '0x',
'value': 0,
'maxFeePerGas': 3750000000,
'maxPriorityFeePerGas': 2 * (10 ** 9),
'maxFeePerGas': 2750000000,
'maxPriorityFeePerGas': 10 ** 9,
'chainId': 61,
}

Expand All @@ -108,8 +108,8 @@ def test_build_transaction_with_contract_class_method(
'to': math_contract.address,
'data': '0xd09de08a',
'value': 0,
'maxFeePerGas': 3750000000,
'maxPriorityFeePerGas': 2 * (10 ** 9),
'maxFeePerGas': 2750000000,
'maxPriorityFeePerGas': 10 ** 9,
'chainId': 61,
}

Expand All @@ -123,8 +123,8 @@ def test_build_transaction_with_contract_default_account_is_set(
'to': math_contract.address,
'data': '0xd09de08a',
'value': 0,
'maxFeePerGas': 3750000000,
'maxPriorityFeePerGas': 2 * (10 ** 9),
'maxFeePerGas': 2750000000,
'maxPriorityFeePerGas': 10 ** 9,
'chainId': 61,
}

Expand Down Expand Up @@ -167,14 +167,14 @@ def test_build_transaction_with_contract_to_address_supplied_errors(web3,
(
{}, (5,), {}, {
'data': '0x7cf5dab00000000000000000000000000000000000000000000000000000000000000005', # noqa: E501
'value': 0, 'maxFeePerGas': 3750000000, 'maxPriorityFeePerGas': 2 * (10 ** 9),
'value': 0, 'maxFeePerGas': 2750000000, 'maxPriorityFeePerGas': 1000000000,
'chainId': 61,
}, False
),
(
{'gas': 800000}, (5,), {}, {
'data': '0x7cf5dab00000000000000000000000000000000000000000000000000000000000000005', # noqa: E501
'value': 0, 'maxFeePerGas': 3750000000, 'maxPriorityFeePerGas': 2 * (10 ** 9),
'value': 0, 'maxFeePerGas': 2750000000, 'maxPriorityFeePerGas': 1000000000,
'chainId': 61,
}, False
),
Expand All @@ -194,14 +194,14 @@ def test_build_transaction_with_contract_to_address_supplied_errors(web3,
(
{'nonce': 7}, (5,), {}, {
'data': '0x7cf5dab00000000000000000000000000000000000000000000000000000000000000005', # noqa: E501
'value': 0, 'maxFeePerGas': 3750000000, 'maxPriorityFeePerGas': 2 * (10 ** 9),
'value': 0, 'maxFeePerGas': 2750000000, 'maxPriorityFeePerGas': 1000000000,
'nonce': 7, 'chainId': 61,
}, True
),
(
{'value': 20000}, (5,), {}, {
'data': '0x7cf5dab00000000000000000000000000000000000000000000000000000000000000005', # noqa: E501
'value': 20000, 'maxFeePerGas': 3750000000, 'maxPriorityFeePerGas': 2 * (10 ** 9),
'value': 20000, 'maxFeePerGas': 2750000000, 'maxPriorityFeePerGas': 1000000000,
'chainId': 61,
}, False
),
Expand Down
73 changes: 73 additions & 0 deletions tests/core/utilities/test_fee_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import pytest

from eth_utils import (
is_integer,
)

from web3.middleware import (
construct_error_generator_middleware,
construct_result_generator_middleware,
)
from web3.types import (
RPCEndpoint,
)


@pytest.mark.parametrize(
'fee_history_result,expected_max_prio_calc',
(
(
{
'reward': [[10 ** 20], [10 ** 20], [10 ** 20], [10 ** 20]],
},
15 * (10 ** 8),
),
(
{
'reward': [[10 ** 2], [10 ** 2], [10 ** 2], [10 ** 2], [10 ** 2]],
},
10 ** 9,
),
(
{
'reward': [[0], [0], [0], [0], [0]],
},
10 ** 9,
),
(
{
'reward': [[1223344455], [1111111111], [1222777777], [0], [1000222111], [0], [0]],
},
round(sum([1223344455, 1111111111, 1222777777, 1000222111]) / 4),
),
),
ids=[
'test-max', 'test-min', 'test-min-all-zero-fees', 'test-non-zero-average'
]
)
# Test fee_utils indirectly by mocking eth_feeHistory results and checking against expected output
def test_fee_utils_indirectly(
web3, fee_history_result, expected_max_prio_calc
) -> None:
fail_max_prio_middleware = construct_error_generator_middleware(
{RPCEndpoint("eth_maxPriorityFeePerGas"): lambda *_: ''}
)
fee_history_result_middleware = construct_result_generator_middleware(
{RPCEndpoint('eth_feeHistory'): lambda *_: fee_history_result}
)

web3.middleware_onion.add(fail_max_prio_middleware, 'fail_max_prio')
web3.middleware_onion.inject(fee_history_result_middleware, 'fee_history_result', layer=0)

with pytest.warns(
UserWarning,
match="There was an issue with the method eth_maxPriorityFeePerGas. Calculating using "
"eth_feeHistory."
):
max_priority_fee = web3.eth.max_priority_fee
assert is_integer(max_priority_fee)
assert max_priority_fee == expected_max_prio_calc

# clean up
web3.middleware_onion.remove('fail_max_prio')
web3.middleware_onion.remove('fee_history_result')
4 changes: 4 additions & 0 deletions tests/integration/test_ethereum_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ def func_wrapper(self, eth_tester, *args, **kwargs):


class TestEthereumTesterEthModule(EthModuleTest):
test_eth_max_priority_fee_with_fee_history_calculation = not_implemented(
EthModuleTest.test_eth_max_priority_fee_with_fee_history_calculation,
ValueError
)
test_eth_sign = not_implemented(EthModuleTest.test_eth_sign, ValueError)
test_eth_sign_ens_names = not_implemented(
EthModuleTest.test_eth_sign_ens_names, ValueError
Expand Down
40 changes: 40 additions & 0 deletions web3/_utils/module_testing/eth_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,16 @@
TransactionNotFound,
TransactionTypeMismatch,
)
from web3.middleware.fixture import (
async_construct_error_generator_middleware,
construct_error_generator_middleware,
)
from web3.types import ( # noqa: F401
BlockData,
FilterParams,
LogReceipt,
Nonce,
RPCEndpoint,
SyncStatus,
TxParams,
Wei,
Expand Down Expand Up @@ -423,6 +428,25 @@ async def test_eth_max_priority_fee(self, async_w3: "Web3") -> None:
max_priority_fee = await async_w3.eth.max_priority_fee # type: ignore
assert is_integer(max_priority_fee)

@pytest.mark.asyncio
async def test_eth_max_priority_fee_with_fee_history_calculation(
self, async_w3: "Web3"
) -> None:
fail_max_prio_middleware = await async_construct_error_generator_middleware(
{RPCEndpoint("eth_maxPriorityFeePerGas"): lambda *_: ''}
)
async_w3.middleware_onion.add(fail_max_prio_middleware, name='fail_max_prio_middleware')

with pytest.warns(
UserWarning,
match="There was an issue with the method eth_maxPriorityFeePerGas. Calculating using "
"eth_feeHistory."
):
max_priority_fee = await async_w3.eth.max_priority_fee # type: ignore
assert is_integer(max_priority_fee)

async_w3.middleware_onion.remove('fail_max_prio_middleware') # clean up

@pytest.mark.asyncio
async def test_eth_getBlockByHash(
self, async_w3: "Web3", empty_block: BlockData
Expand Down Expand Up @@ -1136,6 +1160,22 @@ def test_eth_max_priority_fee(self, web3: "Web3") -> None:
max_priority_fee = web3.eth.max_priority_fee
assert is_integer(max_priority_fee)

def test_eth_max_priority_fee_with_fee_history_calculation(self, web3: "Web3") -> None:
fail_max_prio_middleware = construct_error_generator_middleware(
{RPCEndpoint("eth_maxPriorityFeePerGas"): lambda *_: ''}
)
web3.middleware_onion.add(fail_max_prio_middleware, name='fail_max_prio_middleware')

with pytest.warns(
UserWarning,
match="There was an issue with the method eth_maxPriorityFeePerGas. Calculating using "
"eth_feeHistory."
):
max_priority_fee = web3.eth.max_priority_fee
assert is_integer(max_priority_fee)

web3.middleware_onion.remove('fail_max_prio_middleware') # clean up

def test_eth_accounts(self, web3: "Web3") -> None:
accounts = web3.eth.accounts
assert is_list_like(accounts)
Expand Down
29 changes: 26 additions & 3 deletions web3/middleware/fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
TYPE_CHECKING,
Any,
Callable,
Coroutine,
Dict,
)

Expand All @@ -21,7 +22,7 @@ def construct_fixture_middleware(fixtures: Dict[RPCEndpoint, Any]) -> Middleware
which is found in the provided fixtures.
"""
def fixture_middleware(
make_request: Callable[[RPCEndpoint, Any], Any], web3: "Web3"
make_request: Callable[[RPCEndpoint, Any], Any], _: "Web3"
) -> Callable[[RPCEndpoint, Any], RPCResponse]:
def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
if method in fixtures:
Expand All @@ -43,7 +44,7 @@ def construct_result_generator_middleware(
functions with the signature `fn(method, params)`.
"""
def result_generator_middleware(
make_request: Callable[[RPCEndpoint, Any], Any], web3: "Web3"
make_request: Callable[[RPCEndpoint, Any], Any], _: "Web3"
) -> Callable[[RPCEndpoint, Any], RPCResponse]:
def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
if method in result_generators:
Expand All @@ -65,7 +66,7 @@ def construct_error_generator_middleware(
functions with the signature `fn(method, params)`.
"""
def error_generator_middleware(
make_request: Callable[[RPCEndpoint, Any], Any], web3: "Web3"
make_request: Callable[[RPCEndpoint, Any], Any], _: "Web3"
) -> Callable[[RPCEndpoint, Any], RPCResponse]:
def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
if method in error_generators:
Expand All @@ -75,3 +76,25 @@ def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
return make_request(method, params)
return middleware
return error_generator_middleware


async def async_construct_error_generator_middleware(
error_generators: Dict[RPCEndpoint, Any]
) -> Middleware:
"""
Constructs a middleware which intercepts requests for any method found in
the provided mapping of endpoints to generator functions, returning
whatever error message the generator function returns. Callbacks must be
functions with the signature `fn(method, params)`.
"""
async def error_generator_middleware(
make_request: Callable[[RPCEndpoint, Any], Any], _: "Web3"
) -> Callable[[RPCEndpoint, Any], Coroutine[Any, Any, RPCResponse]]:
async def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
if method in error_generators:
error_msg = error_generators[method](method, params)
return {'error': error_msg}
else:
return await make_request(method, params)
return middleware
return error_generator_middleware

0 comments on commit 11973e3

Please sign in to comment.