Make the use of string literal type hints compatible with PEP 484

Because:
- Not doing so causes F821 linting errors

https://peps.python.org/pep-0484/#forward-references
https://www.flake8rules.com/rules/F821.html
pull/3159/head
Owen Campbell 2023-06-27 12:41:53 +01:00
parent 905de7de5d
commit a4de8a882e
No known key found for this signature in database
GPG Key ID: 628F79BCBE9C2B73
16 changed files with 237 additions and 170 deletions

View File

@ -11,6 +11,7 @@ import maya
from eth_typing import ChecksumAddress from eth_typing import ChecksumAddress
from nucypher_core import FleetStateChecksum, NodeMetadata from nucypher_core import FleetStateChecksum, NodeMetadata
from nucypher import characters
from nucypher.utilities.logging import Logger from nucypher.utilities.logging import Logger
from .nicknames import Nickname from .nicknames import Nickname
@ -41,7 +42,7 @@ class StateDiff(NamedTuple):
class FleetState: class FleetState:
""" """
Fleet state as perceived by a local Ursula. Fleet state as perceived by a local "lawful.Ursula".
Assumptions we're based on: Assumptions we're based on:
@ -57,7 +58,9 @@ class FleetState:
""" """
@classmethod @classmethod
def new(cls, this_node: Optional['Ursula'] = None) -> 'FleetState': def new(
cls, this_node: Optional["characters.lawful.Ursula"] = None
) -> "FleetState":
this_node_ref = weakref.ref(this_node) if this_node else None this_node_ref = weakref.ref(this_node) if this_node else None
# `this_node` might not have its metadata available yet. # `this_node` might not have its metadata available yet.
this_node_metadata = None this_node_metadata = None
@ -66,12 +69,16 @@ class FleetState:
this_node_ref=this_node_ref, this_node_ref=this_node_ref,
this_node_metadata=this_node_metadata) this_node_metadata=this_node_metadata)
def __init__(self, def __init__(
nodes: Dict[ChecksumAddress, 'Ursula'], self,
this_node_ref: Optional[weakref.ReferenceType], nodes: Dict[ChecksumAddress, "characters.lawful.Ursula"],
this_node_metadata: Optional[NodeMetadata]): this_node_ref: Optional[weakref.ReferenceType],
self.checksum = FleetStateChecksum(this_node=this_node_metadata, this_node_metadata: Optional[NodeMetadata],
other_nodes=[node.metadata() for node in nodes.values()]) ):
self.checksum = FleetStateChecksum(
this_node=this_node_metadata,
other_nodes=[node.metadata() for node in nodes.values()],
)
self.nickname = Nickname.from_seed(bytes(self.checksum), length=1) self.nickname = Nickname.from_seed(bytes(self.checksum), length=1)
self._nodes = nodes self._nodes = nodes
self.timestamp = maya.now() self.timestamp = maya.now()
@ -84,12 +91,12 @@ class FleetState:
timestamp=self.timestamp, timestamp=self.timestamp,
population=self.population) population=self.population)
def _calculate_diff(self, def _calculate_diff(
this_node_updated: bool, self,
nodes_to_add: Iterable['Ursula'], this_node_updated: bool,
nodes_to_remove: Iterable[ChecksumAddress] nodes_to_add: Iterable["characters.lawful.Ursula"],
) -> StateDiff: nodes_to_remove: Iterable[ChecksumAddress],
) -> StateDiff:
nodes_updated = [] nodes_updated = []
for node in nodes_to_add: for node in nodes_to_add:
if node.checksum_address in nodes_to_remove: if node.checksum_address in nodes_to_remove:
@ -107,12 +114,12 @@ class FleetState:
nodes_updated=nodes_updated, nodes_updated=nodes_updated,
nodes_removed=nodes_removed) nodes_removed=nodes_removed)
def with_updated_nodes(self, def with_updated_nodes(
nodes_to_add: Iterable['Ursula'], self,
nodes_to_remove: Iterable[ChecksumAddress], nodes_to_add: Iterable["characters.lawful.Ursula"],
skip_this_node: bool = False, nodes_to_remove: Iterable[ChecksumAddress],
) -> 'FleetState': skip_this_node: bool = False,
) -> "FleetState":
if self._this_node_ref is not None and not skip_this_node: if self._this_node_ref is not None and not skip_this_node:
this_node = self._this_node_ref() this_node = self._this_node_ref()
this_node_metadata = this_node.metadata() this_node_metadata = this_node.metadata()
@ -169,7 +176,7 @@ class FleetState:
def __len__(self): def __len__(self):
return len(self._nodes) return len(self._nodes)
def shuffled(self) -> List['Ursula']: def shuffled(self) -> List["characters.lawful.Ursula"]:
nodes_we_know_about = list(self._nodes.values()) nodes_we_know_about = list(self._nodes.values())
random.shuffle(nodes_we_know_about) random.shuffle(nodes_we_know_about)
return nodes_we_know_about return nodes_we_know_about
@ -206,8 +213,9 @@ class FleetSensor:
""" """
log = Logger("Learning") log = Logger("Learning")
def __init__(self, domain: str, this_node: Optional['Ursula'] = None): def __init__(
self, domain: str, this_node: Optional["characters.lawful.Ursula"] = None
):
self._domain = domain self._domain = domain
self._current_state = FleetState.new(this_node) self._current_state = FleetState.new(this_node)
@ -221,7 +229,7 @@ class FleetSensor:
self._auto_update_state = False self._auto_update_state = False
def record_node(self, node: 'Ursula'): def record_node(self, node: "characters.lawful.Ursula"):
if node.domain == self._domain: if node.domain == self._domain:
# Replace the existing object with a newer object, even if they're equal # Replace the existing object with a newer object, even if they're equal
@ -330,7 +338,7 @@ class FleetSensor:
def shuffled(self): def shuffled(self):
return self._current_state.shuffled() return self._current_state.shuffled()
def mark_as(self, label: Exception, node: 'Ursula'): def mark_as(self, label: Exception, node: "characters.lawful.Ursula"):
# TODO: for now we're not using `label` in any way, so we're just ignoring it # TODO: for now we're not using `label` in any way, so we're just ignoring it
self._nodes_to_remove.add(node.checksum_address) self._nodes_to_remove.add(node.checksum_address)
@ -352,8 +360,10 @@ class FleetSensor:
self._remote_last_seen[checksum_address] = maya.now() self._remote_last_seen[checksum_address] = maya.now()
self._remote_states[checksum_address] = state self._remote_states[checksum_address] = state
def status_info(self, checksum_address_or_node: Union[ChecksumAddress, 'Ursula']) -> 'RemoteUrsulaStatus': def status_info(
self,
checksum_address_or_node: Union[ChecksumAddress, "characters.lawful.Ursula"],
) -> "RemoteUrsulaStatus":
if isinstance(checksum_address_or_node, str): if isinstance(checksum_address_or_node, str):
node = self[checksum_address_or_node] node = self[checksum_address_or_node]
else: else:

View File

@ -39,7 +39,7 @@ from nucypher.blockchain.eth.registry import (
) )
from nucypher.blockchain.eth.signers import Signer from nucypher.blockchain.eth.signers import Signer
from nucypher.blockchain.eth.token import NU from nucypher.blockchain.eth.token import NU
from nucypher.blockchain.eth.trackers.dkg import ActiveRitualTracker from nucypher.blockchain.eth.trackers import dkg
from nucypher.blockchain.eth.trackers.pre import WorkTracker from nucypher.blockchain.eth.trackers.pre import WorkTracker
from nucypher.crypto.ferveo.dkg import DecryptionShareSimple, FerveoVariant, Transcript from nucypher.crypto.ferveo.dkg import DecryptionShareSimple, FerveoVariant, Transcript
from nucypher.crypto.powers import ( from nucypher.crypto.powers import (
@ -319,7 +319,7 @@ class Ritualist(BaseActor):
) )
# track active onchain rituals # track active onchain rituals
self.ritual_tracker = ActiveRitualTracker( self.ritual_tracker = dkg.ActiveRitualTracker(
ritualist=self, ritualist=self,
) )

View File

@ -15,6 +15,8 @@ from nucypher_core.ferveo import AggregatedTranscript, DkgPublicKey, Transcript
from web3.contract.contract import Contract, ContractFunction from web3.contract.contract import Contract, ContractFunction
from web3.types import Timestamp, TxParams, TxReceipt, Wei from web3.types import Timestamp, TxParams, TxReceipt, Wei
from nucypher import types
from nucypher.blockchain.eth import events
from nucypher.blockchain.eth.constants import ( from nucypher.blockchain.eth.constants import (
ADJUDICATOR_CONTRACT_NAME, ADJUDICATOR_CONTRACT_NAME,
DISPATCHER_CONTRACT_NAME, DISPATCHER_CONTRACT_NAME,
@ -25,7 +27,6 @@ from nucypher.blockchain.eth.constants import (
SUBSCRIPTION_MANAGER_CONTRACT_NAME, SUBSCRIPTION_MANAGER_CONTRACT_NAME,
) )
from nucypher.blockchain.eth.decorators import contract_api from nucypher.blockchain.eth.decorators import contract_api
from nucypher.blockchain.eth.events import ContractEvents
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
from nucypher.blockchain.eth.registry import BaseContractRegistry from nucypher.blockchain.eth.registry import BaseContractRegistry
from nucypher.config.constants import ( from nucypher.config.constants import (
@ -34,7 +35,6 @@ from nucypher.config.constants import (
) )
from nucypher.crypto.powers import TransactingPower from nucypher.crypto.powers import TransactingPower
from nucypher.crypto.utils import sha256_digest from nucypher.crypto.utils import sha256_digest
from nucypher.types import Agent, NuNits, StakingProviderInfo, TuNits
from nucypher.utilities.logging import Logger # type: ignore from nucypher.utilities.logging import Logger # type: ignore
@ -87,7 +87,7 @@ class EthereumContractAgent:
) )
self.__contract = contract self.__contract = contract
self.events = ContractEvents(contract) self.events = events.ContractEvents(contract)
if not transaction_gas: if not transaction_gas:
transaction_gas = EthereumContractAgent.DEFAULT_TRANSACTION_GAS_LIMITS['default'] transaction_gas = EthereumContractAgent.DEFAULT_TRANSACTION_GAS_LIMITS['default']
self.transaction_gas = transaction_gas self.transaction_gas = transaction_gas
@ -129,23 +129,26 @@ class NucypherTokenAgent(EthereumContractAgent):
contract_name: str = NUCYPHER_TOKEN_CONTRACT_NAME contract_name: str = NUCYPHER_TOKEN_CONTRACT_NAME
@contract_api(CONTRACT_CALL) @contract_api(CONTRACT_CALL)
def get_balance(self, address: ChecksumAddress) -> NuNits: def get_balance(self, address: ChecksumAddress) -> types.NuNits:
"""Get the NU balance (in NuNits) of a token holder address, or of this contract address""" """Get the NU balance (in NuNits) of a token holder address, or of this contract address"""
balance: int = self.contract.functions.balanceOf(address).call() balance: int = self.contract.functions.balanceOf(address).call()
return NuNits(balance) return types.NuNits(balance)
@contract_api(CONTRACT_CALL) @contract_api(CONTRACT_CALL)
def get_allowance(self, owner: ChecksumAddress, spender: ChecksumAddress) -> NuNits: def get_allowance(
self, owner: ChecksumAddress, spender: ChecksumAddress
) -> types.NuNits:
"""Check the amount of tokens that an owner allowed to a spender""" """Check the amount of tokens that an owner allowed to a spender"""
allowance: int = self.contract.functions.allowance(owner, spender).call() allowance: int = self.contract.functions.allowance(owner, spender).call()
return NuNits(allowance) return types.NuNits(allowance)
@contract_api(TRANSACTION) @contract_api(TRANSACTION)
def increase_allowance(self, def increase_allowance(
transacting_power: TransactingPower, self,
spender_address: ChecksumAddress, transacting_power: TransactingPower,
increase: NuNits spender_address: ChecksumAddress,
) -> TxReceipt: increase: types.NuNits,
) -> TxReceipt:
"""Increase the allowance of a spender address funded by a sender address""" """Increase the allowance of a spender address funded by a sender address"""
contract_function: ContractFunction = self.contract.functions.increaseAllowance(spender_address, increase) contract_function: ContractFunction = self.contract.functions.increaseAllowance(spender_address, increase)
receipt: TxReceipt = self.blockchain.send_transaction(contract_function=contract_function, receipt: TxReceipt = self.blockchain.send_transaction(contract_function=contract_function,
@ -153,11 +156,12 @@ class NucypherTokenAgent(EthereumContractAgent):
return receipt return receipt
@contract_api(TRANSACTION) @contract_api(TRANSACTION)
def decrease_allowance(self, def decrease_allowance(
transacting_power: TransactingPower, self,
spender_address: ChecksumAddress, transacting_power: TransactingPower,
decrease: NuNits spender_address: ChecksumAddress,
) -> TxReceipt: decrease: types.NuNits,
) -> TxReceipt:
"""Decrease the allowance of a spender address funded by a sender address""" """Decrease the allowance of a spender address funded by a sender address"""
contract_function: ContractFunction = self.contract.functions.decreaseAllowance(spender_address, decrease) contract_function: ContractFunction = self.contract.functions.decreaseAllowance(spender_address, decrease)
receipt: TxReceipt = self.blockchain.send_transaction(contract_function=contract_function, receipt: TxReceipt = self.blockchain.send_transaction(contract_function=contract_function,
@ -165,11 +169,12 @@ class NucypherTokenAgent(EthereumContractAgent):
return receipt return receipt
@contract_api(TRANSACTION) @contract_api(TRANSACTION)
def approve_transfer(self, def approve_transfer(
amount: NuNits, self,
spender_address: ChecksumAddress, amount: types.NuNits,
transacting_power: TransactingPower spender_address: ChecksumAddress,
) -> TxReceipt: transacting_power: TransactingPower,
) -> TxReceipt:
"""Approve the spender address to transfer an amount of tokens on behalf of the sender address""" """Approve the spender address to transfer an amount of tokens on behalf of the sender address"""
self._validate_zero_allowance(amount, spender_address, transacting_power) self._validate_zero_allowance(amount, spender_address, transacting_power)
@ -181,7 +186,12 @@ class NucypherTokenAgent(EthereumContractAgent):
return receipt return receipt
@contract_api(TRANSACTION) @contract_api(TRANSACTION)
def transfer(self, amount: NuNits, target_address: ChecksumAddress, transacting_power: TransactingPower) -> TxReceipt: def transfer(
self,
amount: types.NuNits,
target_address: ChecksumAddress,
transacting_power: TransactingPower,
) -> TxReceipt:
"""Transfer an amount of tokens from the sender address to the target address.""" """Transfer an amount of tokens from the sender address to the target address."""
contract_function: ContractFunction = self.contract.functions.transfer(target_address, amount) contract_function: ContractFunction = self.contract.functions.transfer(target_address, amount)
receipt: TxReceipt = self.blockchain.send_transaction(contract_function=contract_function, receipt: TxReceipt = self.blockchain.send_transaction(contract_function=contract_function,
@ -189,13 +199,14 @@ class NucypherTokenAgent(EthereumContractAgent):
return receipt return receipt
@contract_api(TRANSACTION) @contract_api(TRANSACTION)
def approve_and_call(self, def approve_and_call(
amount: NuNits, self,
target_address: ChecksumAddress, amount: types.NuNits,
transacting_power: TransactingPower, target_address: ChecksumAddress,
call_data: bytes = b'', transacting_power: TransactingPower,
gas_limit: Optional[Wei] = None call_data: bytes = b"",
) -> TxReceipt: gas_limit: Optional[Wei] = None,
) -> TxReceipt:
self._validate_zero_allowance(amount, target_address, transacting_power) self._validate_zero_allowance(amount, target_address, transacting_power)
payload = None payload = None
@ -402,10 +413,12 @@ class PREApplicationAgent(EthereumContractAgent):
return result return result
@contract_api(CONTRACT_CALL) @contract_api(CONTRACT_CALL)
def get_staking_provider_info(self, staking_provider: ChecksumAddress) -> StakingProviderInfo: def get_staking_provider_info(
self, staking_provider: ChecksumAddress
) -> types.StakingProviderInfo:
# remove reserved fields # remove reserved fields
info: list = self.contract.functions.stakingProviderInfo(staking_provider).call() info: list = self.contract.functions.stakingProviderInfo(staking_provider).call()
return StakingProviderInfo(*info[0:3]) return types.StakingProviderInfo(*info[0:3])
@contract_api(CONTRACT_CALL) @contract_api(CONTRACT_CALL)
def get_authorized_stake(self, staking_provider: ChecksumAddress) -> int: def get_authorized_stake(self, staking_provider: ChecksumAddress) -> int:
@ -441,8 +454,9 @@ class PREApplicationAgent(EthereumContractAgent):
yield address yield address
@contract_api(CONTRACT_CALL) @contract_api(CONTRACT_CALL)
def get_all_active_staking_providers(self, pagination_size: Optional[int] = None) -> Tuple[TuNits, Dict[ChecksumAddress, TuNits]]: def get_all_active_staking_providers(
self, pagination_size: Optional[int] = None
) -> Tuple[types.TuNits, Dict[ChecksumAddress, types.TuNits]]:
if pagination_size is None: if pagination_size is None:
pagination_size = self.DEFAULT_PROVIDERS_PAGINATION_SIZE_LIGHT_NODE if self.blockchain.is_light else self.DEFAULT_PROVIDERS_PAGINATION_SIZE pagination_size = self.DEFAULT_PROVIDERS_PAGINATION_SIZE_LIGHT_NODE if self.blockchain.is_light else self.DEFAULT_PROVIDERS_PAGINATION_SIZE
self.log.debug(f"Defaulting to pagination size {pagination_size}") self.log.debug(f"Defaulting to pagination size {pagination_size}")
@ -488,10 +502,12 @@ class PREApplicationAgent(EthereumContractAgent):
def checksum_address(address: int) -> ChecksumAddress: def checksum_address(address: int) -> ChecksumAddress:
return ChecksumAddress(to_checksum_address(address.to_bytes(ETH_ADDRESS_BYTE_LENGTH, 'big'))) return ChecksumAddress(to_checksum_address(address.to_bytes(ETH_ADDRESS_BYTE_LENGTH, 'big')))
typed_staking_providers = {checksum_address(address): TuNits(authorized_tokens) typed_staking_providers = {
for address, authorized_tokens in staking_providers.items()} checksum_address(address): types.TuNits(authorized_tokens)
for address, authorized_tokens in staking_providers.items()
}
return TuNits(n_tokens), typed_staking_providers return types.TuNits(n_tokens), typed_staking_providers
def get_staking_provider_reservoir(self, def get_staking_provider_reservoir(self,
without: Iterable[ChecksumAddress] = None, without: Iterable[ChecksumAddress] = None,
@ -760,11 +776,11 @@ class ContractAgency:
@classmethod @classmethod
def get_agent( def get_agent(
cls, cls,
agent_class: Type[Agent], agent_class: Type[types.Agent],
registry: Optional[BaseContractRegistry], registry: Optional[BaseContractRegistry],
provider_uri: Optional[str], provider_uri: Optional[str],
contract_version: Optional[str] = None, contract_version: Optional[str] = None,
) -> Agent: ) -> types.Agent:
if not issubclass(agent_class, EthereumContractAgent): if not issubclass(agent_class, EthereumContractAgent):
raise TypeError("Only agent subclasses can be used from the agency.") raise TypeError("Only agent subclasses can be used from the agency.")
@ -780,10 +796,10 @@ class ContractAgency:
registry_id = registry.id registry_id = registry.id
try: try:
return cast(Agent, cls.__agents[registry_id][agent_class]) return cast(types.Agent, cls.__agents[registry_id][agent_class])
except KeyError: except KeyError:
agent = cast( agent = cast(
Agent, types.Agent,
agent_class( agent_class(
registry=registry, registry=registry,
provider_uri=provider_uri, provider_uri=provider_uri,

View File

@ -3,6 +3,7 @@ import os
from web3.contract.contract import Contract from web3.contract.contract import Contract
from nucypher.blockchain.eth import agents
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
from nucypher.config.constants import NUCYPHER_EVENTS_THROTTLE_MAX_BLOCKS from nucypher.config.constants import NUCYPHER_EVENTS_THROTTLE_MAX_BLOCKS
@ -71,13 +72,15 @@ class ContractEventsThrottler:
# default to 1000 - smallest default heard about so far (alchemy) # default to 1000 - smallest default heard about so far (alchemy)
DEFAULT_MAX_BLOCKS_PER_CALL = int(os.environ.get(NUCYPHER_EVENTS_THROTTLE_MAX_BLOCKS, 1000)) DEFAULT_MAX_BLOCKS_PER_CALL = int(os.environ.get(NUCYPHER_EVENTS_THROTTLE_MAX_BLOCKS, 1000))
def __init__(self, def __init__(
agent: 'EthereumContractAgent', self,
event_name: str, agent: "agents.EthereumContractAgent",
from_block: int, event_name: str,
to_block: int = None, # defaults to latest block from_block: int,
max_blocks_per_call: int = DEFAULT_MAX_BLOCKS_PER_CALL, to_block: int = None, # defaults to latest block
**argument_filters): max_blocks_per_call: int = DEFAULT_MAX_BLOCKS_PER_CALL,
**argument_filters,
):
self.event_filter = agent.events[event_name] self.event_filter = agent.events[event_name]
self.from_block = from_block self.from_block = from_block
self.to_block = to_block if to_block is not None else agent.blockchain.client.block_number self.to_block = to_block if to_block is not None else agent.blockchain.client.block_number

View File

@ -6,6 +6,7 @@ from twisted.internet import threads
from web3.contract.contract import ContractEvent from web3.contract.contract import ContractEvent
from web3.datastructures import AttributeDict from web3.datastructures import AttributeDict
from nucypher.blockchain.eth.actors import Ritualist
from nucypher.policy.conditions.utils import camel_case_to_snake from nucypher.policy.conditions.utils import camel_case_to_snake
from nucypher.utilities.events import EventScanner, JSONifiedState from nucypher.utilities.events import EventScanner, JSONifiedState
from nucypher.utilities.logging import Logger from nucypher.utilities.logging import Logger
@ -66,7 +67,7 @@ class ActiveRitualTracker:
def __init__( def __init__(
self, self,
ritualist: "Ritualist", ritualist: Ritualist,
persistent: bool = False, # TODO: use persistent storage? persistent: bool = False, # TODO: use persistent storage?
): ):
self.log = Logger("RitualTracker") self.log = Logger("RitualTracker")

View File

@ -68,7 +68,7 @@ from web3.types import TxReceipt
import nucypher import nucypher
from nucypher.acumen.nicknames import Nickname from nucypher.acumen.nicknames import Nickname
from nucypher.acumen.perception import ArchivedFleetState, RemoteUrsulaStatus from nucypher.acumen.perception import ArchivedFleetState, RemoteUrsulaStatus
from nucypher.blockchain.eth.actors import Operator, PolicyAuthor, Ritualist from nucypher.blockchain.eth import actors
from nucypher.blockchain.eth.agents import ( from nucypher.blockchain.eth.agents import (
ContractAgency, ContractAgency,
CoordinatorAgent, CoordinatorAgent,
@ -100,6 +100,7 @@ from nucypher.crypto.powers import (
TLSHostingPower, TLSHostingPower,
TransactingPower, TransactingPower,
) )
from nucypher.network import trackers
from nucypher.network.decryption import ThresholdDecryptionClient from nucypher.network.decryption import ThresholdDecryptionClient
from nucypher.network.exceptions import NodeSeemsToBeDown from nucypher.network.exceptions import NodeSeemsToBeDown
from nucypher.network.middleware import RestMiddleware from nucypher.network.middleware import RestMiddleware
@ -107,7 +108,6 @@ from nucypher.network.nodes import TEACHER_NODES, NodeSprout, Teacher
from nucypher.network.protocols import parse_node_uri from nucypher.network.protocols import parse_node_uri
from nucypher.network.retrieval import PRERetrievalClient from nucypher.network.retrieval import PRERetrievalClient
from nucypher.network.server import ProxyRESTServer, make_rest_app from nucypher.network.server import ProxyRESTServer, make_rest_app
from nucypher.network.trackers import AvailabilityTracker
from nucypher.policy.conditions.types import Lingo from nucypher.policy.conditions.types import Lingo
from nucypher.policy.conditions.utils import validate_condition_lingo from nucypher.policy.conditions.utils import validate_condition_lingo
from nucypher.policy.kits import PolicyMessageKit from nucypher.policy.kits import PolicyMessageKit
@ -116,9 +116,10 @@ from nucypher.policy.policies import Policy
from nucypher.utilities.emitters import StdoutEmitter from nucypher.utilities.emitters import StdoutEmitter
from nucypher.utilities.logging import Logger from nucypher.utilities.logging import Logger
from nucypher.utilities.networking import validate_operator_ip from nucypher.utilities.networking import validate_operator_ip
from nucypher.utilities.prometheus.metrics import PrometheusMetricsConfig
class Alice(Character, PolicyAuthor): class Alice(Character, actors.PolicyAuthor):
banner = ALICE_BANNER banner = ALICE_BANNER
_default_crypto_powerups = [SigningPower, DecryptingPower, DelegatingPower] _default_crypto_powerups = [SigningPower, DecryptingPower, DelegatingPower]
@ -183,7 +184,7 @@ class Alice(Character, PolicyAuthor):
account=checksum_address, signer=signer account=checksum_address, signer=signer
) )
self._crypto_power.consume_power_up(self.transacting_power) self._crypto_power.consume_power_up(self.transacting_power)
PolicyAuthor.__init__( actors.PolicyAuthor.__init__(
self, self,
domain=self.domain, domain=self.domain,
transacting_power=self.transacting_power, transacting_power=self.transacting_power,
@ -369,7 +370,7 @@ class Alice(Character, PolicyAuthor):
def revoke( def revoke(
self, policy: Policy, onchain: bool = True, offchain: bool = True self, policy: Policy, onchain: bool = True, offchain: bool = True
) -> Tuple[TxReceipt, Dict[ChecksumAddress, Tuple["Revocation", Exception]]]: ) -> Tuple[TxReceipt, Dict[ChecksumAddress, Tuple["actors.Revocation", Exception]]]:
if not (offchain or onchain): if not (offchain or onchain):
raise ValueError("offchain or onchain must be True to issue revocation") raise ValueError("offchain or onchain must be True to issue revocation")
@ -798,7 +799,7 @@ class Bob(Character):
return cleartext return cleartext
class Ursula(Teacher, Character, Operator, Ritualist): class Ursula(Teacher, Character, actors.Operator, actors.Ritualist):
banner = URSULA_BANNER banner = URSULA_BANNER
_alice_class = Alice _alice_class = Alice
@ -864,11 +865,11 @@ class Ursula(Teacher, Character, Operator, Ritualist):
# Health Checks # Health Checks
self._availability_check = availability_check self._availability_check = availability_check
self._availability_tracker = AvailabilityTracker(ursula=self) self._availability_tracker = trackers.AvailabilityTracker(ursula=self)
try: try:
payment_method: ContractPayment payment_method: ContractPayment
Operator.__init__( actors.Operator.__init__(
self, self,
is_me=is_me, is_me=is_me,
domain=self.domain, domain=self.domain,
@ -882,7 +883,7 @@ class Ursula(Teacher, Character, Operator, Ritualist):
) )
# DKG Ritualist # DKG Ritualist
Ritualist.__init__( actors.Ritualist.__init__(
self, self,
domain=domain, domain=domain,
provider_uri=payment_method.provider, provider_uri=payment_method.provider,
@ -1010,7 +1011,7 @@ class Ursula(Teacher, Character, Operator, Ritualist):
ritualist: bool = True, ritualist: bool = True,
hendrix: bool = True, hendrix: bool = True,
start_reactor: bool = True, start_reactor: bool = True,
prometheus_config: "PrometheusMetricsConfig" = None, prometheus_config: PrometheusMetricsConfig = None,
preflight: bool = True, preflight: bool = True,
block_until_ready: bool = True, block_until_ready: bool = True,
eager: bool = False, eager: bool = False,

View File

@ -12,8 +12,9 @@ from cryptography.hazmat.backends import default_backend
from nucypher_core import FleetStateChecksum, MetadataRequest, NodeMetadata from nucypher_core import FleetStateChecksum, MetadataRequest, NodeMetadata
from requests.exceptions import SSLError from requests.exceptions import SSLError
from nucypher import characters
from nucypher.blockchain.eth.registry import BaseContractRegistry from nucypher.blockchain.eth.registry import BaseContractRegistry
from nucypher.config.storages import ForgetfulNodeStorage from nucypher.config.storages import ForgetfulNodeStorage, NodeStorage
from nucypher.network.exceptions import NodeSeemsToBeDown from nucypher.network.exceptions import NodeSeemsToBeDown
from nucypher.utilities.logging import Logger from nucypher.utilities.logging import Logger
@ -29,7 +30,7 @@ class NucypherMiddlewareClient:
self, self,
eth_provider_uri: Optional[str], eth_provider_uri: Optional[str],
registry: Optional["BaseContractRegistry"] = None, registry: Optional["BaseContractRegistry"] = None,
storage: Optional["NodeStorage"] = None, storage: Optional[NodeStorage] = None,
*args, *args,
**kwargs, **kwargs,
): ):
@ -260,7 +261,12 @@ class RestMiddleware:
) )
return response return response
def reencrypt(self, ursula: "Ursula", reencryption_request_bytes: bytes, timeout=8): def reencrypt(
self,
ursula: "characters.lawful.Ursula",
reencryption_request_bytes: bytes,
timeout=8,
):
response = self.client.post( response = self.client.post(
node_or_sprout=ursula, node_or_sprout=ursula,
path="reencrypt", path="reencrypt",
@ -270,7 +276,10 @@ class RestMiddleware:
return response return response
def get_encrypted_decryption_share( def get_encrypted_decryption_share(
self, ursula: "Ursula", decryption_request_bytes: bytes, timeout=8 self,
ursula: "characters.lawful.Ursula",
decryption_request_bytes: bytes,
timeout=8,
): ):
response = self.client.post( response = self.client.post(
node_or_sprout=ursula, node_or_sprout=ursula,

View File

@ -23,6 +23,7 @@ from requests.exceptions import SSLError
from twisted.internet import reactor, task from twisted.internet import reactor, task
from twisted.internet.defer import Deferred from twisted.internet.defer import Deferred
from nucypher import characters
from nucypher.acumen.nicknames import Nickname from nucypher.acumen.nicknames import Nickname
from nucypher.acumen.perception import FleetSensor from nucypher.acumen.perception import FleetSensor
from nucypher.blockchain.eth.agents import ContractAgency, PREApplicationAgent from nucypher.blockchain.eth.agents import ContractAgency, PREApplicationAgent
@ -150,7 +151,6 @@ class NodeSprout:
return self._metadata_payload.domain return self._metadata_payload.domain
def finish(self): def finish(self):
from nucypher.characters.lawful import Ursula
# Remote node cryptographic material # Remote node cryptographic material
crypto_power = CryptoPower() crypto_power = CryptoPower()
@ -167,16 +167,18 @@ class NodeSprout:
self._metadata_payload.certificate_der, backend=default_backend() self._metadata_payload.certificate_der, backend=default_backend()
) )
return Ursula(is_me=False, return characters.lawful.Ursula(
crypto_power=crypto_power, is_me=False,
rest_host=self._metadata_payload.host, crypto_power=crypto_power,
rest_port=self._metadata_payload.port, rest_host=self._metadata_payload.host,
checksum_address=self.checksum_address, rest_port=self._metadata_payload.port,
domain=self._metadata_payload.domain, checksum_address=self.checksum_address,
timestamp=self.timestamp, domain=self._metadata_payload.domain,
operator_signature_from_metadata=self.operator_signature_from_metadata, timestamp=self.timestamp,
certificate=tls_certificate, operator_signature_from_metadata=self.operator_signature_from_metadata,
metadata=self._metadata) certificate=tls_certificate,
metadata=self._metadata,
)
def mature(self): def mature(self):
if self._is_finishing: if self._is_finishing:
@ -293,8 +295,7 @@ class Learner:
if save_metadata and node_storage is NO_STORAGE_AVAILABLE: if save_metadata and node_storage is NO_STORAGE_AVAILABLE:
raise ValueError("Cannot save nodes without a configured node storage") raise ValueError("Cannot save nodes without a configured node storage")
from nucypher.characters.lawful import Ursula self.node_class = node_class or characters.lawful.Ursula
self.node_class = node_class or Ursula
self.node_class.set_cert_storage_function( self.node_class.set_cert_storage_function(
node_storage.store_node_certificate) # TODO: Fix this temporary workaround for on-disk cert storage. #1481 node_storage.store_node_certificate) # TODO: Fix this temporary workaround for on-disk cert storage. #1481
@ -745,13 +746,15 @@ class Learner:
def write_node_metadata(self, node, serializer=bytes) -> str: def write_node_metadata(self, node, serializer=bytes) -> str:
return self.node_storage.store_node_metadata(node=node) return self.node_storage.store_node_metadata(node=node)
def verify_from(self, def verify_from(
stranger: 'Character', self,
message: bytes, stranger: "characters.base.Character",
signature: Signature message: bytes,
): signature: Signature,
):
if not signature.verify(verifying_pk=stranger.stamp.as_umbral_pubkey(), message=message): if not signature.verify(
verifying_pk=stranger.stamp.as_umbral_pubkey(), message=message
):
try: try:
node_on_the_other_end = self.node_class.from_seednode_metadata( node_on_the_other_end = self.node_class.from_seednode_metadata(
stranger.seed_node_metadata(), stranger.seed_node_metadata(),

View File

@ -22,6 +22,7 @@ from nucypher_core.umbral import (
VerifiedCapsuleFrag, VerifiedCapsuleFrag,
) )
from nucypher.characters import lawful
from nucypher.crypto.signing import InvalidSignature from nucypher.crypto.signing import InvalidSignature
from nucypher.network.client import ThresholdAccessControlClient from nucypher.network.client import ThresholdAccessControlClient
from nucypher.network.exceptions import NodeSeemsToBeDown from nucypher.network.exceptions import NodeSeemsToBeDown
@ -182,13 +183,14 @@ class PRERetrievalClient(ThresholdAccessControlClient):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def _request_reencryption(self, def _request_reencryption(
ursula: 'Ursula', self,
reencryption_request: ReencryptionRequest, ursula: "lawful.Ursula",
alice_verifying_key: PublicKey, reencryption_request: ReencryptionRequest,
policy_encrypting_key: PublicKey, alice_verifying_key: PublicKey,
bob_encrypting_key: PublicKey, policy_encrypting_key: PublicKey,
) -> Dict['Capsule', 'VerifiedCapsuleFrag']: bob_encrypting_key: PublicKey,
) -> Dict["Capsule", "VerifiedCapsuleFrag"]:
""" """
Sends a reencryption request to a single Ursula and processes the results. Sends a reencryption request to a single Ursula and processes the results.

View File

@ -8,12 +8,13 @@ from twisted.internet import reactor
from twisted.internet.task import LoopingCall from twisted.internet.task import LoopingCall
from twisted.python.failure import Failure from twisted.python.failure import Failure
from nucypher import characters
from nucypher.blockchain.eth.agents import ContractAgency, PREApplicationAgent from nucypher.blockchain.eth.agents import ContractAgency, PREApplicationAgent
from nucypher.blockchain.eth.constants import NULL_ADDRESS from nucypher.blockchain.eth.constants import NULL_ADDRESS
from nucypher.utilities.emitters import StdoutEmitter
from nucypher.network.exceptions import NodeSeemsToBeDown from nucypher.network.exceptions import NodeSeemsToBeDown
from nucypher.network.middleware import RestMiddleware from nucypher.network.middleware import RestMiddleware
from nucypher.network.nodes import NodeSprout from nucypher.network.nodes import NodeSprout
from nucypher.utilities.emitters import StdoutEmitter
from nucypher.utilities.logging import Logger from nucypher.utilities.logging import Logger
from nucypher.utilities.task import SimpleTask from nucypher.utilities.task import SimpleTask
@ -263,7 +264,9 @@ class AvailabilityTracker:
self.log.debug(f'{ursula_or_sprout} responded to uptime check with {e.__class__.__name__}') self.log.debug(f'{ursula_or_sprout} responded to uptime check with {e.__class__.__name__}')
continue continue
def measure(self, ursula_or_sprout: Union['Ursula', NodeSprout]) -> None: def measure(
self, ursula_or_sprout: Union["characters.lawful.Ursula", NodeSprout]
) -> None:
"""Measure self-availability from a single remote node that participates uptime checks.""" """Measure self-availability from a single remote node that participates uptime checks."""
try: try:
response = self._ursula.network_middleware.check_availability(initiator=self._ursula, responder=ursula_or_sprout) response = self._ursula.network_middleware.check_availability(initiator=self._ursula, responder=ursula_or_sprout)

View File

@ -10,7 +10,7 @@ from nucypher.blockchain.eth.registry import (
BaseContractRegistry, BaseContractRegistry,
InMemoryContractRegistry, InMemoryContractRegistry,
) )
from nucypher.policy.policies import Policy from nucypher.policy import policies
class PaymentMethod(ABC): class PaymentMethod(ABC):
@ -25,7 +25,7 @@ class PaymentMethod(ABC):
shares: int shares: int
@abstractmethod @abstractmethod
def pay(self, policy: Policy) -> Dict: def pay(self, policy: "policies.Policy") -> Dict:
"""Carry out payment for the given policy.""" """Carry out payment for the given policy."""
raise NotImplementedError raise NotImplementedError
@ -101,7 +101,7 @@ class SubscriptionManagerPayment(ContractPayment):
result = self.agent.is_policy_active(policy_id=bytes(request.hrac)) result = self.agent.is_policy_active(policy_id=bytes(request.hrac))
return result return result
def pay(self, policy: Policy) -> TxReceipt: def pay(self, policy: "policies.Policy") -> TxReceipt:
"""Writes a new policy to the SubscriptionManager contract.""" """Writes a new policy to the SubscriptionManager contract."""
receipt = self.agent.create_policy( receipt = self.agent.create_policy(
value=policy.value, # wei value=policy.value, # wei
@ -176,7 +176,7 @@ class FreeReencryptions(PaymentMethod):
def verify(self, payee: ChecksumAddress, request: ReencryptionRequest) -> bool: def verify(self, payee: ChecksumAddress, request: ReencryptionRequest) -> bool:
return True return True
def pay(self, policy: Policy) -> Dict: def pay(self, policy: "policies.Policy") -> Dict:
receipt = f'Receipt for free policy {bytes(policy.hrac).hex()}.' receipt = f'Receipt for free policy {bytes(policy.hrac).hex()}.'
return dict(receipt=receipt.encode()) return dict(receipt=receipt.encode())

View File

@ -2,11 +2,13 @@ from typing import Dict, Iterable, List, Optional, Sequence
import maya import maya
from eth_typing.evm import ChecksumAddress from eth_typing.evm import ChecksumAddress
from nucypher_core import HRAC, Address, TreasureMap from nucypher_core import HRAC, Address, EncryptedTreasureMap, TreasureMap
from nucypher_core.umbral import PublicKey, VerifiedKeyFrag from nucypher_core.umbral import PublicKey, VerifiedKeyFrag
from nucypher import characters
from nucypher.crypto.powers import DecryptingPower from nucypher.crypto.powers import DecryptingPower
from nucypher.network.middleware import RestMiddleware from nucypher.network.middleware import RestMiddleware
from nucypher.policy import payment
from nucypher.policy.reservoir import PrefetchStrategy, make_staking_provider_reservoir from nucypher.policy.reservoir import PrefetchStrategy, make_staking_provider_reservoir
from nucypher.policy.revocation import RevocationKit from nucypher.policy.revocation import RevocationKit
from nucypher.utilities.concurrency import WorkerPool from nucypher.utilities.concurrency import WorkerPool
@ -29,21 +31,21 @@ class Policy:
number of available qualified network nodes. number of available qualified network nodes.
""" """
def __init__(self, def __init__(
publisher: 'Alice', self,
label: bytes, publisher: "characters.lawful.Alice",
bob: 'Bob', label: bytes,
kfrags: Sequence[VerifiedKeyFrag], bob: "characters.lawful.Bob",
public_key: PublicKey, kfrags: Sequence[VerifiedKeyFrag],
threshold: int, public_key: PublicKey,
expiration: maya.MayaDT, threshold: int,
commencement: maya.MayaDT, expiration: maya.MayaDT,
value: int, commencement: maya.MayaDT,
rate: int, value: int,
duration: int, rate: int,
payment_method: 'PaymentMethod' duration: int,
): payment_method: "payment.PaymentMethod",
):
self.threshold = threshold self.threshold = threshold
self.shares = len(kfrags) self.shares = len(kfrags)
self.label = label self.label = label
@ -75,12 +77,14 @@ class Policy:
) )
return reservoir return reservoir
def _publish(self, ursulas: List['Ursula']) -> Dict: def _publish(self, ursulas: List["characters.lawful.Ursula"]) -> Dict:
self.nodes = [ursula.checksum_address for ursula in ursulas] self.nodes = [ursula.checksum_address for ursula in ursulas]
receipt = self.payment_method.pay(policy=self) receipt = self.payment_method.pay(policy=self)
return receipt return receipt
def _ping_node(self, address: ChecksumAddress, network_middleware: RestMiddleware) -> 'Ursula': def _ping_node(
self, address: ChecksumAddress, network_middleware: RestMiddleware
) -> "characters.lawful.Ursula":
# Handles edge case when provided address is not a known peer. # Handles edge case when provided address is not a known peer.
if address not in self.publisher.known_nodes: if address not in self.publisher.known_nodes:
raise RuntimeError(f"{address} is not a known peer") raise RuntimeError(f"{address} is not a known peer")
@ -94,11 +98,12 @@ class Policy:
else: else:
raise RuntimeError(f"{ursula} is not available for selection ({status_code}).") raise RuntimeError(f"{ursula} is not available for selection ({status_code}).")
def _sample(self, def _sample(
network_middleware: RestMiddleware, self,
ursulas: Optional[Iterable['Ursula']] = None, network_middleware: RestMiddleware,
timeout: int = 10, ursulas: Optional[Iterable["characters.lawful.Ursula"]] = None,
) -> List['Ursula']: timeout: int = 10,
) -> List["characters.lawful.Ursula"]:
"""Send concurrent requests to the /ping HTTP endpoint of nodes drawn from the reservoir.""" """Send concurrent requests to the /ping HTTP endpoint of nodes drawn from the reservoir."""
ursulas = ursulas or [] ursulas = ursulas or []
@ -108,7 +113,7 @@ class Policy:
reservoir = self._make_reservoir(handpicked_addresses) reservoir = self._make_reservoir(handpicked_addresses)
value_factory = PrefetchStrategy(reservoir, self.shares) value_factory = PrefetchStrategy(reservoir, self.shares)
def worker(address) -> 'Ursula': def worker(address) -> "characters.lawful.Ursula":
return self._ping_node(address, network_middleware) return self._ping_node(address, network_middleware)
worker_pool = WorkerPool( worker_pool = WorkerPool(
@ -142,7 +147,11 @@ class Policy:
ursulas = list(successes.values()) ursulas = list(successes.values())
return ursulas return ursulas
def enact(self, network_middleware: RestMiddleware, ursulas: Optional[Iterable['Ursula']] = None) -> 'EnactedPolicy': def enact(
self,
network_middleware: RestMiddleware,
ursulas: Optional[Iterable["characters.lawful.Ursula"]] = None,
) -> "EnactedPolicy":
"""Attempts to enact the policy, returns an `EnactedPolicy` object on success.""" """Attempts to enact the policy, returns an `EnactedPolicy` object on success."""
ursulas = self._sample(network_middleware=network_middleware, ursulas=ursulas) ursulas = self._sample(network_middleware=network_middleware, ursulas=ursulas)
@ -177,16 +186,16 @@ class Policy:
class EnactedPolicy: class EnactedPolicy:
def __init__(
def __init__(self, self,
hrac: HRAC, hrac: HRAC,
label: bytes, label: bytes,
public_key: PublicKey, public_key: PublicKey,
threshold: int, threshold: int,
treasure_map: 'EncryptedTreasureMap', treasure_map: EncryptedTreasureMap,
revocation_kit: RevocationKit, revocation_kit: RevocationKit,
publisher_verifying_key: PublicKey): publisher_verifying_key: PublicKey,
):
self.hrac = hrac self.hrac = hrac
self.label = label self.label = label
self.public_key = public_key self.public_key = public_key

View File

@ -3,12 +3,16 @@ from typing import NamedTuple, NewType, TypeVar, Union
from eth_typing.evm import ChecksumAddress from eth_typing.evm import ChecksumAddress
from web3.types import TxReceipt, Wei from web3.types import TxReceipt, Wei
from nucypher.blockchain.eth import agents
ERC20UNits = NewType("ERC20UNits", int) ERC20UNits = NewType("ERC20UNits", int)
NuNits = NewType("NuNits", ERC20UNits) NuNits = NewType("NuNits", ERC20UNits)
TuNits = NewType("TuNits", ERC20UNits) TuNits = NewType("TuNits", ERC20UNits)
Agent = TypeVar('Agent', bound='EthereumContractAgent') Agent = TypeVar("Agent", bound="agents.EthereumContractAgent")
ContractReturnValue = TypeVar('ContractReturnValue', bound=Union[TxReceipt, Wei, int, str, bool]) ContractReturnValue = TypeVar(
"ContractReturnValue", bound=Union[TxReceipt, Wei, int, str, bool]
)
class StakingProviderInfo(NamedTuple): class StakingProviderInfo(NamedTuple):

View File

@ -15,7 +15,7 @@ from typing import Dict, Type
from eth_typing.evm import ChecksumAddress from eth_typing.evm import ChecksumAddress
import nucypher import nucypher
from nucypher.blockchain.eth.actors import NucypherTokenActor from nucypher.blockchain.eth import actors
from nucypher.blockchain.eth.agents import ( from nucypher.blockchain.eth.agents import (
ContractAgency, ContractAgency,
EthereumContractAgent, EthereumContractAgent,
@ -23,6 +23,7 @@ from nucypher.blockchain.eth.agents import (
) )
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
from nucypher.blockchain.eth.registry import BaseContractRegistry from nucypher.blockchain.eth.registry import BaseContractRegistry
from nucypher.characters import lawful
class MetricsCollector(ABC): class MetricsCollector(ABC):
@ -73,7 +74,8 @@ class BaseMetricsCollector(MetricsCollector):
class UrsulaInfoMetricsCollector(BaseMetricsCollector): class UrsulaInfoMetricsCollector(BaseMetricsCollector):
"""Collector for Ursula specific metrics.""" """Collector for Ursula specific metrics."""
def __init__(self, ursula: 'Ursula'):
def __init__(self, ursula: "lawful.Ursula"):
super().__init__() super().__init__()
self.ursula = ursula self.ursula = ursula
@ -210,7 +212,7 @@ class OperatorMetricsCollector(BaseMetricsCollector):
} }
def _collect_internal(self) -> None: def _collect_internal(self) -> None:
operator_token_actor = NucypherTokenActor( operator_token_actor = actors.NucypherTokenActor(
registry=self.contract_registry, registry=self.contract_registry,
domain=self.domain, domain=self.domain,
checksum_address=self.operator_address, checksum_address=self.operator_address,

View File

@ -14,6 +14,7 @@ from typing import List
from twisted.internet import reactor, task from twisted.internet import reactor, task
from twisted.web.resource import Resource from twisted.web.resource import Resource
from nucypher.characters import lawful
from nucypher.utilities.prometheus.collector import ( from nucypher.utilities.prometheus.collector import (
BlockchainMetricsCollector, BlockchainMetricsCollector,
MetricsCollector, MetricsCollector,
@ -118,9 +119,11 @@ def collect_prometheus_metrics(metrics_collectors: List[MetricsCollector]) -> No
collector.collect() collector.collect()
def start_prometheus_exporter(ursula: 'Ursula', def start_prometheus_exporter(
prometheus_config: PrometheusMetricsConfig, ursula: "lawful.Ursula",
registry: CollectorRegistry = REGISTRY) -> None: prometheus_config: PrometheusMetricsConfig,
registry: CollectorRegistry = REGISTRY,
) -> None:
"""Configure, collect, and serve prometheus metrics.""" """Configure, collect, and serve prometheus metrics."""
from prometheus_client.twisted import MetricsResource from prometheus_client.twisted import MetricsResource
from twisted.web.resource import Resource from twisted.web.resource import Resource
@ -148,7 +151,7 @@ def start_prometheus_exporter(ursula: 'Ursula',
reactor.listenTCP(prometheus_config.port, factory, interface=prometheus_config.listen_address) reactor.listenTCP(prometheus_config.port, factory, interface=prometheus_config.listen_address)
def create_metrics_collectors(ursula: "Ursula") -> List[MetricsCollector]: def create_metrics_collectors(ursula: "lawful.Ursula") -> List[MetricsCollector]:
"""Create collectors used to obtain metrics.""" """Create collectors used to obtain metrics."""
collectors: List[MetricsCollector] = [UrsulaInfoMetricsCollector(ursula=ursula)] collectors: List[MetricsCollector] = [UrsulaInfoMetricsCollector(ursula=ursula)]

View File

@ -5,9 +5,10 @@ from unittest.mock import Mock
from constant_sorrow.constants import CONTRACT_ATTRIBUTE, CONTRACT_CALL, TRANSACTION from constant_sorrow.constants import CONTRACT_ATTRIBUTE, CONTRACT_CALL, TRANSACTION
from nucypher.blockchain.eth import agents from nucypher.blockchain.eth import agents
from nucypher.blockchain.eth.agents import Agent, ContractAgency, EthereumContractAgent from nucypher.blockchain.eth.agents import ContractAgency, EthereumContractAgent
from nucypher.blockchain.eth.constants import NULL_ADDRESS from nucypher.blockchain.eth.constants import NULL_ADDRESS
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
from nucypher.types import Agent
from tests.constants import MOCK_ETH_PROVIDER_URI from tests.constants import MOCK_ETH_PROVIDER_URI
from tests.mock.interfaces import MockBlockchain from tests.mock.interfaces import MockBlockchain