From dabc5d92daf908369d2dca414d5fb2d3b9c1cd41 Mon Sep 17 00:00:00 2001 From: Kieran Prasch Date: Fri, 2 Jun 2023 15:21:11 +0200 Subject: [PATCH] Improved multichain support and bugfixes (removes RPC caching). --- nucypher/blockchain/eth/actors.py | 30 ++++++++++++++++----------- nucypher/blockchain/eth/agents.py | 18 +++++++++------- nucypher/blockchain/eth/interfaces.py | 4 ---- nucypher/characters/lawful.py | 9 +++++--- nucypher/config/base.py | 11 ++++++++++ 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/nucypher/blockchain/eth/actors.py b/nucypher/blockchain/eth/actors.py index a1579d0ff..4ca856952 100644 --- a/nucypher/blockchain/eth/actors.py +++ b/nucypher/blockchain/eth/actors.py @@ -180,7 +180,6 @@ class Operator(BaseActor): # because, given the need for initialization context, it's far less melodramatic # to do it here, and it's still available via the public crypto powers API. crypto_power.consume_power_up(transacting_power) - self.payment_method = payment_method self._operator_bonded_tracker = OperatorBondedTracker(ursula=self) @@ -191,25 +190,32 @@ class Operator(BaseActor): self.__operator_address = operator_address self.__staking_provider_address = None # set by block_until_ready if is_me: - self.application_agent = ContractAgency.get_agent(PREApplicationAgent, registry=self.registry) + self.application_agent = ContractAgency.get_agent( + PREApplicationAgent, + eth_provider_uri=eth_provider_uri, + registry=self.registry, + ) self.work_tracker = work_tracker or WorkTracker(worker=self) + # # Multi-provider support + # + + # TODO: Improve and formalize fully configurable multi-provider support # TODO: Abstract away payment provider #3004 - eth_chain = self.application_agent.blockchain - polygon_chain = payment_method.agent.blockchain - - # TODO: #3094 This is a hack to get around a bug where an InfuraClient in instantiated with a Web3 instance - # that has a different provider than the one passed to the constructor. This is a temporary fix. - polygon_chain.client.w3 = Web3(polygon_chain.provider) - - # TODO: Verify consistency between network names and provider connection? # TODO: #3094 Is chain ID stable and completely reliable? - # TODO: Can this be relocated to a higher layer to better support TAC? + # TODO: Relocate to a higher layer + eth_chain = self.application_agent.blockchain + polygon_chain = self.payment_method.agent.blockchain + + # TODO: Use clients layer? self.condition_providers = { eth_chain.client.chain_id: eth_chain.provider, - polygon_chain.client.chain_id: polygon_chain.provider + polygon_chain.client.chain_id: polygon_chain.provider, } + self.log.info( + f"Connected to {len(self.condition_providers)} blockchains: {self.condition_providers}" + ) def _local_operator_address(self): return self.__operator_address diff --git a/nucypher/blockchain/eth/agents.py b/nucypher/blockchain/eth/agents.py index d8c710f7d..7319fded7 100644 --- a/nucypher/blockchain/eth/agents.py +++ b/nucypher/blockchain/eth/agents.py @@ -61,17 +61,21 @@ class EthereumContractAgent: usually, a failed `require()`. """ - def __init__(self, - registry: BaseContractRegistry = None, # TODO: Consider make it non-optional again. See comment in InstanceAgent. - eth_provider_uri: Optional[str] = None, - contract: Optional[Contract] = None, - transaction_gas: Optional[Wei] = None, - contract_version: Optional[str] = None): + def __init__( + self, + eth_provider_uri: str, + registry: BaseContractRegistry, + contract: Optional[Contract] = None, + transaction_gas: Optional[Wei] = None, + contract_version: Optional[str] = None, + ): self.log = Logger(self.__class__.__name__) self.registry = registry - self.blockchain = BlockchainInterfaceFactory.get_or_create_interface(eth_provider_uri=eth_provider_uri) + self.blockchain = BlockchainInterfaceFactory.get_or_create_interface( + eth_provider_uri=eth_provider_uri + ) if not contract: # Fetch the contract contract = self.blockchain.get_contract_by_name( diff --git a/nucypher/blockchain/eth/interfaces.py b/nucypher/blockchain/eth/interfaces.py index 408169b30..badce7e32 100644 --- a/nucypher/blockchain/eth/interfaces.py +++ b/nucypher/blockchain/eth/interfaces.py @@ -257,10 +257,6 @@ class BlockchainInterface: self.log.debug('Injecting POA middleware at layer 0') self.client.inject_middleware(geth_poa_middleware, layer=0) - self.client.add_middleware(middleware.time_based_cache_middleware) - # self.client.add_middleware(middleware.latest_block_based_cache_middleware) # TODO: This line causes failed tests and nonce reuse in tests. See #2348. - self.client.add_middleware(middleware.simple_cache_middleware) - self.configure_gas_strategy() def configure_gas_strategy(self, gas_strategy: Optional[Callable] = None) -> None: diff --git a/nucypher/characters/lawful.py b/nucypher/characters/lawful.py index 5c246a1bb..c48efd2c0 100644 --- a/nucypher/characters/lawful.py +++ b/nucypher/characters/lawful.py @@ -809,7 +809,6 @@ class Ursula(Teacher, Character, Operator, Ritualist): known_nodes: Iterable[Teacher] = None, **character_kwargs, ): - Character.__init__( self, is_me=is_me, @@ -1261,8 +1260,12 @@ class Ursula(Teacher, Character, Operator, Ritualist): # Check the node's stake (optional) if minimum_stake > 0 and staking_provider_address: - application_agent = ContractAgency.get_agent(PREApplicationAgent, registry=registry) - seednode_stake = application_agent.get_authorized_stake(staking_provider=staking_provider_address) + application_agent = ContractAgency.get_agent( + PREApplicationAgent, eth_provider_uri=provider_uri, registry=registry + ) + seednode_stake = application_agent.get_authorized_stake( + staking_provider=staking_provider_address + ) if seednode_stake < minimum_stake: raise Learner.NotATeacher(f"{staking_provider_address} is staking less than the specified minimum stake value ({minimum_stake}).") diff --git a/nucypher/config/base.py b/nucypher/config/base.py index 7b10d4f9a..115cedcad 100644 --- a/nucypher/config/base.py +++ b/nucypher/config/base.py @@ -460,6 +460,17 @@ class CharacterConfiguration(BaseConfiguration): f"Using existing blockchain interface connection ({self.eth_provider_uri})." ) + # TODO: this is potential fix for multichain connection, if we want to use it build it out into a loop + # for uri in eth_provider_uri (list of uris fom config): + BlockchainInterfaceFactory.get_or_create_interface( + eth_provider_uri=payment_provider, + poa=self.poa, + light=self.is_light, + emitter=emitter, + gas_strategy=self.gas_strategy, + max_gas_price=self.max_gas_price, + ) + if not self.registry: # TODO: These two code blocks are untested. if (