Exemplo n.º 1
0
def nucypher_test_config(blockchain_config):

    config = NucypherConfig(keyring="this is the most secure password in the world.",
                            blockchain_config=blockchain_config)
    yield config
    NucypherConfig.reset()
    Blockchain.sever()
    del config
Exemplo n.º 2
0
    def __init__(self,
                 checksum_address: str = None,
                 blockchain: Blockchain = None
                 ) -> None:
        """
        :param checksum_address:  If not passed, we assume this is an unknown actor

        :param token_agent:  The token agent with the blockchain attached; If not passed, A default
        token agent and blockchain connection will be created from default values.

        """
        try:
            parent_address = self.checksum_public_address  # type: str
            if checksum_address is not None:
                if parent_address != checksum_address:
                    raise ValueError("Can't have two different addresses.")
        except AttributeError:
            self.checksum_public_address = checksum_address  # type: str

        if blockchain is None:
            blockchain = Blockchain.connect()
        self.blockchain = blockchain

        self.token_agent = NucypherTokenAgent()
        self._transaction_cache = list()  # type: list # track transactions transmitted
Exemplo n.º 3
0
    def connect_to_blockchain(self,
                              enode: str = None,
                              recompile_contracts: bool = False,
                              full_sync: bool = False) -> None:
        """

        :param enode: ETH seednode or bootnode enode address to start learning from,
                      i.e. 'enode://[email protected]:30303'

        :param recompile_contracts: Recompile all contracts on connection.

        :return: None
        """
        if self.federated_only:
            raise NodeConfiguration.ConfigurationError("Cannot connect to blockchain in federated mode")

        self.blockchain = Blockchain.connect(provider_uri=self.provider_uri,
                                             compile=recompile_contracts,
                                             poa=self.poa,
                                             fetch_registry=True,
                                             provider_process=self.provider_process,
                                             sync=full_sync)

        # Read Ethereum Node Keyring
        self.accounts = self.blockchain.interface.w3.eth.accounts

        # Add Ethereum Peer
        if enode:
            if self.blockchain.interface.client_version == 'geth':
                self.blockchain.interface.w3.geth.admin.addPeer(enode)
            else:
                raise NotImplementedError
Exemplo n.º 4
0
    def __init__(self,
                 blockchain: Blockchain = None,
                 contract: Contract = None,
                 transaction_gas: int = None
                 ) -> None:

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

        if blockchain is None:
            blockchain = Blockchain.connect()
        self.blockchain = blockchain

        if contract is None:  # Fetch the contract
            contract = self.blockchain.interface.get_contract_by_name(name=self.registry_contract_name,
                                                                      proxy_name=self._proxy_name,
                                                                      use_proxy_address=self._forward_address)
        self.__contract = contract

        if not transaction_gas:
            transaction_gas = EthereumContractAgent.DEFAULT_TRANSACTION_GAS
        self.transaction_gas = transaction_gas

        super().__init__()
        self.log.info("Initialized new {} for {} with {} and {}".format(self.__class__.__name__,
                                                                        self.contract_address,
                                                                        self.blockchain.interface.provider_uri,
                                                                        self.blockchain.interface.registry.filepath))
Exemplo n.º 5
0
    def connect_to_blockchain(self):
        """Initialize all blockchain entities from parsed config values"""

        self.blockchain = Blockchain.from_config(filepath=self.config_filepath)
        self.accounts = self.blockchain.interface.w3.eth.accounts

        #TODO: Exception handling here for key error when using incompadible operating mode
        if self.payload['tester'] and self.payload['deploy']:
            self.blockchain.interface.deployer_address = self.accounts[0]
Exemplo n.º 6
0
 def from_blockchain(cls,
                     provider_uri: str,
                     registry=None,
                     *args,
                     **kwargs):
     blockchain = Blockchain.connect(provider_uri=provider_uri,
                                     registry=registry)
     instance = cls(blockchain=blockchain, *args, **kwargs)
     return instance
Exemplo n.º 7
0
    def connect_to_blockchain(self, recompile_contracts: bool = False):
        if self.federated_only:
            raise NodeConfiguration.ConfigurationError("Cannot connect to blockchain in federated mode")

        self.blockchain = Blockchain.connect(provider_uri=self.provider_uri,
                                             compile=recompile_contracts,
                                             poa=self.poa)

        self.accounts = self.blockchain.interface.w3.eth.accounts
        self.log.debug("Established connection to provider {}".format(self.blockchain.interface.provider_uri))
Exemplo n.º 8
0
    def connect_to_blockchain(self):
        """Initialize all blockchain entities from parsed config values"""

        if self.node_config is constants.NO_NODE_CONFIGURATION:
            raise RuntimeError("No node configuration is available")

        self.blockchain = Blockchain.from_config(config=self.node_config)
        self.accounts = self.blockchain.interface.w3.eth.accounts

        if self.node_config.deploy:
            self.blockchain.interface.deployer_address = self.accounts[0]
Exemplo n.º 9
0
    def __init__(self, blockchain: Blockchain = None, *args, **kwargs):

        if blockchain is None:
            blockchain = Blockchain.connect()
        self.blockchain = blockchain

        # Fetch the contract by reading address and abi from the registry and blockchain
        contract = self.blockchain.interface.get_contract_by_name(
            name=self.principal_contract_name, upgradeable=self._upgradeable)
        self.__contract = contract

        super().__init__()
Exemplo n.º 10
0
def test_rollback(click_runner):
    """Roll 'em all back!"""

    mock_temporary_registry = EthereumContractRegistry(registry_filepath=MOCK_REGISTRY_FILEPATH)
    blockchain = Blockchain.connect(registry=mock_temporary_registry)

    # Input Components
    yes = 'Y\n'

    # Stage Rollbacks
    old_secret = INSECURE_SECRETS[PLANNED_UPGRADES]
    rollback_secret = generate_insecure_secret()
    user_input = '0\n' + yes + old_secret + rollback_secret + rollback_secret

    contracts_to_rollback = ('MinersEscrow',       # v4 -> v3
                             'PolicyManager',      # v4 -> v3
                             'MiningAdjudicator',  # v4 -> v3
                             )
    # Execute Rollbacks
    for contract_name in contracts_to_rollback:

        command = ('rollback',
                   '--contract-name', contract_name,
                   '--registry-infile', MOCK_REGISTRY_FILEPATH,
                   '--provider-uri', TEST_PROVIDER_URI,
                   '--poa')

        result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False)
        assert result.exit_code == 0

        records = blockchain.interface.registry.search(contract_name=contract_name)
        assert len(records) == 4

        *old_records, v3, v4 = records
        current_target, rollback_target = v4, v3

        _name, current_target_address, *abi = current_target
        _name, rollback_target_address, *abi = rollback_target
        assert current_target_address != rollback_target_address

        # Ensure the proxy targets the rollback target (previous version)
        with pytest.raises(BlockchainInterface.UnknownContract):
            blockchain.interface.get_proxy(target_address=current_target_address, proxy_name='Dispatcher')

        proxy = blockchain.interface.get_proxy(target_address=rollback_target_address, proxy_name='Dispatcher')

        # Deeper - Ensure the proxy targets the old deployment on-chain
        targeted_address = proxy.functions.target().call()
        assert targeted_address != current_target
        assert targeted_address == rollback_target_address
Exemplo n.º 11
0
    def derive_crypto_power(
        self, power_class: ClassVar
    ) -> Union[KeyPairBasedPower, DerivedKeyBasedPower]:
        """
        Takes either a SigningPower or an DecryptingPower and returns
        either a SigningPower or DecryptingPower with the coinciding
        private key.

        TODO: Derive a key from the root_key.
        """
        # Keypair-Based
        if issubclass(power_class, KeyPairBasedPower):

            codex = {
                SigningPower: self.__signing_keypath,
                DecryptingPower: self.__root_keypath,
                TLSHostingPower: self.__tls_keypath
            }

            # Create Power
            try:
                umbral_privkey = self.__decrypt_keyfile(codex[power_class])
                keypair = power_class._keypair_class(umbral_privkey)
                new_cryptopower = power_class(keypair=keypair)
            except KeyError:
                failure_message = "{} is an invalid type for deriving a CryptoPower".format(
                    power_class.__name__)
                raise TypeError(failure_message)

        # Derived
        elif issubclass(power_class, DerivedKeyBasedPower):
            key_data = _read_keyfile(self.__delegating_keypath,
                                     deserializer=self._private_key_serializer)
            wrap_key = _derive_wrapping_key_from_key_material(
                salt=key_data['wrap_salt'],
                key_material=self.__derived_key_material)
            keying_material = SecretBox(wrap_key).decrypt(key_data['key'])
            new_cryptopower = power_class(keying_material=keying_material)

        elif power_class is BlockchainPower:
            new_cryptopower = power_class(blockchain=Blockchain.connect(),
                                          account=self.checksum_address)

        else:
            failure_message = "{} is an invalid type for deriving a CryptoPower.".format(
                power_class.__name__)
            raise ValueError(failure_message)

        return new_cryptopower
Exemplo n.º 12
0
def test_geth_EIP_191_client_signature_integration(geth_dev_node):
    if 'CIRCLECI' in os.environ:
        pytest.skip("Do not run Geth nodes in CI")

    # Start a geth process
    blockchain = Blockchain.connect(provider_process=geth_dev_node, sync=False)

    # Sign a message (RPC) and verify it.
    etherbase = blockchain.interface.accounts[0]
    stamp = b'STAMP-' + os.urandom(64)
    signature = blockchain.interface.client.sign_message(account=etherbase,
                                                         message=stamp)
    is_valid = verify_eip_191(address=etherbase,
                              signature=signature,
                              message=stamp)
    assert is_valid
Exemplo n.º 13
0
 def connect_to_blockchain(self):
     if self.federated_only:
         raise NodeConfiguration.ConfigurationError(
             "Cannot connect to blockchain in federated mode")
     if self.deployer:
         self.registry_filepath = NodeConfiguration.REGISTRY_SOURCE
     if self.compile:
         click.confirm("Compile solidity source?", abort=True)
     self.blockchain = Blockchain.connect(provider_uri=self.provider_uri,
                                          deployer=self.deployer,
                                          compile=self.compile)
     if self.poa:
         w3 = self.blockchain.interface.w3
         w3.middleware_stack.inject(geth_poa_middleware, layer=0)
     self.accounts = self.blockchain.interface.w3.eth.accounts
     self.log.debug("CLI established connection to provider {}".format(
         self.blockchain.interface.provider_uri))
Exemplo n.º 14
0
    def __init__(self,
                 beneficiary: str,
                 blockchain: Blockchain = None,
                 allocation_registry: AllocationRegistry = None,
                 *args, **kwargs) -> None:

        self.blockchain = blockchain or Blockchain.connect()

        self.__allocation_registry = allocation_registry or self.__allocation_registry()
        self.__beneficiary = beneficiary
        self.__principal_contract = NO_CONTRACT_AVAILABLE
        self.__proxy_contract = NO_CONTRACT_AVAILABLE

        # Sets the above
        self.__read_principal()
        self.__read_proxy()
        super().__init__(blockchain=self.blockchain, contract=self.principal_contract, *args, **kwargs)
Exemplo n.º 15
0
    def __init__(self,
                 blockchain: Blockchain = None,
                 contract: Contract = None,
                 *args,
                 **kwargs):

        if blockchain is None:
            blockchain = Blockchain.connect()
        self.blockchain = blockchain

        if contract is None:
            address = blockchain.interface.get_contract_address(
                contract_name=self._principal_contract_name)[
                    -1]  # TODO: Handle multiple
            contract = blockchain.interface.get_contract(address)
        self.__contract = contract

        super().__init__(*args, **kwargs)
Exemplo n.º 16
0
    def __init__(self,
                 checksum_address: str = None,
                 blockchain: Blockchain = None):
        """
        :param checksum_address:  If not passed, we assume this is an unknown actor
        """
        try:
            parent_address = self.checksum_address  # type: str
            if checksum_address is not None:
                if parent_address != checksum_address:
                    raise ValueError("Can't have two different addresses.")
        except AttributeError:
            self.checksum_address = checksum_address  # type: str

        if blockchain is None:
            blockchain = Blockchain.connect()  # Attempt to connect
        self.blockchain = blockchain

        self.token_agent = NucypherTokenAgent(blockchain=self.blockchain)
        self._transaction_cache = list(
        )  # type: list # track transactions transmitted
Exemplo n.º 17
0
    def __init__(self,
                 blockchain: Blockchain = None,
                 contract: Contract = None) -> None:

        self.log = getLogger('agency')

        if blockchain is None:
            blockchain = Blockchain.connect()
        self.blockchain = blockchain

        if contract is None:
            # Fetch the contract by reading address and abi from the registry and blockchain
            contract = self.blockchain.interface.get_contract_by_name(
                name=self.principal_contract_name,
                upgradeable=self._upgradeable)
        self.__contract = contract
        super().__init__()
        self.log.info("Initialized new {} for {} with {} and {}".format(
            self.__class__.__name__, self.contract_address,
            self.blockchain.interface.provider_uri,
            self.blockchain.interface.registry.filepath))
Exemplo n.º 18
0
    def __init__(self,
                 blockchain: Blockchain = None,
                 registry_filepath: str = None,
                 *args,
                 **kwargs) -> None:

        if blockchain is None:
            blockchain = Blockchain.connect()
        self.blockchain = blockchain

        if registry_filepath is not None:
            # TODO: Warn on override?
            self.blockchain.interface._registry._swap_registry(
                filepath=registry_filepath)

        # Fetch the contract by reading address and abi from the registry and blockchain
        contract = self.blockchain.interface.get_contract_by_name(
            name=self.principal_contract_name, upgradeable=self._upgradeable)

        self.__contract = contract
        super().__init__()
Exemplo n.º 19
0
    def produce(self, passphrase: str = None, **overrides):
        """Produce a new Ursula from configuration"""

        if not self.temp:
            self.read_keyring()
            self.keyring.unlock(passphrase=passphrase)

        merged_parameters = {
            **self.static_payload,
            **self.dynamic_payload,
            **overrides
        }

        if self.federated_only is False:

            if self.poa:  # TODO: move this..?
                w3 = self.miner_agent.blockchain.interface.w3
                w3.middleware_stack.inject(geth_poa_middleware, layer=0)

            if not self.miner_agent:  # TODO: move this..?
                self.blockchain = Blockchain.connect(
                    provider_uri=self.blockchain_uri,
                    registry_filepath=self.registry_filepath)
                self.token_agent = NucypherTokenAgent(
                    blockchain=self.blockchain)
                self.miner_agent = MinerAgent(token_agent=self.token_agent)
                merged_parameters.update(miner_agent=self.miner_agent)

        ursula = self._Character(**merged_parameters)

        if self.temp:  # TODO: Move this..?

            class MockDatastoreThreadPool(object):
                def callInThread(self, f, *args, **kwargs):
                    return f(*args, **kwargs)

            ursula.datastore_threadpool = MockDatastoreThreadPool()

        return ursula
Exemplo n.º 20
0
    def __connect(deployer_address=None):

        # Ensure config root exists
        if not os.path.exists(DEFAULT_CONFIG_ROOT):
            os.makedirs(DEFAULT_CONFIG_ROOT)

        # Connect to Blockchain
        blockchain = Blockchain.connect(provider_uri=provider_uri,
                                        deployer=True,
                                        compile=not no_compile,
                                        poa=poa)

        if not deployer_address:
            etherbase = blockchain.interface.w3.eth.accounts[0]
            deployer_address = etherbase
        click.confirm(
            "Deployer Address is {} - Continue?".format(deployer_address),
            abort=True)

        deployer = Deployer(blockchain=blockchain,
                            deployer_address=deployer_address)

        return deployer
Exemplo n.º 21
0
    def __init__(self,
                 domains: Set = (GLOBAL_DOMAIN, ),
                 is_me: bool = True,
                 federated_only: bool = False,
                 blockchain: Blockchain = None,
                 checksum_public_address: bytes = NO_BLOCKCHAIN_CONNECTION.
                 bool_value(False),
                 network_middleware: RestMiddleware = None,
                 keyring_dir: str = None,
                 crypto_power: CryptoPower = None,
                 crypto_power_ups: List[CryptoPowerUp] = None,
                 *args,
                 **kwargs) -> None:
        """

        Base class for Nucypher protocol actors.


        PowerUps
        ========
        :param crypto_power: A CryptoPower object; if provided, this will be the character's CryptoPower.
        :param crypto_power_ups: If crypto_power is not provided, a new one will be made to consume all CryptoPowerUps.

        If neither crypto_power nor crypto_power_ups are provided, we give this
        Character all CryptoPowerUps listed in their _default_crypto_powerups
        attribute.

        :param is_me: Set this to True when you want this Character to represent
            the owner of the configuration under which the program is being run.
            A Character who is_me can do things that other Characters can't,
            like run servers, sign messages, and decrypt messages which are
            encrypted for them.  Typically this will be True for exactly one
            Character, but there are scenarios in which its imaginable to be
            represented by zero Characters or by more than one Character.

        """

        self.federated_only = federated_only  # type: bool

        #
        # Powers
        #
        if crypto_power and crypto_power_ups:
            raise ValueError(
                "Pass crypto_power or crypto_power_ups (or neither), but not both."
            )
        crypto_power_ups = crypto_power_ups or list()  # type: list

        if crypto_power:
            self._crypto_power = crypto_power  # type: CryptoPower
        elif crypto_power_ups:
            self._crypto_power = CryptoPower(power_ups=crypto_power_ups)
        else:
            self._crypto_power = CryptoPower(
                power_ups=self._default_crypto_powerups)

        self._checksum_address = checksum_public_address
        #
        # Self-Character
        #
        if is_me is True:
            if not self.federated_only:
                self.blockchain = blockchain or Blockchain.connect()

            self.keyring_dir = keyring_dir  # type: str
            self.treasure_maps = {}  # type: dict
            self.network_middleware = network_middleware or RestMiddleware()

            #
            # Signing Power
            #
            try:
                signing_power = self._crypto_power.power_ups(
                    SigningPower)  # type: SigningPower
                self._stamp = signing_power.get_signature_stamp(
                )  # type: SignatureStamp
            except NoSigningPower:
                self._stamp = NO_SIGNING_POWER

            #
            # Learner
            #
            Learner.__init__(self,
                             domains=domains,
                             network_middleware=network_middleware,
                             *args,
                             **kwargs)

        #
        # Stranger-Character
        #
        else:  # Feel like a stranger
            if network_middleware is not None:
                raise TypeError(
                    "Network middleware cannot be attached to a Stanger-Character."
                )
            self._stamp = StrangerStamp(self.public_keys(SigningPower))
            self.keyring_dir = STRANGER
            self.network_middleware = STRANGER

        #
        # Decentralized
        #
        if not federated_only:
            if not checksum_public_address:
                raise ValueError(
                    "No checksum_public_address provided while running in a non-federated mode."
                )
            else:
                self._checksum_address = checksum_public_address  # TODO: Check that this matches BlockchainPower
        #
        # Federated
        #
        elif federated_only:
            try:
                self._set_checksum_address()  # type: str
            except NoSigningPower:
                self._checksum_address = NO_BLOCKCHAIN_CONNECTION
            if checksum_public_address:
                # We'll take a checksum address, as long as it matches their singing key
                if not checksum_public_address == self.checksum_public_address:
                    error = "Federated-only Characters derive their address from their Signing key; got {} instead."
                    raise self.SuspiciousActivity(
                        error.format(checksum_public_address))

        #
        # Nicknames
        #
        try:
            self.nickname, self.nickname_metadata = nickname_from_seed(
                self.checksum_public_address)
        except SigningPower.not_found_error:
            if self.federated_only:
                self.nickname = self.nickname_metadata = NO_NICKNAME
            else:
                raise

        #
        # Fleet state
        #
        if is_me is True:
            self.known_nodes.record_fleet_state()

        #
        # Character Control
        #
        self.controller = NO_CONTROL_PROTOCOL
Exemplo n.º 22
0
def deploy(click_config, action, poa, provider_uri, deployer_address,
           contract_name, allocation_infile, allocation_outfile,
           registry_infile, registry_outfile, no_compile, amount,
           recipient_address, config_root, force):
    """Manage contract and registry deployment"""

    # Ensure config root exists, because we need a default place to put outfiles.
    config_root = config_root or DEFAULT_CONFIG_ROOT
    if not os.path.exists(config_root):
        os.makedirs(config_root)

    # Establish a contract Registry
    registry, registry_filepath = None, (registry_outfile or registry_infile)
    if registry_filepath is not None:
        registry = EthereumContractRegistry(
            registry_filepath=registry_filepath)

    # Connect to Blockchain
    blockchain = Blockchain.connect(provider_uri=provider_uri,
                                    registry=registry,
                                    deployer=True,
                                    compile=not no_compile,
                                    poa=poa)

    # OK - Let's init a Deployment actor
    if not deployer_address:
        etherbase = blockchain.interface.w3.eth.accounts[0]
        deployer_address = etherbase  # TODO: Make this required instead, perhaps interactive

    click.confirm(
        "Deployer Address is {} - Continue?".format(deployer_address),
        abort=True)
    deployer = Deployer(blockchain=blockchain,
                        deployer_address=deployer_address)

    # The Big Three
    if action == "contracts":
        secrets = click_config.collect_deployment_secrets()

        # Track tx hashes, and new agents
        __deployment_transactions = dict()
        __deployment_agents = dict()

        if force:
            deployer.blockchain.interface.registry._destroy()

        try:
            txhashes, agents = deployer.deploy_network_contracts(
                miner_secret=bytes(secrets.miner_secret, encoding='utf-8'),
                policy_secret=bytes(secrets.policy_secret, encoding='utf-8'),
                adjudicator_secret=bytes(secrets.mining_adjudicator_secret,
                                         encoding='utf-8'))
        except BlockchainInterface.InterfaceError:
            raise  # TODO: Handle registry management here (contract may already exist)
        else:
            __deployment_transactions.update(txhashes)

        # User Escrow Proxy
        deployer.deploy_escrow_proxy(
            secret=bytes(secrets.escrow_proxy_secret, encoding='utf-8'))
        click.secho("Deployed!", fg='green', bold=True)

        #
        # Deploy Single Contract
        #
        if contract_name:

            try:
                deployer_func = deployer.deployers[contract_name]
            except KeyError:
                message = "No such contract {}. Available contracts are {}".format(
                    contract_name, deployer.deployers.keys())
                click.secho(message, fg='red', bold=True)
                raise click.Abort()
            else:
                _txs, _agent = deployer_func()

        registry_outfile = deployer.blockchain.interface.registry.filepath
        click.secho(
            '\nDeployment Transaction Hashes for {}'.format(registry_outfile),
            bold=True,
            fg='blue')
        for contract_name, transactions in __deployment_transactions.items():

            heading = '\n{} ({})'.format(
                contract_name, agents[contract_name].contract_address)
            click.secho(heading, bold=True)
            click.echo('*' * (42 + 3 + len(contract_name)))

            total_gas_used = 0
            for tx_name, txhash in transactions.items():
                receipt = deployer.blockchain.wait_for_receipt(txhash=txhash)
                total_gas_used += int(receipt['gasUsed'])

                if receipt['status'] == 1:
                    click.secho("OK", fg='green', nl=False, bold=True)
                else:
                    click.secho("Failed", fg='red', nl=False, bold=True)
                click.secho(" | {}".format(tx_name), fg='yellow', nl=False)
                click.secho(" | {}".format(txhash.hex()),
                            fg='yellow',
                            nl=False)
                click.secho(" ({} gas)".format(receipt['cumulativeGasUsed']))

                click.secho("Block #{} | {}\n".format(
                    receipt['blockNumber'], receipt['blockHash'].hex()))

        click.secho(
            "Cumulative Gas Consumption: {} gas\n".format(total_gas_used),
            bold=True,
            fg='blue')

    elif action == "allocations":
        if not allocation_infile:
            allocation_infile = click.prompt("Enter allocation data filepath")
        click.confirm("Continue deploying and allocating?", abort=True)
        deployer.deploy_beneficiaries_from_file(
            allocation_data_filepath=allocation_infile,
            allocation_outfile=allocation_outfile)

    elif action == "transfer":
        token_agent = NucypherTokenAgent(blockchain=blockchain)
        click.confirm(
            f"Transfer {amount} from {token_agent.contract_address} to {recipient_address}?",
            abort=True)
        txhash = token_agent.transfer(
            amount=amount,
            sender_address=token_agent.contract_address,
            target_address=recipient_address)
        click.secho(f"OK | {txhash}")
        return

    elif action == "destroy-registry":
        registry_filepath = deployer.blockchain.interface.registry.filepath
        click.confirm(
            f"Are you absolutely sure you want to destroy the contract registry at {registry_filepath}?",
            abort=True)
        os.remove(registry_filepath)
        click.secho(f"Successfully destroyed {registry_filepath}", fg='red')

    else:
        raise click.BadArgumentUsage(message=f"Unknown action '{action}'")
Exemplo n.º 23
0
def test_upgrade_contracts(click_runner):

    #
    # Setup
    #

    # Connect to the blockchain with a blank temporary file-based registry
    mock_temporary_registry = EthereumContractRegistry(registry_filepath=MOCK_REGISTRY_FILEPATH)
    blockchain = Blockchain.connect(registry=mock_temporary_registry)

    # Check the existing state of the registry before the meat and potatoes
    expected_registrations = 9
    with open(MOCK_REGISTRY_FILEPATH, 'r') as file:
        raw_registry_data = file.read()
        registry_data = json.loads(raw_registry_data)
        assert len(registry_data) == expected_registrations

    #
    # Input Components
    #

    cli_action = 'upgrade'
    base_command = ('--registry-infile', MOCK_REGISTRY_FILEPATH, '--provider-uri', TEST_PROVIDER_URI, '--poa')

    # Generate user inputs
    yes = 'Y\n'  # :-)
    upgrade_inputs = dict()
    for version, insecure_secret in INSECURE_SECRETS.items():

        next_version = version + 1
        old_secret = INSECURE_SECRETS[version]
        try:
            new_secret = INSECURE_SECRETS[next_version]
        except KeyError:
            continue
        #             addr-----secret----new deploy secret (2x for confirmation)
        user_input = '0\n' + yes + old_secret + (new_secret * 2)
        upgrade_inputs[next_version] = user_input

    #
    # Stage Upgrades
    #

    contracts_to_upgrade = ('MinersEscrow',       # v1 -> v2
                            'PolicyManager',      # v1 -> v2
                            'MiningAdjudicator',  # v1 -> v2
                            'UserEscrowProxy',    # v1 -> v2

                            'MinersEscrow',       # v2 -> v3
                            'MinersEscrow',       # v3 -> v4

                            'MiningAdjudicator',  # v2 -> v3
                            'PolicyManager',      # v2 -> v3
                            'UserEscrowProxy',    # v2 -> v3

                            'UserEscrowProxy',    # v3 -> v4
                            'PolicyManager',      # v3 -> v4
                            'MiningAdjudicator',  # v3 -> v4

                            )  # NOTE: Keep all versions the same in this test (all version 4, for example)

    # Each contract starts at version 1
    version_tracker = {name: 1 for name in contracts_to_upgrade}

    #
    # Upgrade Contracts
    #

    for contract_name in contracts_to_upgrade:

        # Assemble CLI command
        command = (cli_action, '--contract-name', contract_name, *base_command)

        # Select upgrade interactive input scenario
        current_version = version_tracker[contract_name]
        new_version = current_version + 1
        user_input = upgrade_inputs[new_version]

        # Execute upgrade (Meat)
        result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False)
        assert result.exit_code == 0  # TODO: Console painting

        # Mutate the version tracking
        version_tracker[contract_name] += 1
        expected_registrations += 1

        # Verify the registry is updated (Potatoes)
        with open(MOCK_REGISTRY_FILEPATH, 'r') as file:

            # Read the registry file directly, bypassing its interfaces
            raw_registry_data = file.read()
            registry_data = json.loads(raw_registry_data)
            assert len(registry_data) == expected_registrations

            # Check that there is more than one entry, since we've deployed a "version 2"
            expected_enrollments = current_version + 1

            registered_names = [r[0] for r in registry_data]
            enrollments = registered_names.count(contract_name)

            assert enrollments > 1, f"New contract is not enrolled in {MOCK_REGISTRY_FILEPATH}"
            assert enrollments == expected_enrollments, f"Incorrect number of records enrolled for {contract_name}. " \
                                                        f"Expected {expected_enrollments} got {enrollments}."

        # Ensure deployments are different addresses
        records = blockchain.interface.registry.search(contract_name=contract_name)
        assert len(records) == expected_enrollments

        old, new = records[-2:]            # Get the last two entries
        old_name, old_address, *abi = old  # Previous version
        new_name, new_address, *abi = new  # New version
        assert old_name == new_name        # TODO: Inspect ABI?
        assert old_address != new_address

        # Select proxy (Dispatcher vs Linker)
        if contract_name == "UserEscrowProxy":
            proxy_name = "UserEscrowLibraryLinker"
        else:
            proxy_name = 'Dispatcher'

        # Ensure the proxy targets the new deployment
        proxy = blockchain.interface.get_proxy(target_address=new_address, proxy_name=proxy_name)
        targeted_address = proxy.functions.target().call()
        assert targeted_address != old_address
        assert targeted_address == new_address
Exemplo n.º 24
0
=======
from nucypher.config.constants import DEFAULT_SIMULATION_REGISTRY_FILEPATH
from nucypher.config.metadata import collect_stored_nodes
from nucypher.data_sources import DataSource
# This is already running in another process.
from nucypher.network.middleware import RestMiddleware
>>>>>>> 26103ab... Project-wide automated import optimization, followed-up with some hand-tweaking:examples/finnegans-wake-demo.py

# This is already running in another process.


##############################################
# This is already running in another process.
##############################################

BLOCKCHAIN = Blockchain.connect()

URSULA = Ursula.from_config()

#########
# Alice #
#########

ALICE = Alice.from_config()

# Here are our Policy details.
policy_end_datetime = maya.now() + datetime.timedelta(days=201)
m = 2
n = 3
label = b"secret/files/and/stuff"
Exemplo n.º 25
0
def deploy(click_config, action, poa, provider_uri, geth, enode,
           deployer_address, contract_name, allocation_infile,
           allocation_outfile, registry_infile, registry_outfile, no_compile,
           amount, recipient_address, config_root, sync, force):
    """Manage contract and registry deployment"""

    ETH_NODE = None

    #
    # Validate
    #

    # Ensure config root exists, because we need a default place to put output files.
    config_root = config_root or DEFAULT_CONFIG_ROOT
    if not os.path.exists(config_root):
        os.makedirs(config_root)

    #
    # Connect to Blockchain
    #

    # Establish a contract registry from disk if specified
    registry, registry_filepath = None, (registry_outfile or registry_infile)
    if registry_filepath is not None:
        registry = EthereumContractRegistry(
            registry_filepath=registry_filepath)

    if geth:
        # Spawn geth child process
        ETH_NODE = NuCypherGethDevnetProcess(config_root=config_root)
        ETH_NODE.ensure_account_exists(password=click_config.get_password(
            confirm=True))
        if not ETH_NODE.initialized:
            ETH_NODE.initialize_blockchain()
        ETH_NODE.start()  # TODO: Graceful shutdown
        provider_uri = ETH_NODE.provider_uri

    # Deployment-tuned blockchain connection
    blockchain = Blockchain.connect(provider_uri=provider_uri,
                                    poa=poa,
                                    registry=registry,
                                    compile=not no_compile,
                                    deployer=True,
                                    fetch_registry=False,
                                    sync=sync)

    #
    # Deployment Actor
    #

    if not deployer_address:
        for index, address in enumerate(blockchain.interface.w3.eth.accounts):
            click.secho(f"{index} --- {address}")
        choices = click.IntRange(0, len(blockchain.interface.w3.eth.accounts))
        deployer_address_index = click.prompt("Select deployer address",
                                              default=0,
                                              type=choices)
        deployer_address = blockchain.interface.w3.eth.accounts[
            deployer_address_index]

    # Verify Address
    if not force:
        click.confirm("Selected {} - Continue?".format(deployer_address),
                      abort=True)
    deployer = Deployer(blockchain=blockchain,
                        deployer_address=deployer_address)

    # Verify ETH Balance
    click.secho(f"\n\nDeployer ETH balance: {deployer.eth_balance}")
    if deployer.eth_balance == 0:
        click.secho("Deployer address has no ETH.", fg='red', bold=True)
        raise click.Abort()

    if not blockchain.interface.is_local:
        # (~ dev mode; Assume accounts are already unlocked)
        password = click.prompt("Enter ETH node password", hide_input=True)
        blockchain.interface.w3.geth.personal.unlockAccount(
            deployer_address, password)

    # Add ETH Bootnode or Peer
    if enode:
        if geth:
            blockchain.interface.w3.geth.admin.addPeer(enode)
            click.secho(f"Added ethereum peer {enode}")
        else:
            raise NotImplemented  # TODO: other backends

    #
    # Action switch
    #

    if action == 'upgrade':
        if not contract_name:
            raise click.BadArgumentUsage(
                message="--contract-name is required when using --upgrade")
        existing_secret = click.prompt(
            'Enter existing contract upgrade secret', hide_input=True)
        new_secret = click.prompt('Enter new contract upgrade secret',
                                  hide_input=True,
                                  confirmation_prompt=True)
        deployer.upgrade_contract(contract_name=contract_name,
                                  existing_plaintext_secret=existing_secret,
                                  new_plaintext_secret=new_secret)

    elif action == 'rollback':
        existing_secret = click.prompt(
            'Enter existing contract upgrade secret', hide_input=True)
        new_secret = click.prompt('Enter new contract upgrade secret',
                                  hide_input=True,
                                  confirmation_prompt=True)
        deployer.rollback_contract(contract_name=contract_name,
                                   existing_plaintext_secret=existing_secret,
                                   new_plaintext_secret=new_secret)

    elif action == "contracts":

        registry_filepath = deployer.blockchain.interface.registry.filepath
        if os.path.isfile(registry_filepath):
            click.secho(
                f"\nThere is an existing contract registry at {registry_filepath}.\n"
                f"Did you mean 'nucypher-deploy upgrade'?\n",
                fg='yellow')
            click.confirm(
                "Optionally, destroy existing local registry and continue?",
                abort=True)
            click.confirm(
                f"Confirm deletion of contract registry '{registry_filepath}'?",
                abort=True)
            os.remove(registry_filepath)

        #
        # Deploy Single Contract
        #

        if contract_name:
            # TODO: Handle secret collection for single contract deployment

            try:
                deployer_func = deployer.deployers[contract_name]
            except KeyError:
                message = f"No such contract {contract_name}. Available contracts are {deployer.deployers.keys()}"
                click.secho(message, fg='red', bold=True)
                raise click.Abort()
            else:
                # Deploy single contract
                _txs, _agent = deployer_func()

            # TODO: Painting for single contract deployment
            if ETH_NODE:
                ETH_NODE.stop()
            return

        #
        # Stage Deployment
        #

        # Track tx hashes, and new agents
        __deployment_transactions = dict()
        __deployment_agents = dict()

        secrets = click_config.collect_deployment_secrets()
        click.clear()
        click.secho(NU_BANNER)

        w3 = deployer.blockchain.interface.w3
        click.secho(f"Current Time ........ {maya.now().iso8601()}")
        click.secho(
            f"Web3 Provider ....... {deployer.blockchain.interface.provider_uri}"
        )
        click.secho(f"Block ............... {w3.eth.blockNumber}")
        click.secho(f"Gas Price ........... {w3.eth.gasPrice}")

        click.secho(f"Deployer Address .... {deployer.checksum_address}")
        click.secho(f"ETH ................. {deployer.eth_balance}")
        click.secho(
            f"CHAIN ID............. {deployer.blockchain.interface.chain_id}")
        click.secho(
            f"CHAIN................ {deployer.blockchain.interface.chain_name}"
        )

        # Ask - Last chance to gracefully abort
        if not force:
            click.secho(
                "\nDeployment successfully staged. Take a deep breath. \n",
                fg='green')
            if click.prompt("Type 'DEPLOY' to continue") != 'DEPLOY':
                raise click.Abort()

        # Delay - Last chance to crash and abort
        click.secho(f"Starting deployment in 3 seconds...", fg='red')
        time.sleep(1)
        click.secho(f"2...", fg='yellow')
        time.sleep(1)
        click.secho(f"1...", fg='green')
        time.sleep(1)
        click.secho(f"Deploying...", bold=True)

        #
        # DEPLOY < -------
        #

        txhashes, deployers = deployer.deploy_network_contracts(
            miner_secret=secrets.miner_secret,
            policy_secret=secrets.policy_secret,
            adjudicator_secret=secrets.mining_adjudicator_secret,
            user_escrow_proxy_secret=secrets.escrow_proxy_secret)

        # Success
        __deployment_transactions.update(txhashes)

        #
        # Paint
        #

        total_gas_used = 0  # TODO: may be faulty
        for contract_name, transactions in __deployment_transactions.items():

            # Paint heading
            heading = '\n{} ({})'.format(
                contract_name, deployers[contract_name].contract_address)
            click.secho(heading, bold=True)
            click.echo('*' * (42 + 3 + len(contract_name)))

            for tx_name, txhash in transactions.items():

                # Wait for inclusion in the blockchain
                try:
                    receipt = deployer.blockchain.wait_for_receipt(
                        txhash=txhash)
                except TimeExhausted:
                    raise  # TODO: Option to wait longer or retry

                # Examine Receipt # TODO: This currently cannot receive failed transactions
                if receipt['status'] == 1:
                    click.secho("OK", fg='green', nl=False, bold=True)
                else:
                    click.secho("Failed", fg='red', nl=False, bold=True)

                # Accumulate gas
                total_gas_used += int(receipt['gasUsed'])

                # Paint
                click.secho(" | {}".format(tx_name), fg='yellow', nl=False)
                click.secho(" | {}".format(txhash.hex()),
                            fg='yellow',
                            nl=False)
                click.secho(" ({} gas)".format(receipt['cumulativeGasUsed']))
                click.secho("Block #{} | {}\n".format(
                    receipt['blockNumber'], receipt['blockHash'].hex()))

        # Paint outfile paths
        click.secho(
            "Cumulative Gas Consumption: {} gas".format(total_gas_used),
            bold=True,
            fg='blue')
        registry_outfile = deployer.blockchain.interface.registry.filepath
        click.secho('Generated registry {}'.format(registry_outfile),
                    bold=True,
                    fg='blue')

        # Save transaction metadata
        receipts_filepath = deployer.save_deployment_receipts(
            transactions=__deployment_transactions)
        click.secho(f"Saved deployment receipts to {receipts_filepath}",
                    fg='blue',
                    bold=True)

        #
        # Publish Contract Registry
        #

        if not deployer.blockchain.interface.is_local:
            if click.confirm("Publish new contract registry?"):
                try:
                    response = registry.publish(
                    )  # TODO: Handle non-200 response and dehydrate
                except EthereumContractRegistry.RegistryError as e:
                    click.secho("Registry publication failed.",
                                fg='red',
                                bold=True)
                    click.secho(str(e))
                    raise click.Abort()
                click.secho(f"Published new contract registry.", fg='green')

    elif action == "allocations":
        if not allocation_infile:
            allocation_infile = click.prompt("Enter allocation data filepath")
        click.confirm("Continue deploying and allocating?", abort=True)
        deployer.deploy_beneficiaries_from_file(
            allocation_data_filepath=allocation_infile,
            allocation_outfile=allocation_outfile)

    elif action == "transfer":
        token_agent = NucypherTokenAgent(blockchain=blockchain)
        click.confirm(
            f"Transfer {amount} from {token_agent.contract_address} to {recipient_address}?",
            abort=True)
        txhash = token_agent.transfer(
            amount=amount,
            sender_address=token_agent.contract_address,
            target_address=recipient_address)
        click.secho(f"OK | {txhash}")

    elif action == "publish-registry":
        registry = deployer.blockchain.interface.registry
        click.confirm(
            f"Publish {registry.filepath} to GitHub (Authentication Required)?",
            abort=True)
        try:
            response = registry.publish(
            )  # TODO: Handle non-200 response and dehydrate
        except EthereumContractRegistry.RegistryError as e:
            click.secho(str(e))
            raise click.Abort()
        click.secho(f"Published new contract registry.", fg='green')

    elif action == "destroy-registry":
        registry_filepath = deployer.blockchain.interface.registry.filepath
        click.confirm(
            f"Are you absolutely sure you want to destroy the contract registry at {registry_filepath}?",
            abort=True)
        os.remove(registry_filepath)
        click.secho(f"Successfully destroyed {registry_filepath}", fg='red')

    else:
        raise click.BadArgumentUsage(message=f"Unknown action '{action}'")

    if ETH_NODE:
        ETH_NODE.stop()