Esempio n. 1
0
 def create_bidder(self, registry, hw_wallet: bool = False):
     signer = Signer.from_signer_uri(
         self.signer_uri) if self.signer_uri else None
     return self.__create_bidder(registry=registry,
                                 signer=signer,
                                 hw_wallet=hw_wallet,
                                 transacting=True)
def test_signer_reads_keystore_from_disk(mock_account, mock_key,
                                         temp_dir_path):

    # Test reading a keyfile from the disk via KeystoreSigner since
    # it is mocked for the rest of this test module
    fake_ethereum = temp_dir_path / '.fake-ethereum'
    try:
        fake_ethereum.mkdir()

        tmp_keystore = temp_dir_path / '.fake-ethereum' / 'keystore'
        tmp_keystore.mkdir()

        mock_keyfile_path = tmp_keystore / MOCK_KEYFILE_NAME
        mock_keyfile_path.touch(exist_ok=True)

        with open(mock_keyfile_path, 'w') as fake_keyfile:
            fake_keyfile.write(json.dumps(MOCK_KEYFILE))

        mock_keystore_uri = f'keystore://{tmp_keystore}'
        signer = Signer.from_signer_uri(uri=mock_keystore_uri, testnet=True)

        assert signer.path == tmp_keystore
        assert len(signer.accounts) == 1
        assert MOCK_KEYFILE['address'] in signer.accounts

    finally:
        if fake_ethereum.exists():
            shutil.rmtree(fake_ethereum, ignore_errors=True)
Esempio n. 3
0
    def __create_bidder(self,
                        registry,
                        domain: str,
                        transacting: bool = True,
                        hw_wallet: bool = False,
                        ) -> Bidder:

        is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri)
        testnet = self.network != NetworksInventory.MAINNET
        signer = Signer.from_signer_uri(self.signer_uri, testnet=testnet) if self.signer_uri else None
        password_required = (not is_clef and not hw_wallet)
        if signer and transacting and password_required:
            client_password = get_client_password(checksum_address=self.bidder_address)
            signer.unlock_account(account=self.bidder_address, password=client_password)

        transacting_power = None
        if transacting:
            transacting_power = TransactingPower(account=self.bidder_address, signer=signer)
            transacting_power.unlock(password=client_password)

        bidder = Bidder(registry=registry,
                        transacting_power=transacting_power,
                        checksum_address=self.bidder_address if not transacting_power else None,
                        domain=domain)
        return bidder
def test_create_signer_from_keystore_file(mock_account, mock_keystore):
    mock_keystore_path = mock_keystore / MOCK_KEYFILE_NAME
    mock_keystore_uri = f'keystore:{mock_keystore_path}'

    # Return a "real" account address from the keyfile
    signer = Signer.from_signer_uri(uri=mock_keystore_uri, testnet=True)  # type: KeystoreSigner
    assert signer.path == str(mock_keystore_path)
    assert len(signer.accounts) == 1
    assert mock_account.address in signer.accounts
def test_create_signer_from_keystore_directory(mock_account, mock_keystore):
    mock_keystore_path = mock_keystore
    mock_keystore_uri = f'keystore:{mock_keystore_path}'

    # Return a "real" account address from the keyfile
    signer = Signer.from_signer_uri(uri=mock_keystore_uri,
                                    testnet=True)  # type: KeystoreSigner
    assert signer.path == mock_keystore_path
    assert len(signer.accounts) == 1
    assert mock_account.address in signer.accounts
def good_signer(mock_account, mock_keystore):

    # Return a "real" account address from the keyfile
    mock_keystore_uri = f'keystore:{mock_keystore}'
    signer = Signer.from_signer_uri(uri=mock_keystore_uri)  # type: KeystoreSigner

    # unlock
    signer.unlock_account(account=mock_account.address, password=INSECURE_DEVELOPMENT_PASSWORD)

    return signer
Esempio n. 7
0
def unbond(registry_filepath, eth_provider_uri, signer_uri, staking_provider,
           network, force):
    """Unbonds an operator from an authorized staking provider."""

    #
    # Setup
    #

    emitter = StdoutEmitter()
    if not signer_uri:
        emitter.message('--signer is required', color='red')
        raise click.Abort()
    if not network:
        network = select_network(emitter=emitter,
                                 network_type=NetworksInventory.ETH)

    connect_to_blockchain(eth_provider_uri=eth_provider_uri, emitter=emitter)
    registry = get_registry(network=network,
                            registry_filepath=registry_filepath)
    agent = ContractAgency.get_agent(PREApplicationAgent, registry=registry)
    signer = Signer.from_signer_uri(signer_uri)
    transacting_power = TransactingPower(account=staking_provider,
                                         signer=signer)

    #
    # Check
    #

    bonded, onchain_operator_address = is_bonded(
        agent=agent, staking_provider=staking_provider, return_address=True)
    if not bonded:
        emitter.message(NOT_BONDED.format(provider=staking_provider),
                        color='red')
        raise click.Abort()
    check_bonding_requirements(emitter=emitter,
                               agent=agent,
                               staking_provider=staking_provider)

    #
    # Unbond
    #

    if not force:
        click.confirm(CONFIRM_UNBONDING.format(
            provider=staking_provider, operator=onchain_operator_address),
                      abort=True)
    transacting_power.unlock(password=get_client_password(
        checksum_address=staking_provider,
        envvar=NUCYPHER_ENVVAR_STAKING_PROVIDER_ETH_PASSWORD))
    emitter.echo(UNBONDING.format(operator=onchain_operator_address))
    receipt = agent.bond_operator(operator=NULL_ADDRESS,
                                  transacting_power=transacting_power,
                                  staking_provider=staking_provider)
    paint_receipt_summary(receipt=receipt, emitter=emitter)
Esempio n. 8
0
    def dynamic_payload(self) -> dict:
        """Exported dynamic configuration values for initializing Ursula"""
        payload = dict()
        if not self.federated_only:
            payload.update(dict(registry=self.registry, signer=Signer.from_signer_uri(self.signer_uri)))

        payload.update(dict(network_middleware=self.network_middleware or self.DEFAULT_NETWORK_MIDDLEWARE(),
                            known_nodes=self.known_nodes,
                            node_storage=self.node_storage,
                            crypto_power_ups=self.derive_node_power_ups()))
        return payload
Esempio n. 9
0
def test_create_signer(mocker, mock_listdir, mock_account, mock_key):

    # Return a "real" account address from the keyfile
    mock_keyfile_reader = mocker.patch.object(KeystoreSigner,
                                              '_KeystoreSigner__read_keyfile',
                                              autospec=True)
    mock_keyfile_reader.return_value = mock_account.address, dict(
        address=mock_account.address)

    signer = Signer.from_signer_uri(
        uri=MOCK_KEYSTORE_URI)  # type: KeystoreSigner
    assert signer.path == MOCK_KEYSTORE_PATH
    assert len(signer.accounts) == 1
    assert mock_account.address in signer.accounts
Esempio n. 10
0
def test_invalid_keystore(mocker, mock_listdir):

    # mock Keystoresigner.__read_keyfile
    # Invalid keystore values and exception handling
    mock_keyfile_reader = mocker.patch.object(KeystoreSigner,
                                              '_KeystoreSigner__read_keyfile',
                                              autospec=True)
    mock_keyfile_reader.return_value = '0xdeadbeef', dict()

    #
    # 1 - Create
    #

    with pytest.raises(KeystoreSigner.InvalidKeyfile) as e:
        Signer.from_signer_uri(uri=MOCK_KEYSTORE_URI)
    assert "does not contain a valid ethereum address" in str(e.value)

    # Invalid keyfiles
    for exception in (FileNotFoundError, KeyError):
        with pytest.raises(KeystoreSigner.InvalidKeyfile):
            mock_keyfile_reader.side_effect = exception
            Signer.from_signer_uri(uri=MOCK_KEYSTORE_URI)
    mock_keyfile_reader.side_effect = None  # clean up this mess
Esempio n. 11
0
    def __create_bidder(self,
                        registry,
                        transacting: bool = True,
                        hw_wallet: bool = False) -> Bidder:

        client_password = None
        is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri)
        if transacting and not is_clef and not hw_wallet:
            client_password = get_client_password(checksum_address=self.bidder_address)
        signer = Signer.from_signer_uri(self.signer_uri) if self.signer_uri else None
        bidder = Bidder(checksum_address=self.bidder_address,
                        registry=registry,
                        client_password=client_password,
                        signer=signer,
                        transacting=transacting)
        return bidder
Esempio n. 12
0
def good_signer(mocker, mock_account, mock_key):
    # Return a "real" account address from the keyfile
    mock_keyfile_reader = mocker.patch.object(KeystoreSigner,
                                              '_KeystoreSigner__read_keyfile',
                                              autospec=True)
    mock_keyfile_reader.return_value = mock_account.address, dict(
        address=mock_account.address)

    signer = Signer.from_signer_uri(
        uri=MOCK_KEYSTORE_URI)  # type: KeystoreSigner

    # unlock
    mock_decrypt = mocker.patch.object(Account, 'decrypt', autospec=True)
    mock_decrypt.return_value = mock_key.privateKey
    signer.unlock_account(account=mock_account.address,
                          password=INSECURE_DEVELOPMENT_PASSWORD)

    return signer
def test_invalid_keystore(tmp_path):
    with pytest.raises(Signer.InvalidSignerURI) as e:
        Signer.from_signer_uri(uri=f'keystore:{tmp_path/"nonexistent"}', testnet=True)

    empty_path = tmp_path / 'empty_file'
    open(empty_path, 'x+t').close()
    with pytest.raises(KeystoreSigner.InvalidKeyfile, match=
        'Invalid JSON in keyfile at') as e:
        Signer.from_signer_uri(uri=f'keystore:{empty_path}', testnet=True)

    empty_json = tmp_path / 'empty_json'
    json.dump({}, open(empty_json, 'x+t'))
    with pytest.raises(KeystoreSigner.InvalidKeyfile, match=
        'Keyfile does not contain address field at') as e:
        Signer.from_signer_uri(uri=f'keystore:{empty_json}', testnet=True)

    bad_address = tmp_path / 'bad_address'
    json.dump({'address':''}, open(bad_address, 'x+t'))
    with pytest.raises(KeystoreSigner.InvalidKeyfile, match=
        'does not contain a valid ethereum address') as e:
        Signer.from_signer_uri(uri=f'keystore:{bad_address}', testnet=True)
Esempio n. 14
0
 def dynamic_payload(self) -> dict:
     payload = dict(registry=self.registry,
                    signer=Signer.from_signer_uri(self.signer_uri))
     return payload
Esempio n. 15
0
 def dynamic_payload(self) -> dict:
     testnet = self.domain != NetworksInventory.MAINNET
     signer = Signer.from_signer_uri(self.signer_uri, testnet=testnet)
     payload = dict(registry=self.registry, signer=signer)
     return payload
Esempio n. 16
0
def test_blank_keystore_uri():
    with pytest.raises(Signer.InvalidSignerURI) as error:
        Signer.from_signer_uri(uri='keystore://')  # it's blank!
    assert 'Blank signer URI - No keystore path provided' in str(error)
Esempio n. 17
0
    def create_actor(self, emitter, is_multisig: bool = False):

        _ensure_config_root(self.config_root)
        deployer_interface = _initialize_blockchain(
            poa=self.poa,
            provider_uri=self.provider_uri,
            emitter=emitter,
            ignore_solidity_check=self.ignore_solidity_check,
            gas_strategy=self.gas_strategy)

        # Warnings
        _pre_launch_warnings(emitter, self.etherscan, self.hw_wallet)

        #
        # Establish Registry
        #
        local_registry = establish_deployer_registry(
            emitter=emitter,
            use_existing_registry=bool(self.contract_name),
            registry_infile=self.registry_infile,
            registry_outfile=self.registry_outfile,
            dev=self.dev)
        #
        # Make Authenticated Deployment Actor
        #
        # Verify Address & collect password
        password = None
        if is_multisig:
            multisig_agent = ContractAgency.get_agent(MultiSigAgent,
                                                      registry=local_registry)
            deployer_address = multisig_agent.contract.address
            is_transacting = False
        else:
            is_transacting = True
            deployer_address = self.deployer_address
            if not deployer_address:
                prompt = "Select deployer account"
                deployer_address = select_client_account(
                    emitter=emitter,
                    prompt=prompt,
                    provider_uri=self.provider_uri,
                    signer_uri=self.signer_uri,
                    show_eth_balance=True)

            if not self.force:
                click.confirm(
                    "Selected {} - Continue?".format(deployer_address),
                    abort=True)

            if not self.hw_wallet and not deployer_interface.client.is_local:
                password = get_client_password(
                    checksum_address=deployer_address)
        # Produce Actor
        signer = Signer.from_signer_uri(
            self.signer_uri) if self.signer_uri else None
        ADMINISTRATOR = ContractAdministrator(
            registry=local_registry,
            client_password=password,
            deployer_address=deployer_address,
            is_transacting=is_transacting,
            signer=signer,
            staking_escrow_test_mode=self.se_test_mode)
        # Verify ETH Balance
        emitter.echo(f"\n\nDeployer ETH balance: {ADMINISTRATOR.eth_balance}")
        if is_transacting and ADMINISTRATOR.eth_balance == 0:
            emitter.echo("Deployer address has no ETH.",
                         color='red',
                         bold=True)
            raise click.Abort()
        return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
Esempio n. 18
0
def select_client_account(emitter,
                          provider_uri: str = None,
                          signer_uri: str = None,
                          wallet: Wallet = None,
                          prompt: str = None,
                          default: int = 0,
                          registry=None,
                          show_eth_balance: bool = False,
                          show_nu_balance: bool = False,
                          show_staking: bool = False,
                          network: str = None,
                          poa: bool = None) -> str:
    """
    Note: Showing ETH and/or NU balances, causes an eager blockchain connection.
    """

    # We use Wallet internally as an account management abstraction
    if not wallet:
        if not provider_uri and not signer_uri:
            raise ValueError(
                "At least a provider URI or signer URI is necessary to select an account"
            )
        # Lazy connect the blockchain interface
        if not BlockchainInterfaceFactory.is_interface_initialized(
                provider_uri=provider_uri):
            BlockchainInterfaceFactory.initialize_interface(
                provider_uri=provider_uri, poa=poa, emitter=emitter)
        signer = Signer.from_signer_uri(signer_uri) if signer_uri else None
        wallet = Wallet(provider_uri=provider_uri, signer=signer)
    elif provider_uri or signer_uri:
        raise ValueError(
            "If you input a wallet, don't pass a provider URI or signer URI too"
        )

    # Display accounts info
    if show_nu_balance or show_staking:  # Lazy registry fetching
        if not registry:
            registry = InMemoryContractRegistry.from_latest_publication(
                network=network)

    wallet_accounts = wallet.accounts
    enumerated_accounts = dict(enumerate(wallet_accounts))
    if len(enumerated_accounts) < 1:
        emitter.echo("No ETH accounts were found.", color='red', bold=True)
        raise click.Abort()

    # Display account info
    headers = ['Account']
    if show_staking:
        headers.append('Staking')
    if show_eth_balance:
        headers.append('ETH')
    if show_nu_balance:
        headers.append('NU')

    rows = list()
    for index, account in enumerated_accounts.items():
        row = [account]
        if show_staking:
            staker = Staker(is_me=True,
                            checksum_address=account,
                            registry=registry)
            staker.stakes.refresh()
            is_staking = 'Yes' if bool(staker.stakes) else 'No'
            row.append(is_staking)
        if show_eth_balance:
            ether_balance = Web3.fromWei(wallet.eth_balance(account), 'ether')
            row.append(f'{ether_balance} ETH')
        if show_nu_balance:
            token_balance = NU.from_nunits(
                wallet.token_balance(account, registry))
            row.append(token_balance)
        rows.append(row)
    emitter.echo(tabulate(rows, headers=headers, showindex='always'))

    # Prompt the user for selection, and return
    prompt = prompt or "Select index of account"
    account_range = click.IntRange(min=0, max=len(enumerated_accounts) - 1)
    choice = click.prompt(prompt, type=account_range, default=default)
    chosen_account = enumerated_accounts[choice]

    emitter.echo(f"Selected {choice}: {chosen_account}", color='blue')
    return chosen_account
Esempio n. 19
0
    def create_actor(
        self,
        emitter: StdoutEmitter,
        is_multisig: bool = False
    ) -> Tuple[ContractAdministrator, str, BlockchainInterface,
               BaseContractRegistry]:

        ensure_config_root(self.config_root)
        deployer_interface = initialize_deployer_interface(
            poa=self.poa,
            provider_uri=self.provider_uri,
            emitter=emitter,
            ignore_solidity_check=self.ignore_solidity_check,
            gas_strategy=self.gas_strategy)

        # Warnings
        deployer_pre_launch_warnings(emitter, self.etherscan, self.hw_wallet)

        #
        # Establish Registry
        #
        local_registry = establish_deployer_registry(
            emitter=emitter,
            use_existing_registry=bool(self.contract_name),
            registry_infile=self.registry_infile,
            registry_outfile=self.registry_outfile,
            dev=self.dev)
        #
        # Make Authenticated Deployment Actor
        #
        # Verify Address & collect password
        password = None
        if is_multisig:
            multisig_agent = ContractAgency.get_agent(MultiSigAgent,
                                                      registry=local_registry)
            deployer_address = multisig_agent.contract.address
            is_transacting = False
        else:
            is_transacting = True
            deployer_address = self.deployer_address
            if not deployer_address:
                deployer_address = select_client_account(
                    emitter=emitter,
                    prompt=SELECT_DEPLOYER_ACCOUNT,
                    provider_uri=self.provider_uri,
                    signer_uri=self.signer_uri,
                    show_eth_balance=True)

            if not self.force:
                click.confirm(
                    CONFIRM_SELECTED_ACCOUNT.format(address=deployer_address),
                    abort=True)

            is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri)
            eth_password_is_needed = not self.hw_wallet and not deployer_interface.client.is_local and not is_clef
            if eth_password_is_needed:
                password = get_client_password(
                    checksum_address=deployer_address)
        # Produce Actor
        signer = Signer.from_signer_uri(
            self.signer_uri) if self.signer_uri else None
        ADMINISTRATOR = ContractAdministrator(
            registry=local_registry,
            client_password=password,
            deployer_address=deployer_address,
            is_transacting=is_transacting,
            signer=signer,
            staking_escrow_test_mode=self.se_test_mode)
        # Verify ETH Balance
        emitter.echo(
            DEPLOYER_BALANCE.format(eth_balance=ADMINISTRATOR.eth_balance))
        if is_transacting and ADMINISTRATOR.eth_balance == 0:
            emitter.echo(DEPLOYER_ADDRESS_ZERO_ETH, color='red', bold=True)
            raise click.Abort()
        return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
Esempio n. 20
0
L1_NETWORK = 'mainnet'  # 'ibex'
L2_NETWORK = 'polygon'  # 'mumbai'

#######################################
# Alicia, the Authority of the Policy #
#######################################

connect_web3_provider(
    eth_provider_uri=L1_PROVIDER)  # Connect to the ethereum provider.
connect_web3_provider(
    eth_provider_uri=L2_PROVIDER)  # Connect to the layer 2 provider.

# Setup and unlock alice's ethereum wallet.
# WARNING: Never give your mainnet password or mnemonic phrase to anyone.
# Do not use mainnet keys, create a dedicated software wallet to use for this demo.
wallet = Signer.from_signer_uri(SIGNER_URI)
password = os.environ.get('DEMO_ALICE_PASSWORD') or getpass(
    f"Enter password to unlock Alice's wallet ({ALICE_ADDRESS[:8]}): ")
wallet.unlock_account(account=ALICE_ADDRESS, password=password)

# This is Alice's payment method.
payment_method = SubscriptionManagerPayment(network=L2_NETWORK,
                                            eth_provider=L2_PROVIDER)

# This is Alicia.
alicia = Alice(checksum_address=ALICE_ADDRESS,
               signer=wallet,
               domain=L1_NETWORK,
               eth_provider_uri=L1_PROVIDER,
               payment_method=payment_method)
Esempio n. 21
0
def select_client_account(emitter,
                          provider_uri: str = None,
                          signer: Signer = None,
                          signer_uri: str = None,
                          wallet: Wallet = None,
                          prompt: str = None,
                          default: int = 0,
                          registry=None,
                          show_eth_balance: bool = False,
                          show_nu_balance: bool = False,
                          show_staking: bool = False,
                          network: str = None,
                          poa: bool = None
                          ) -> str:
    """
    Interactively select an ethereum wallet account from a table of nucypher account metadata.

    Note: Showing ETH and/or NU balances, causes an eager blockchain connection.
    """

    if wallet and (provider_uri or signer_uri or signer):
        raise ValueError("If a wallet is provided, don't provide a signer, provider URI, or signer URI.")

    # We use Wallet internally as an account management abstraction
    if not wallet:

        if signer and signer_uri:
            raise ValueError('Pass either signer or signer_uri but not both.')

        if not provider_uri and not signer_uri:
            raise ValueError("At least a provider URI or signer URI is necessary to select an account")

        if provider_uri:
            # Lazy connect the blockchain interface
            if not BlockchainInterfaceFactory.is_interface_initialized(provider_uri=provider_uri):
                BlockchainInterfaceFactory.initialize_interface(provider_uri=provider_uri, poa=poa, emitter=emitter)

        if signer_uri:
            signer = Signer.from_signer_uri(signer_uri)

        wallet = Wallet(provider_uri=provider_uri, signer=signer)

    # Display accounts info
    if show_nu_balance or show_staking:  # Lazy registry fetching
        if not registry:
            if not network:
                raise ValueError("Pass network name or registry; Got neither.")
            registry = InMemoryContractRegistry.from_latest_publication(network=network)

    wallet_accounts = wallet.accounts
    enumerated_accounts = dict(enumerate(wallet_accounts))
    if len(enumerated_accounts) < 1:
        emitter.echo(NO_ETH_ACCOUNTS, color='red', bold=True)
        raise click.Abort()

    # Display account info
    headers = ['Account']
    if show_staking:
        headers.append('Staking')
    if show_eth_balance:
        headers.append('ETH')
    if show_nu_balance:
        headers.append('NU')

    rows = list()
    for index, account in enumerated_accounts.items():
        row = [account]
        if show_staking:
            staker = Staker(is_me=True, checksum_address=account, registry=registry)
            staker.stakes.refresh()
            is_staking = 'Yes' if bool(staker.stakes) else 'No'
            row.append(is_staking)
        if show_eth_balance:
            ether_balance = Web3.fromWei(wallet.eth_balance(account), 'ether')
            row.append(f'{ether_balance} ETH')
        if show_nu_balance:
            token_balance = NU.from_nunits(wallet.token_balance(account, registry))
            row.append(token_balance)
        rows.append(row)
    emitter.echo(tabulate(rows, headers=headers, showindex='always'))

    # Prompt the user for selection, and return
    prompt = prompt or GENERIC_SELECT_ACCOUNT
    account_range = click.IntRange(min=0, max=len(enumerated_accounts)-1)
    choice = click.prompt(prompt, type=account_range, default=default)
    chosen_account = enumerated_accounts[choice]

    emitter.echo(SELECTED_ACCOUNT.format(choice=choice, chosen_account=chosen_account), color='blue')
    return chosen_account
Esempio n. 22
0
def test_trezor_signer_creation_from_uri(mock_trezor, simple_trezor_uri):
    signer = Signer.from_signer_uri(uri=simple_trezor_uri, testnet=False)
    assert isinstance(signer, TrezorSigner)
    assert len(signer.accounts) == 1
    del signer
Esempio n. 23
0
def test_blank_keystore_uri():
    with pytest.raises(
            Signer.InvalidSignerURI,
            match='Blank signer URI - No keystore path provided') as error:
        Signer.from_signer_uri(uri='keystore://', testnet=True)  # it's blank!
Esempio n. 24
0
    def __init__(
            self,

            # Base
            emitter=None,
            config_root: Optional[Path] = None,
            filepath: Optional[Path] = None,

            # Mode
            dev_mode: bool = False,
            federated_only: bool = False,

            # Identity
            checksum_address: str = None,
            crypto_power: CryptoPower = None,

            # Keystore
            keystore: Keystore = None,
            keystore_path: Optional[Path] = None,

            # Learner
            learn_on_same_thread: bool = False,
            abort_on_learning_error: bool = False,
            start_learning_now: bool = True,

            # Network
            controller_port: int = None,
            domain: str = DEFAULT_DOMAIN,
            network_middleware: RestMiddleware = None,
            lonely: bool = False,

            # Node Storage
            known_nodes: set = None,
            node_storage: NodeStorage = None,
            reload_metadata: bool = True,
            save_metadata: bool = True,

            # Blockchain
            poa: bool = None,
            light: bool = False,
            provider_uri: str = None,
            gas_strategy: Union[Callable, str] = DEFAULT_GAS_STRATEGY,
            max_gas_price: Optional[int] = None,
            signer_uri: str = None,

            # Registry
            registry: BaseContractRegistry = None,
            registry_filepath: Optional[Path] = None,

            # Deployed Workers
            worker_data: dict = None):

        self.log = Logger(self.__class__.__name__)

        # This constant is used to signal that a path can be generated if one is not provided.
        UNINITIALIZED_CONFIGURATION.bool_value(False)

        # Identity
        # NOTE: NodeConfigurations can only be used with Self-Characters
        self.is_me = True
        self.checksum_address = checksum_address

        # Keystore
        self.crypto_power = crypto_power
        if keystore_path and not keystore:
            keystore = Keystore(keystore_path=keystore_path)
        self.__keystore = self.__keystore = keystore or NO_KEYSTORE_ATTACHED.bool_value(
            False)
        self.keystore_dir = Path(
            keystore.keystore_path
        ).parent if keystore else UNINITIALIZED_CONFIGURATION

        # Contract Registry
        if registry and registry_filepath:
            if registry.filepath != registry_filepath:
                error = f"Inconsistent registry filepaths for '{registry.filepath.absolute()}'" \
                        f" and '{registry_filepath.absolute()}'."
                raise ValueError(error)
            else:
                self.log.warn(
                    f"Registry and registry filepath were both passed.")
        self.registry = registry or NO_BLOCKCHAIN_CONNECTION.bool_value(False)
        self.registry_filepath = registry_filepath or UNINITIALIZED_CONFIGURATION

        # Blockchain
        self.poa = poa
        self.is_light = light
        self.provider_uri = provider_uri or NO_BLOCKCHAIN_CONNECTION
        self.signer_uri = signer_uri or None

        # Learner
        self.federated_only = federated_only
        self.domain = domain
        self.learn_on_same_thread = learn_on_same_thread
        self.abort_on_learning_error = abort_on_learning_error
        self.start_learning_now = start_learning_now
        self.save_metadata = save_metadata
        self.reload_metadata = reload_metadata
        self.known_nodes = known_nodes or set()  # handpicked
        self.lonely = lonely

        # Configuration
        self.__dev_mode = dev_mode
        self.config_file_location = filepath or UNINITIALIZED_CONFIGURATION
        self.config_root = UNINITIALIZED_CONFIGURATION

        # Deployed Workers
        self.worker_data = worker_data

        #
        # Federated vs. Blockchain arguments consistency
        #

        #
        # Federated
        #

        if self.federated_only:
            # Check for incompatible values
            blockchain_args = {
                'filepath': registry_filepath,
                'poa': poa,
                'provider_uri': provider_uri,
                'gas_strategy': gas_strategy,
                'max_gas_price': max_gas_price
            }
            if any(blockchain_args.values()):
                bad_args = ", ".join(f"{arg}={val}"
                                     for arg, val in blockchain_args.items()
                                     if val)
                self.log.warn(
                    f"Arguments {bad_args} are incompatible with federated_only. "
                    f"Overridden with a sane default.")

                # Clear decentralized attributes to ensure consistency with a
                # federated configuration.
                self.poa = False
                self.is_light = False
                self.provider_uri = None
                self.registry_filepath = None
                self.gas_strategy = None
                self.max_gas_price = None

        #
        # Decentralized
        #

        else:
            self.gas_strategy = gas_strategy
            self.max_gas_price = max_gas_price  # gwei
            is_initialized = BlockchainInterfaceFactory.is_interface_initialized(
                provider_uri=self.provider_uri)
            if not is_initialized and provider_uri:
                BlockchainInterfaceFactory.initialize_interface(
                    provider_uri=self.provider_uri,
                    poa=self.poa,
                    light=self.is_light,
                    emitter=emitter,
                    gas_strategy=self.gas_strategy,
                    max_gas_price=self.max_gas_price)
            else:
                self.log.warn(
                    f"Using existing blockchain interface connection ({self.provider_uri})."
                )

            if not self.registry:
                # TODO: These two code blocks are untested.
                if not self.registry_filepath:  # TODO: Registry URI  (goerli://speedynet.json) :-)
                    self.log.info(f"Fetching latest registry from source.")
                    self.registry = InMemoryContractRegistry.from_latest_publication(
                        network=self.domain)
                else:
                    self.registry = LocalContractRegistry(
                        filepath=self.registry_filepath)
                    self.log.info(f"Using local registry ({self.registry}).")

            self.testnet = self.domain != NetworksInventory.MAINNET
            self.signer = Signer.from_signer_uri(self.signer_uri,
                                                 testnet=self.testnet)

        if dev_mode:
            self.__temp_dir = UNINITIALIZED_CONFIGURATION
            self._setup_node_storage()
            self.initialize(password=DEVELOPMENT_CONFIGURATION)
        else:
            self.__temp_dir = LIVE_CONFIGURATION
            self.config_root = config_root or self.DEFAULT_CONFIG_ROOT
            self._cache_runtime_filepaths()
            self._setup_node_storage(node_storage=node_storage)

        # Network
        self.controller_port = controller_port or self.DEFAULT_CONTROLLER_PORT
        self.network_middleware = network_middleware or self.DEFAULT_NETWORK_MIDDLEWARE(
            registry=self.registry)

        super().__init__(filepath=self.config_file_location,
                         config_root=self.config_root)
Esempio n. 25
0
def bond(registry_filepath, eth_provider_uri, signer_uri, operator_address,
         staking_provider, network, force):
    """
    Bond an operator to a staking provider.
    The staking provider must be authorized to use the PREApplication.
    """

    #
    # Setup
    #

    emitter = StdoutEmitter()
    connect_to_blockchain(eth_provider_uri=eth_provider_uri, emitter=emitter)
    if not signer_uri:
        emitter.message('--signer is required', color='red')
        raise click.Abort()
    if not network:
        network = select_network(emitter=emitter)

    signer = Signer.from_signer_uri(signer_uri)
    transacting_power = TransactingPower(account=staking_provider,
                                         signer=signer)
    registry = get_registry(network=network,
                            registry_filepath=registry_filepath)
    agent = ContractAgency.get_agent(PREApplicationAgent, registry=registry)

    #
    # Checks
    #

    # Check for authorization
    is_authorized(emitter=emitter,
                  agent=agent,
                  staking_provider=staking_provider)

    # Check bonding
    if is_bonded(agent=agent,
                 staking_provider=staking_provider,
                 return_address=False):
        # operator is already set - check timing
        check_bonding_requirements(emitter=emitter,
                                   agent=agent,
                                   staking_provider=staking_provider)

    # Check for pre-existing staking providers for this operator
    onchain_staking_provider = agent.get_staking_provider_from_operator(
        operator_address=operator_address)
    if onchain_staking_provider != NULL_ADDRESS:
        emitter.message(ALREADY_BONDED.format(
            provider=onchain_staking_provider, operator=operator_address),
                        color='red')
        raise click.Abort()  # dont steal bananas

    # Check that operator is not human
    if staking_provider != operator_address:
        # if the operator has a beneficiary it is the staking provider.
        beneficiary = agent.get_beneficiary(staking_provider=operator_address)
        if beneficiary != NULL_ADDRESS:
            emitter.message(UNEXPECTED_HUMAN_OPERATOR, color='red')
            raise click.Abort()

    #
    # Bond
    #

    if not force:
        click.confirm(CONFIRM_BONDING.format(provider=staking_provider,
                                             operator=operator_address),
                      abort=True)
    transacting_power.unlock(password=get_client_password(
        checksum_address=staking_provider,
        envvar=NUCYPHER_ENVVAR_STAKING_PROVIDER_ETH_PASSWORD))
    emitter.echo(BONDING.format(operator=operator_address))
    receipt = agent.bond_operator(operator=operator_address,
                                  transacting_power=transacting_power,
                                  staking_provider=staking_provider)
    paint_receipt_summary(receipt=receipt, emitter=emitter)