middleware
Documentation for eth_defi.middleware Python module.
Web3 middleware.
Most are for dealing with JSON-RPC unreliability issues with retries.
Taken from exception_retry_request.py from Web3.py
Modified to support sleep and throttling
Logs warnings to Python logging subsystem in the case there is need to retry
See also
eth_defi.provider.broken_provider.
Module Attributes
List of Web3 exceptions we know we should retry after some timeout |
|
List of HTTP status codes we know we might want to retry after a timeout |
|
HTTP status codes that indicate potential API key/authentication issues We retry these but log a warning to alert the user |
|
List of ValueError status codes we know we might want to retry after a timeout |
|
Because Ethreum JSON-RPC API is horribly broken, we also need to check for error messages besides error codes. |
|
Ethereum JSON-RPC calls where the value never changes |
|
How long, in milliseconds, a send through |
|
Receipt poll interval, in seconds, after an |
|
EIP-7966 error code for a transaction accepted but not mined within the timeout. |
Functions
|
Configure provider retry settings for web3.py v7+. |
Capture transactions sign and send as raw transactions - v6/v7 compatible. |
|
|
Creates middleware that retries failed HTTP requests. |
A HTTP retry middleware with sleep and backoff. |
|
|
Helper to check retryable errors from JSON-RPC calls. |
|
Automatically show the transaction revert reason in Python traceback. |
Classes
Return from a transaction send only once Anvil has mined the transaction. |
|
Cache JSON-RPC call values that never change. |
|
Exceptions
A special exception raised when we suspect JSON-RPC node does not yet have data for a block we asked. |
|
Deal with non-standard RPC providers and whatever shitty logic they have invented for error codes |
- exception SomeCrappyRPCProviderException
Bases:
ExceptionDeal with non-standard RPC providers and whatever shitty logic they have invented for error codes
- __init__(*args, **kwargs)
- __new__(**kwargs)
- add_note(note, /)
Add a note to the exception
- with_traceback(tb, /)
Set self.__traceback__ to tb and return self.
- DEFAULT_RETRYABLE_EXCEPTIONS: Tuple[BaseException] = (<class 'requests.exceptions.ConnectionError'>, <class 'requests.exceptions.HTTPError'>, <class 'requests.exceptions.Timeout'>, <class 'requests.exceptions.TooManyRedirects'>, <class 'web3.exceptions.BlockNotFound'>, <class 'requests.exceptions.ChunkedEncodingError'>, <class 'http.client.RemoteDisconnected'>, <class 'eth_defi.middleware.SomeCrappyRPCProviderException'>, <class 'requests.exceptions.ContentDecodingError'>)
List of Web3 exceptions we know we should retry after some timeout
For
BlockNotFoundsee alsoeth_defi.rpc.broken_provider.
- DEFAULT_RETRYABLE_HTTP_STATUS_CODES = (429, 500, 502, 503, 504, 525, 520, 410, 403, 400, 401)
List of HTTP status codes we know we might want to retry after a timeout
Taken from https://stackoverflow.com/a/72302017/315168
- AUTH_WARNING_HTTP_STATUS_CODES = (401, 403)
HTTP status codes that indicate potential API key/authentication issues We retry these but log a warning to alert the user
- DEFAULT_RETRYABLE_RPC_ERROR_CODES = (-32003, -32043, -32005, -32701, 42903, -32002, -32603, -32052, -32601)
List of ValueError status codes we know we might want to retry after a timeout
This is a self-managed list curated by pain.
JSON-RPC error might be mapped to
ValueErrorif nothing else is available.Example from Pokt Network:
ValueError: {‘message’: ‘Internal JSON-RPC error.’, ‘code’: -32603}
We assume this is a broken RPC node and Pokt will reroute the the next retried request to some other node.
See GoEthereum error codes https://github.com/ethereum/go-ethereum/blob/master/rpc/errors.go
- DEFAULT_RETRYABLE_RPC_ERROR_MESSAGES = {'Internal JSON-RPC error', 'Parse error', 'Unexpected error (code=40000)', 'empty reader set', 'execution aborted (timeout = 5s)', 'header not found', 'missing trie node', 'nonce too low', 'pruned history unavailable'}
Because Ethreum JSON-RPC API is horribly broken, we also need to check for error messages besides error codes.
- STATIC_CALL_LIST = ('eth_chainId',)
Ethereum JSON-RPC calls where the value never changes
- exception ProbablyNodeHasNoBlock
Bases:
ExceptionA special exception raised when we suspect JSON-RPC node does not yet have data for a block we asked.
Calling a contract on a block before contract was deployed
Calling a contract on a block where the node does not have the block data yet
See
eth_defi.provider.fallbackfor details.- __init__(*args, **kwargs)
- __new__(**kwargs)
- add_note(note, /)
Add a note to the exception
- with_traceback(tb, /)
Set self.__traceback__ to tb and return self.
- is_retryable_http_exception(exc, retryable_exceptions=(<class 'requests.exceptions.ConnectionError'>, <class 'requests.exceptions.HTTPError'>, <class 'requests.exceptions.Timeout'>, <class 'requests.exceptions.TooManyRedirects'>, <class 'web3.exceptions.BlockNotFound'>, <class 'requests.exceptions.ChunkedEncodingError'>, <class 'http.client.RemoteDisconnected'>, <class 'eth_defi.middleware.SomeCrappyRPCProviderException'>, <class 'requests.exceptions.ContentDecodingError'>), retryable_status_codes=(429, 500, 502, 503, 504, 525, 520, 410, 403, 400, 401), retryable_rpc_error_codes=(-32003, -32043, -32005, -32701, 42903, -32002, -32603, -32052, -32601), retryable_rpc_error_messages={'Internal JSON-RPC error', 'Parse error', 'Unexpected error (code=40000)', 'empty reader set', 'execution aborted (timeout = 5s)', 'header not found', 'missing trie node', 'nonce too low', 'pruned history unavailable'}, method=None, params=None)
Helper to check retryable errors from JSON-RPC calls.
Retryable reasons are connection timeouts, API throttling and such.
We support various kind of exceptions and HTTP status codes we know we can try.
- Parameters
exc (Exception) – Exception raised by
requestsor Web3 machinery.retryable_exceptions (Tuple[BaseException]) – Exception raised by
requestsor Web3 machinery.retryable_status_codes (Collection[int]) – HTTP status codes we can retry. E.g. 429 Too Many requests.
retryable_rpc_error_messages (Collection[str]) – See
DEFAULT_RETRYABLE_RPC_ERROR_MESSAGES.retryable_rpc_error_codes (Collection[int]) –
- exception_retry_middleware(make_request, web3, retryable_exceptions, retryable_status_codes, retryable_rpc_error_codes, retries=10, sleep=5.0, backoff=1.6)
Creates middleware that retries failed HTTP requests. Is a default middleware for HTTPProvider.
MIGRATED: Now uses compat version for v6/v7 compatibility.
See
http_retry_request_with_sleep_middleware()for usage.- Parameters
make_request (Callable[[web3.types.RPCEndpoint, Any], web3.types.RPCResponse]) –
web3 (web3.main.Web3) –
retryable_exceptions (Tuple[BaseException]) –
retryable_status_codes (Collection[int]) –
retryable_rpc_error_codes (Collection[int]) –
retries (int) –
sleep (float) –
backoff (float) –
- Return type
Callable[[web3.types.RPCEndpoint, Any], web3.types.RPCResponse]
- http_retry_request_with_sleep_middleware(make_request, web3)
A HTTP retry middleware with sleep and backoff.
MIGRATED: In web3.py v7+, this function is deprecated in favor of ExceptionRetryConfiguration on the provider. However, for backwards compatibility, this function still works but may not be called if v7 provider retry configuration is used instead.
If you want to customise timeouts, supported exceptions and such you can directly create your own middleware using
exception_retry_middleware().Usage:
web3.middleware_onion.clear() web3.middleware_onion.inject(http_retry_request_with_sleep_middleware, layer=0)
- configure_provider_retry(provider, retries=10, backoff_factor=0.5, retryable_exceptions=None)
Configure provider retry settings for web3.py v7+.
This is the recommended way to configure retries in v7+.
- raise_on_revert_middleware(make_request, web3)
Automatically show the transaction revert reason in Python traceback.
Designed to make writing unit tests more productive
Transaction will already revert in eth_estimateGas call unless you have manually set the gas limit for your transaction
If a transaction fails, this middleware display its revert reason in Python exception message
Tested with Anvil testing backend
May interfere with
http_retry_request_with_sleep_middleware(), others, so don’t use in production
from eth_defi.middleware import revert_reason_middleware # Fix the web3.py stock gas estimate middlware with smarted one web3.middleware_onion.replace("gas_estimate", revert_reason_aware_buffered_gas_estimate_middleware) # Now you check the revert reason as the following
- construct_sign_and_send_raw_middleware_anvil(private_key_or_account)
Capture transactions sign and send as raw transactions - v6/v7 compatible.
- Return type
Type[web3.middleware.base.Web3Middleware]
- class StaticCallCacheMiddleware
Bases:
web3.middleware.base.Web3MiddlewareCache JSON-RPC call values that never change.
The cache is stored on the web3 instance itself, to allow sharing the cache between different JSON-RPC providers.
- __init__(w3)
- static_call_cache_middleware
- ANVIL_SYNC_SEND_TIMEOUT_MS = 1000
How long, in milliseconds, a send through
AnvilSyncSendMiddlewarewaits for Anvil to mine the transaction before returning the hash anyway.An automined transaction is mined in about 15 ms. The bound only matters when the transaction cannot be mined at once: automining is off, the fork is on interval mining, there is a nonce gap, or a cold fork read is slow. The caller then gets the hash as with a normal send and polls for the receipt as before.
- ANVIL_SYNC_SEND_POLL_SECONDS = 0.005
Receipt poll interval, in seconds, after an
eth_sendTransactioninAnvilSyncSendMiddleware.
- EIP_7966_TIMEOUT_ERROR_CODE = 4
EIP-7966 error code for a transaction accepted but not mined within the timeout. The error
datacarries the transaction hash.
- class AnvilSyncSendMiddleware
Bases:
web3.middleware.base.Web3MiddlewareReturn from a transaction send only once Anvil has mined the transaction.
Anvil 1.8 automines asynchronously:
eth_sendRawTransactionandeth_sendTransactionreturn the hash before the block exists, so the first receipt poll misses and every receipt wait sleeps one poll interval, one second in our confirmation helpers.eth_sendRawTransactiongoes through the EIP-7966eth_sendRawTransactionSyncmethod, which Anvil answers with the receipt once the transaction is mined. The middleware returns the hash, as the plain method would.eth_sendTransactionis sent as is, because Anvil’seth_sendTransactionSynctakes no timeout and waits 30 s for a transaction that cannot be mined. The middleware then polls the receipt everyANVIL_SYNC_SEND_POLL_SECONDSbefore returning.Both wait at most
ANVIL_SYNC_SEND_TIMEOUT_MS, then return the hash, so tests that mine on demand keep working.On an Anvil without the sync method, raw sends fall back to the plain method for the rest of the connection’s life.
Other errors, such as a nonce or gas error, are passed through unchanged.
Callers see no API change; their first receipt read succeeds.
Installed by
eth_defi.provider.multi_provider.create_multi_provider_web3()for Anvil connections only. It must be the innermost middleware, so that the signing middleware’seth_sendRawTransactionalso goes through it.- __init__(w3)
- Parameters
w3 (web3.main.Web3) –