Skip to content

Commit

Permalink
formatting and validation middleware async support
Browse files Browse the repository at this point in the history
  • Loading branch information
fselmo committed Feb 4, 2022
1 parent 99b21f4 commit 614fcee
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 82 deletions.
1 change: 1 addition & 0 deletions newsfragments/2098.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
async support for formatting, validation, and geth poa middlewares
4 changes: 3 additions & 1 deletion tests/integration/go_ethereum/test_goethereum_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from web3.middleware import (
async_buffered_gas_estimate_middleware,
async_gas_price_strategy_middleware,
async_validation_middleware,
)
from web3.net import (
AsyncNet,
Expand Down Expand Up @@ -95,8 +96,9 @@ async def async_w3(geth_process, endpoint_uri):
_web3 = Web3(
AsyncHTTPProvider(endpoint_uri),
middlewares=[
async_buffered_gas_estimate_middleware,
async_gas_price_strategy_middleware,
async_buffered_gas_estimate_middleware
async_validation_middleware,
],
modules={'eth': AsyncEth,
'async_net': AsyncNet,
Expand Down
69 changes: 69 additions & 0 deletions web3/_utils/module_testing/eth_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,14 @@
TimeExhausted,
TransactionNotFound,
TransactionTypeMismatch,
ValidationError,
)
from web3.middleware import (
async_geth_poa_middleware,
)
from web3.middleware.fixture import (
async_construct_error_generator_middleware,
async_construct_result_generator_middleware,
construct_error_generator_middleware,
)
from web3.types import ( # noqa: F401
Expand Down Expand Up @@ -290,6 +295,47 @@ async def test_eth_send_transaction_max_fee_less_than_tip(
):
await async_w3.eth.send_transaction(txn_params) # type: ignore

@pytest.mark.asyncio
async def test_validation_middleware_chain_id_mismatch(
self, async_w3: "Web3", unlocked_account_dual_type: ChecksumAddress
) -> None:
wrong_chain_id = 1234567890
actual_chain_id = await async_w3.eth.chain_id # type: ignore

txn_params: TxParams = {
'from': unlocked_account_dual_type,
'to': unlocked_account_dual_type,
'value': Wei(1),
'gas': Wei(21000),
'maxFeePerGas': async_w3.toWei(2, 'gwei'),
'maxPriorityFeePerGas': async_w3.toWei(1, 'gwei'),
'chainId': wrong_chain_id,

}
with pytest.raises(
ValidationError,
match=f'The transaction declared chain ID {wrong_chain_id}, '
f'but the connected node is on {actual_chain_id}'
):
await async_w3.eth.send_transaction(txn_params) # type: ignore

@pytest.mark.asyncio
async def test_geth_poa_middleware(self, async_w3: "Web3") -> None:
return_block_with_long_extra_data = await async_construct_result_generator_middleware(
{
RPCEndpoint('eth_getBlockByNumber'): lambda *_: {'extraData': '0x' + 'ff' * 33},
}
)
async_w3.middleware_onion.inject(async_geth_poa_middleware, 'poa', layer=0)
async_w3.middleware_onion.inject(return_block_with_long_extra_data, 'extradata', layer=0)
block = await async_w3.eth.get_block('latest') # type: ignore
assert 'extraData' not in block
assert block.proofOfAuthorityData == b'\xff' * 33

# clean up
async_w3.middleware_onion.remove('poa')
async_w3.middleware_onion.remove('extradata')

@pytest.mark.asyncio
async def test_eth_send_raw_transaction(self, async_w3: "Web3") -> None:
# private key 0x3c2ab4e8f17a7dea191b8c991522660126d681039509dc3bb31af7c9bdb63518
Expand Down Expand Up @@ -1997,6 +2043,29 @@ def test_eth_send_transaction_max_fee_less_than_tip(
):
web3.eth.send_transaction(txn_params)

def test_validation_middleware_chain_id_mismatch(
self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress
) -> None:
wrong_chain_id = 1234567890
actual_chain_id = web3.eth.chain_id

txn_params: TxParams = {
'from': unlocked_account_dual_type,
'to': unlocked_account_dual_type,
'value': Wei(1),
'gas': Wei(21000),
'maxFeePerGas': web3.toWei(2, 'gwei'),
'maxPriorityFeePerGas': web3.toWei(1, 'gwei'),
'chainId': wrong_chain_id,

}
with pytest.raises(
ValidationError,
match=f'The transaction declared chain ID {wrong_chain_id}, '
f'but the connected node is on {actual_chain_id}'
):
web3.eth.send_transaction(txn_params)

@pytest.mark.parametrize(
"max_fee",
(1000000000, None),
Expand Down
6 changes: 3 additions & 3 deletions web3/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ def default_middlewares(
"""
return [
(request_parameter_normalizer, 'request_param_normalizer'), # Delete
(gas_price_strategy_middleware, 'gas_price_strategy'), # Add Async
(gas_price_strategy_middleware, 'gas_price_strategy'),
(name_to_address_middleware(web3), 'name_to_address'), # Add Async
(attrdict_middleware, 'attrdict'), # Delete
(pythonic_middleware, 'pythonic'), # Delete
(validation_middleware, 'validation'), # Add async
(validation_middleware, 'validation'),
(abi_middleware, 'abi'), # Delete
(buffered_gas_estimate_middleware, 'gas_estimate'),
]
Expand All @@ -159,8 +159,8 @@ async def _coro_make_request(
self.logger.debug("Making request. Method: %s", method)
return await request_func(method, params)

@staticmethod
def formatted_response(
self,
response: RPCResponse,
params: Any,
error_formatters: Optional[Callable[..., Any]] = None,
Expand Down
2 changes: 2 additions & 0 deletions web3/middleware/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
gas_price_strategy_middleware,
)
from .geth_poa import ( # noqa: F401
async_geth_poa_middleware,
geth_poa_middleware,
)
from .names import ( # noqa: F401
Expand All @@ -69,6 +70,7 @@
make_stalecheck_middleware,
)
from .validation import ( # noqa: F401
async_validation_middleware,
validation_middleware,
)

Expand Down
4 changes: 2 additions & 2 deletions web3/middleware/buffered_gas_estimate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
TYPE_CHECKING,
Any,
Callable,
Coroutine,
)

from eth_utils.toolz import (
Expand All @@ -16,6 +15,7 @@
get_buffered_gas_estimate,
)
from web3.types import (
AsyncMiddleware,
RPCEndpoint,
RPCResponse,
)
Expand Down Expand Up @@ -43,7 +43,7 @@ def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:

async def async_buffered_gas_estimate_middleware(
make_request: Callable[[RPCEndpoint, Any], Any], web3: "Web3"
) -> Callable[[RPCEndpoint, Any], Coroutine[Any, Any, RPCResponse]]:
) -> AsyncMiddleware:
async def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
if method == 'eth_sendTransaction':
transaction = params[0]
Expand Down
26 changes: 24 additions & 2 deletions web3/middleware/fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
TYPE_CHECKING,
Any,
Callable,
Coroutine,
Dict,
)

from web3.types import (
AsyncMiddleware,
Middleware,
RPCEndpoint,
RPCResponse,
Expand Down Expand Up @@ -78,6 +78,28 @@ def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
return error_generator_middleware


# --- async --- #

async def async_construct_result_generator_middleware(
result_generators: Dict[RPCEndpoint, Any]
) -> Middleware:
"""
Constructs a middleware which returns a static response for any method
which is found in the provided fixtures.
"""
async def result_generator_middleware(
make_request: Callable[[RPCEndpoint, Any], Any], _: "Web3"
) -> AsyncMiddleware:
async def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
if method in result_generators:
result = result_generators[method](method, params)
return {'result': result}
else:
return await make_request(method, params)
return middleware
return result_generator_middleware


async def async_construct_error_generator_middleware(
error_generators: Dict[RPCEndpoint, Any]
) -> Middleware:
Expand All @@ -89,7 +111,7 @@ async def async_construct_error_generator_middleware(
"""
async def error_generator_middleware(
make_request: Callable[[RPCEndpoint, Any], Any], _: "Web3"
) -> Callable[[RPCEndpoint, Any], Coroutine[Any, Any, RPCResponse]]:
) -> AsyncMiddleware:
async def middleware(method: RPCEndpoint, params: Any) -> RPCResponse:
if method in error_generators:
error_msg = error_generators[method](method, params)
Expand Down
Loading

0 comments on commit 614fcee

Please sign in to comment.