Skip to content

Commit

Permalink
feat: add dynamic middleware check (#94)
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey authored Nov 26, 2024
1 parent a39aa3b commit ddeecee
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
34 changes: 31 additions & 3 deletions ape_infura/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
from ape_ethereum.provider import Web3Provider
from web3 import HTTPProvider, Web3
from web3.exceptions import ContractLogicError as Web3ContractLogicError
from web3.exceptions import ExtraDataLengthError
from web3.gas_strategies.rpc import rpc_gas_price_strategy
from web3.middleware import geth_poa_middleware
from web3.middleware.validation import MAX_EXTRADATA_LENGTH

_ENVIRONMENT_VARIABLE_NAMES = ("WEB3_INFURA_PROJECT_ID", "WEB3_INFURA_API_KEY")
# NOTE: https://docs.infura.io/learn/websockets#supported-networks
Expand Down Expand Up @@ -94,7 +96,17 @@ def connection_str(self) -> str:
return self.uri

def connect(self):
self._web3 = Web3(HTTPProvider(self.uri))
self._web3 = _create_web3(HTTPProvider(self.uri))

if self._needs_poa_middleware:
self._web3.middleware_onion.inject(geth_poa_middleware, layer=0)

self._web3.eth.set_gas_price_strategy(rpc_gas_price_strategy)

@property
def _needs_poa_middleware(self) -> bool:
if self._web3 is None:
return False

# Any chain that *began* as PoA needs the middleware for pre-merge blocks
optimism = (10, 420)
Expand All @@ -103,9 +115,21 @@ def connect(self):
blast = (11155111, 168587773)

if self._web3.eth.chain_id in (*optimism, *polygon, *linea, *blast):
self._web3.middleware_onion.inject(geth_poa_middleware, layer=0)
return True

self._web3.eth.set_gas_price_strategy(rpc_gas_price_strategy)
for block_id in ("earliest", "latest"):
try:
block = self.web3.eth.get_block(block_id) # type: ignore
except ExtraDataLengthError:
return True
else:
if (
"proofOfAuthorityData" in block
or len(block.get("extraData", "")) > MAX_EXTRADATA_LENGTH
):
return True

return False

def disconnect(self):
"""
Expand Down Expand Up @@ -149,3 +173,7 @@ def get_virtual_machine_error(self, exception: Exception, **kwargs) -> VirtualMa
return ContractLogicError(txn=txn)

return VirtualMachineError(message, txn=txn)


def _create_web3(http_provider: HTTPProvider) -> Web3:
return Web3(http_provider)
1 change: 1 addition & 0 deletions ape_infura/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"sepolia",
],
"ethereum": [
"holesky",
"mainnet",
"sepolia",
],
Expand Down
14 changes: 14 additions & 0 deletions tests/test_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import pytest
import websocket # type: ignore
from ape import networks
from ape.utils import ZERO_ADDRESS
from web3.exceptions import ExtraDataLengthError
from web3.middleware import geth_poa_middleware

from ape_infura.provider import _WEBSOCKET_CAPABLE_ECOSYSTEMS, Infura

Expand Down Expand Up @@ -93,3 +96,14 @@ def test_uri_with_random_api_key(provider, mocker):

# Disconnect so key isn't cached.
provider.disconnect()


def test_dynamic_poa_check(mocker):
real = networks.ethereum.holesky.get_provider("infura")
mock_web3 = mocker.MagicMock()
mock_web3.eth.get_block.side_effect = ExtraDataLengthError
infura = Infura(name=real.name, network=real.network)
patch = mocker.patch("ape_infura.provider._create_web3")
patch.return_value = mock_web3
infura.connect()
mock_web3.middleware_onion.inject.assert_called_once_with(geth_poa_middleware, layer=0)

0 comments on commit ddeecee

Please sign in to comment.