From de8d96e8eaebaa8082e1dc2e498e211dc5b08600 Mon Sep 17 00:00:00 2001 From: Kieran Prasch Date: Sun, 29 Oct 2023 20:15:52 +0100 Subject: [PATCH] use domain lookups sparingly and cache the lookups results --- nucypher/blockchain/eth/actors.py | 5 +++-- nucypher/blockchain/eth/domains.py | 14 ++++---------- nucypher/blockchain/eth/registry.py | 6 ++---- nucypher/characters/base.py | 7 +++---- nucypher/characters/lawful.py | 2 -- nucypher/network/nodes.py | 8 ++------ nucypher/policy/payment.py | 2 +- tests/unit/test_character_sign_and_verify.py | 6 +++--- 8 files changed, 18 insertions(+), 32 deletions(-) diff --git a/nucypher/blockchain/eth/actors.py b/nucypher/blockchain/eth/actors.py index e760d77e5..b112b360d 100644 --- a/nucypher/blockchain/eth/actors.py +++ b/nucypher/blockchain/eth/actors.py @@ -37,6 +37,7 @@ from nucypher.blockchain.eth.agents import ( from nucypher.blockchain.eth.clients import PUBLIC_CHAINS from nucypher.blockchain.eth.constants import NULL_ADDRESS from nucypher.blockchain.eth.decorators import validate_checksum_address +from nucypher.blockchain.eth.domains import TACoDomain from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory from nucypher.blockchain.eth.registry import ( ContractRegistry, @@ -69,7 +70,7 @@ class BaseActor: @validate_checksum_address def __init__( self, - domain: str, + domain: TACoDomain, registry: ContractRegistry, transacting_power: Optional[TransactingPower] = None, checksum_address: Optional[ChecksumAddress] = None, @@ -92,7 +93,7 @@ class BaseActor: self.transacting_power = transacting_power self.registry = registry - self.domain = domains.get_domain(str(domain)) + self.domain = domain self._saved_receipts = list() # track receipts of transmitted transactions def __repr__(self): diff --git a/nucypher/blockchain/eth/domains.py b/nucypher/blockchain/eth/domains.py index 1a6594477..5c30523e5 100644 --- a/nucypher/blockchain/eth/domains.py +++ b/nucypher/blockchain/eth/domains.py @@ -1,3 +1,4 @@ +from cytoolz.functoolz import memoize from enum import Enum from typing import NamedTuple, Dict @@ -24,11 +25,7 @@ class PolygonChain(ChainInfo, Enum): class TACoDomain: - def __init__(self, - name: str, - eth_chain: EthChain, - polygon_chain: PolygonChain, - ): + def __init__(self, name: str, eth_chain: EthChain, polygon_chain: PolygonChain): self.name = name self.eth_chain = eth_chain self.polygon_chain = polygon_chain @@ -54,9 +51,6 @@ class TACoDomain: def __bool__(self): return True - def __iter__(self): - return str(self) - @property def is_testnet(self) -> bool: return self.eth_chain != EthChain.MAINNET @@ -80,14 +74,14 @@ TAPIR = TACoDomain( polygon_chain=PolygonChain.MUMBAI, ) -__DOMAINS = (MAINNET, LYNX, TAPIR) DEFAULT_DOMAIN: TACoDomain = MAINNET -SUPPORTED_DOMAINS: Dict[str, TACoDomain] = {domain.name: domain for domain in __DOMAINS} +SUPPORTED_DOMAINS: Dict[str, TACoDomain] = {domain.name: domain for domain in (MAINNET, LYNX, TAPIR)} +@memoize def get_domain(d: str) -> TACoDomain: if not isinstance(d, str): raise TypeError(f"domain must be a string, not {type(d)}") diff --git a/nucypher/blockchain/eth/registry.py b/nucypher/blockchain/eth/registry.py index fed0f206b..7ea7417b1 100644 --- a/nucypher/blockchain/eth/registry.py +++ b/nucypher/blockchain/eth/registry.py @@ -34,8 +34,7 @@ class RegistrySource(ABC): class Unavailable(RegistrySourceError): """Raised when there are no available registry sources""" - def __init__(self, domain: Union[str, TACoDomain], *args, **kwargs): - domain = domains.get_domain(str(domain)) + def __init__(self, domain: TACoDomain, *args, **kwargs): if str(domain) not in domains.SUPPORTED_DOMAINS: raise ValueError( f"{self.__class__.__name__} not available for domain '{domain}'. " @@ -303,11 +302,10 @@ class ContractRegistry: @classmethod def from_latest_publication( cls, - domain: Union[str, TACoDomain], + domain: TACoDomain, source_manager: Optional[RegistrySourceManager] = None, ) -> "ContractRegistry": """Get the latest contract registry available from a registry source chain.""" - domain = domains.get_domain(str(domain)) source_manager = source_manager or RegistrySourceManager(domain=domain) source = source_manager.fetch_latest_publication() registry = cls(source=source) diff --git a/nucypher/characters/base.py b/nucypher/characters/base.py index 2734ac55a..766f04a0f 100644 --- a/nucypher/characters/base.py +++ b/nucypher/characters/base.py @@ -79,6 +79,8 @@ class Character(Learner): """ + self.domain = domains.get_domain(str(domain)) + # # Keys & Powers # @@ -118,9 +120,7 @@ class Character(Learner): self.eth_endpoint = eth_endpoint self.polygon_endpoint = polygon_endpoint - self.registry = registry or ContractRegistry.from_latest_publication( - domain=domains.get_domain(str(domain)), - ) + self.registry = registry or ContractRegistry.from_latest_publication(domain) # REST self.network_middleware = network_middleware or RestMiddleware( @@ -129,7 +129,6 @@ class Character(Learner): # Learner Learner.__init__(self, - domain=domain, network_middleware=self.network_middleware, node_class=known_node_class, include_self_in_the_state=include_self_in_the_state, diff --git a/nucypher/characters/lawful.py b/nucypher/characters/lawful.py index aabb98890..5eb45761f 100644 --- a/nucypher/characters/lawful.py +++ b/nucypher/characters/lawful.py @@ -827,7 +827,6 @@ class Ursula(Teacher, Character, Operator): known_nodes: Iterable[Teacher] = None, **character_kwargs, ): - domain = domains.get_domain(str(domain)) Character.__init__( self, is_me=is_me, @@ -905,7 +904,6 @@ class Ursula(Teacher, Character, Operator): # Teacher (All Modes) Teacher.__init__( self, - domain=domain, certificate=certificate, certificate_filepath=certificate_filepath, ) diff --git a/nucypher/network/nodes.py b/nucypher/network/nodes.py index a7c3b1100..1ae4ff88e 100644 --- a/nucypher/network/nodes.py +++ b/nucypher/network/nodes.py @@ -29,6 +29,7 @@ from nucypher.acumen.perception import FleetSensor from nucypher.blockchain.eth import domains from nucypher.blockchain.eth.agents import ContractAgency, TACoApplicationAgent from nucypher.blockchain.eth.constants import NULL_ADDRESS +from nucypher.blockchain.eth.domains import TACoDomain from nucypher.blockchain.eth.registry import ContractRegistry from nucypher.config.constants import SeednodeMetadata from nucypher.config.storages import ForgetfulNodeStorage @@ -251,7 +252,6 @@ class Learner: """ def __init__(self, - domain: str, node_class: object = None, network_middleware: RestMiddleware = None, start_learning_now: bool = False, @@ -269,7 +269,6 @@ class Learner: self.log = Logger("learning-loop") # type: Logger self.learning_deferred = Deferred() - self.domain = domains.get_domain(str(domain)) default_middleware = self.__DEFAULT_MIDDLEWARE_CLASS( registry=self.registry, eth_endpoint=self.eth_endpoint ) @@ -280,7 +279,7 @@ class Learner: self._abort_on_learning_error = abort_on_learning_error - self.__known_nodes = self.tracker_class(domain=domain, this_node=self if include_self_in_the_state else None) + self.__known_nodes = self.tracker_class(domain=self.domain, this_node=self if include_self_in_the_state else None) self._verify_node_bonding = verify_node_bonding self.lonely = lonely @@ -969,13 +968,10 @@ class Teacher: __DEFAULT_MIN_SEED_STAKE = 0 def __init__(self, - domain: str, # TODO: Consider using a Domain type certificate: Certificate, certificate_filepath: Path, ) -> None: - self.domain = domain - # # Identity # diff --git a/nucypher/policy/payment.py b/nucypher/policy/payment.py index bb0dd1d34..64dff4fa9 100644 --- a/nucypher/policy/payment.py +++ b/nucypher/policy/payment.py @@ -73,7 +73,7 @@ class ContractPayment(PaymentMethod, ABC): ): super().__init__(*args, **kwargs) self.blockchain_endpoint = blockchain_endpoint - self.domain = domains.get_domain(str(domain)) + self.domain = domain if not registry: registry = ContractRegistry.from_latest_publication(domain=self.domain) self.registry = registry diff --git a/tests/unit/test_character_sign_and_verify.py b/tests/unit/test_character_sign_and_verify.py index 2495dc4d8..cb0bb9c30 100644 --- a/tests/unit/test_character_sign_and_verify.py +++ b/tests/unit/test_character_sign_and_verify.py @@ -5,7 +5,7 @@ from nucypher.config.constants import TEMPORARY_DOMAIN_NAME from nucypher.crypto.powers import CryptoPower, NoSigningPower, SigningPower from nucypher.crypto.signing import InvalidSignature from nucypher.policy.payment import FreeReencryptions -from tests.constants import MOCK_ETH_PROVIDER_URI +from tests.constants import MOCK_ETH_PROVIDER_URI, TEMPORARY_DOMAIN """ Chapter 1: SIGNING @@ -21,7 +21,7 @@ def test_actor_without_signing_power_cannot_sign(): non_signer = Character( crypto_power=cannot_sign, start_learning_now=False, - domain=TEMPORARY_DOMAIN_NAME, + domain=TEMPORARY_DOMAIN, eth_endpoint=MOCK_ETH_PROVIDER_URI, ) @@ -46,7 +46,7 @@ def test_actor_with_signing_power_can_sign(): crypto_power_ups=[SigningPower], is_me=True, start_learning_now=False, - domain=TEMPORARY_DOMAIN_NAME, + domain=TEMPORARY_DOMAIN, eth_endpoint=MOCK_ETH_PROVIDER_URI, ) stamp_of_the_signer = signer.stamp