Ejemplo n.º 1
0
    TokenNetworkAddress,
)
from raiden_contracts.constants import CONTRACT_TOKEN_NETWORK_REGISTRY, CONTRACT_USER_DEPOSIT
from raiden_contracts.tests.utils import get_random_privkey, to_canonical_address
from raiden_libs.events import (
    ReceiveChannelClosedEvent,
    ReceiveChannelOpenedEvent,
    ReceiveTokenNetworkCreatedEvent,
    UpdatedHeadBlockEvent,
)
from raiden_libs.logging import format_to_hex

from ..libs.mocks.web3 import ContractMock, Web3Mock

PARTICIPANT1_PRIVKEY, PARTICIPANT1 = make_privkey_address()
PARTICIPANT2 = Address(bytes([2] * 20))


def test_save_and_load_token_networks(pathfinding_service_mock_empty):
    pfs = pathfinding_service_mock_empty

    token_address = Address(bytes([1] * 20))
    token_network_address = TokenNetworkAddress(bytes([2] * 20))
    channel_id = ChannelID(1)
    p1 = Address(bytes([3] * 20))
    p2 = Address(bytes([4] * 20))
    events = [
        ReceiveTokenNetworkCreatedEvent(
            token_address=token_address,
            token_network_address=token_network_address,
            block_number=BlockNumber(1),
Ejemplo n.º 2
0
def make_address() -> Address:
    return Address(make_20bytes())
Ejemplo n.º 3
0
    def deploy_solidity_contract(
        self,  # pylint: disable=too-many-locals
        contract_name,
        all_contracts,
        libraries=None,
        constructor_parameters=None,
        contract_path=None,
    ):
        """
        Deploy a solidity contract.
        Args:
            sender (address): the sender address
            contract_name (str): the name of the contract to compile
            all_contracts (dict): the json dictionary containing the result of compiling a file
            libraries (list): A list of libraries to use in deployment
            constructor_parameters (tuple): A tuple of arguments to pass to the constructor
            contract_path (str): If we are dealing with solc >= v0.4.9 then the path
                                 to the contract is a required argument to extract
                                 the contract data from the `all_contracts` dict.
        """
        if libraries is None:
            libraries = dict()
        if constructor_parameters is None:
            constructor_parameters = []
        all_contracts = copy.deepcopy(all_contracts)
        if contract_name in all_contracts:
            contract_key = contract_name

        elif contract_path is not None:
            contract_key = os.path.basename(
                contract_path) + ':' + contract_name

            if contract_key not in all_contracts:
                raise ValueError('Unknown contract {}'.format(contract_name))
        else:
            raise ValueError(
                'Unknown contract {} and no contract_path given'.format(
                    contract_name), )

        libraries = dict(libraries)
        contract = all_contracts[contract_key]
        contract_interface = contract['abi']
        symbols = solidity_unresolved_symbols(contract['bin'])

        if symbols:
            available_symbols = list(
                map(solidity_library_symbol, all_contracts.keys()))

            unknown_symbols = set(symbols) - set(available_symbols)
            if unknown_symbols:
                msg = 'Cannot deploy contract, known symbols {}, unresolved symbols {}.'.format(
                    available_symbols,
                    unknown_symbols,
                )
                raise Exception(msg)

            dependencies = deploy_dependencies_symbols(all_contracts)
            deployment_order = dependencies_order_of_build(
                contract_key, dependencies)

            deployment_order.pop()  # remove `contract_name` from the list

            log.debug('Deploying dependencies: {}'.format(
                str(deployment_order)))

            for deploy_contract in deployment_order:
                dependency_contract = all_contracts[deploy_contract]

                hex_bytecode = solidity_resolve_symbols(
                    dependency_contract['bin'], libraries)
                bytecode = unhexlify(hex_bytecode)

                dependency_contract['bin'] = bytecode

                transaction_hash_hex = self.send_transaction(
                    to=Address(b''),
                    data=bytecode,
                )
                transaction_hash = unhexlify(transaction_hash_hex)

                self.poll(transaction_hash)
                receipt = self.get_transaction_receipt(transaction_hash)

                contract_address = receipt['contractAddress']
                # remove the hexadecimal prefix 0x from the address
                contract_address = contract_address[2:]

                libraries[deploy_contract] = contract_address

                deployed_code = self.web3.eth.getCode(
                    to_checksum_address(contract_address))

                if not deployed_code:
                    raise RuntimeError(
                        'Contract address has no code, check gas usage.')

            hex_bytecode = solidity_resolve_symbols(contract['bin'], libraries)
            bytecode = unhexlify(hex_bytecode)

            contract['bin'] = bytecode

        if isinstance(contract['bin'], str):
            contract['bin'] = unhexlify(contract['bin'])

        if not constructor_parameters:
            constructor_parameters = ()

        contract = self.web3.eth.contract(abi=contract['abi'],
                                          bytecode=contract['bin'])
        bytecode = contract.constructor(
            *constructor_parameters).buildTransaction()['data']
        transaction_hash_hex = self.send_transaction(
            to=Address(b''),
            data=bytecode,
        )
        transaction_hash = unhexlify(transaction_hash_hex)

        self.poll(transaction_hash)
        receipt = self.get_transaction_receipt(transaction_hash)
        contract_address = receipt['contractAddress']

        deployed_code = self.web3.eth.getCode(
            to_checksum_address(contract_address))

        if not deployed_code:
            raise RuntimeError(
                'Deployment of {} failed. Contract address has no code, check gas usage.'
                .format(contract_name, ), )

        return self.new_contract_proxy(
            contract_interface,
            contract_address,
        )
Ejemplo n.º 4
0
    TODEVICE = "toDevice"  # supports sending and receiving toDevice messages on Matrix


class ServerListType(Enum):
    ACTIVE_SERVERS = "active_servers"
    ALL_SERVERS = "all_servers"


# Set at 64 since parity's default is 64 and Geth's default is 128
# TODO: Make this configurable. Since in parity this is also a configurable value
STATE_PRUNING_AFTER_BLOCKS = 64
STATE_PRUNING_SAFETY_MARGIN = 8
NO_STATE_QUERY_AFTER_BLOCKS = STATE_PRUNING_AFTER_BLOCKS - STATE_PRUNING_SAFETY_MARGIN

NULL_ADDRESS_BYTES = bytes(20)
NULL_ADDRESS_HEX = to_hex_address(Address(NULL_ADDRESS_BYTES))
NULL_ADDRESS_CHECKSUM = to_checksum_address(Address(NULL_ADDRESS_BYTES))

EMPTY_HASH = BlockHash(bytes(32))
EMPTY_BALANCE_HASH = BalanceHash(bytes(32))
EMPTY_MESSAGE_HASH = AdditionalHash(bytes(32))
EMPTY_SIGNATURE = Signature(bytes(65))
EMPTY_SECRET = Secret(bytes(32))
EMPTY_SECRETHASH = SecretHash(bytes(32))
EMPTY_SECRET_SHA256 = sha256_secrethash(EMPTY_SECRET)
LOCKSROOT_OF_NO_LOCKS = Locksroot(keccak(b""))
EMPTY_LOCKSROOT = Locksroot(bytes(32))
ZERO_TOKENS = TokenAmount(0)

ABSENT_SECRET = Secret(b"")
Ejemplo n.º 5
0
    def deploy_solidity_contract(
        self,  # pylint: disable=too-many-locals
        contract_name: str,
        all_contracts: Dict[str, ABI],
        libraries: Dict[str, str] = None,
        constructor_parameters: Tuple[Any] = None,
        contract_path: str = None,
    ):
        """
        Deploy a solidity contract.

        Args:
            contract_name: The name of the contract to compile.
            all_contracts: The json dictionary containing the result of compiling a file.
            libraries: A list of libraries to use in deployment.
            constructor_parameters: A tuple of arguments to pass to the constructor.
            contract_path: If we are dealing with solc >= v0.4.9 then the path
                           to the contract is a required argument to extract
                           the contract data from the `all_contracts` dict.
        """
        if libraries:
            libraries = dict(libraries)
        else:
            libraries = dict()

        ctor_parameters = constructor_parameters or ()
        all_contracts = copy.deepcopy(all_contracts)

        if contract_name in all_contracts:
            contract_key = contract_name

        elif contract_path is not None:
            contract_key = os.path.basename(
                contract_path) + ":" + contract_name

            if contract_key not in all_contracts:
                raise ValueError("Unknown contract {}".format(contract_name))
        else:
            raise ValueError(
                "Unknown contract {} and no contract_path given".format(
                    contract_name))

        contract = all_contracts[contract_key]
        contract_interface = contract["abi"]
        symbols = solidity_unresolved_symbols(contract["bin"])

        if symbols:
            available_symbols = list(
                map(solidity_library_symbol, all_contracts.keys()))

            unknown_symbols = set(symbols) - set(available_symbols)
            if unknown_symbols:
                msg = "Cannot deploy contract, known symbols {}, unresolved symbols {}.".format(
                    available_symbols, unknown_symbols)
                raise Exception(msg)

            dependencies = deploy_dependencies_symbols(all_contracts)
            deployment_order = dependencies_order_of_build(
                contract_key, dependencies)

            deployment_order.pop()  # remove `contract_name` from the list

            log.debug("Deploying dependencies: {}".format(
                str(deployment_order)),
                      node=pex(self.address))

            for deploy_contract in deployment_order:
                dependency_contract = all_contracts[deploy_contract]

                hex_bytecode = solidity_resolve_symbols(
                    dependency_contract["bin"], libraries)
                bytecode = decode_hex(hex_bytecode)

                dependency_contract["bin"] = bytecode

                gas_limit = self.web3.eth.getBlock(
                    "latest")["gasLimit"] * 8 // 10
                transaction_hash = self.send_transaction(to=Address(b""),
                                                         startgas=gas_limit,
                                                         data=bytecode)

                self.poll(transaction_hash)
                receipt = self.get_transaction_receipt(transaction_hash)

                contract_address = receipt["contractAddress"]
                # remove the hexadecimal prefix 0x from the address
                contract_address = remove_0x_prefix(contract_address)

                libraries[deploy_contract] = contract_address

                deployed_code = self.web3.eth.getCode(
                    to_checksum_address(contract_address))

                if not deployed_code:
                    raise RuntimeError(
                        "Contract address has no code, check gas usage.")

            hex_bytecode = solidity_resolve_symbols(contract["bin"], libraries)
            bytecode = decode_hex(hex_bytecode)

            contract["bin"] = bytecode

        if isinstance(contract["bin"], str):
            contract["bin"] = decode_hex(contract["bin"])

        contract_object = self.web3.eth.contract(abi=contract["abi"],
                                                 bytecode=contract["bin"])
        contract_transaction = contract_object.constructor(
            *ctor_parameters).buildTransaction()
        transaction_hash = self.send_transaction(
            to=Address(b""),
            data=contract_transaction["data"],
            startgas=self._gas_estimate_correction(
                contract_transaction["gas"]),
        )

        self.poll(transaction_hash)
        receipt = self.get_transaction_receipt(transaction_hash)
        contract_address = receipt["contractAddress"]

        deployed_code = self.web3.eth.getCode(
            to_checksum_address(contract_address))

        if not deployed_code:
            raise RuntimeError(
                "Deployment of {} failed. Contract address has no code, check gas usage."
                .format(contract_name))

        return self.new_contract_proxy(contract_interface,
                                       contract_address), receipt
Ejemplo n.º 6
0
def services_bundle_from_contracts_deployment(
    config: RaidenConfig,
    proxy_manager: ProxyManager,
    routing_mode: RoutingMode,
    deployed_addresses: DeploymentAddresses,
    pathfinding_service_address: str,
    enable_monitoring: bool,
) -> ServicesBundle:
    """
    Initialize and setup the contract proxies.

    Depending on the provided contract addresses via the CLI, the routing mode,
    the environment type and the network id try to initialize the proxies.
    Returns the initialized proxies or exits the application with an error if
    there is a problem.

    Also depending on the given arguments populate config with PFS related settings
    """
    node_network_id = config.chain_id
    environment_type = config.environment_type

    user_deposit_address = deployed_addresses.user_deposit_address
    service_registry_address = deployed_addresses.service_registry_address
    token_network_registry_address = deployed_addresses.token_network_registry_address

    contractname_address: List[Tuple[str, Address, Callable]] = [
        ("user_deposit", Address(user_deposit_address), proxy_manager.user_deposit)
    ]
    if routing_mode == RoutingMode.PFS:
        contractname_address.append(
            ("service_registry", Address(service_registry_address), proxy_manager.service_registry)
        )
    if enable_monitoring or routing_mode == RoutingMode.PFS:
        contractname_address.append(
            (
                "monitoring_service",
                Address(deployed_addresses.monitoring_service_address),
                proxy_manager.monitoring_service,
            )
        )
        contractname_address.append(
            ("one_to_n", Address(deployed_addresses.one_to_n_address), proxy_manager.one_to_n)
        )

    proxies = dict()

    for contractname, address, constructor in contractname_address:
        try:
            proxy = constructor(address)
        except ContractCodeMismatch as e:
            handle_contract_code_mismatch(e)
        except AddressWithoutCode:
            handle_contract_no_code(contractname, address)
        except AddressWrongContract:
            handle_contract_wrong_address(contractname, address)

        proxies[contractname] = proxy

    if routing_mode == RoutingMode.PFS:
        check_pfs_configuration(pathfinding_service_address=pathfinding_service_address)

        pfs_info = configure_pfs_or_exit(
            pfs_url=pathfinding_service_address,
            routing_mode=routing_mode,
            service_registry=proxies["service_registry"],
            node_network_id=node_network_id,
            token_network_registry_address=TokenNetworkRegistryAddress(
                token_network_registry_address
            ),
            pathfinding_max_fee=config.services.pathfinding_max_fee,
        )
        msg = "Eth address of selected pathfinding service is unknown."
        assert pfs_info.payment_address is not None, msg

        # Only check that PFS is registered in production mode
        if environment_type == Environment.PRODUCTION:
            check_pfs_for_production(
                service_registry=proxies["service_registry"], pfs_info=pfs_info
            )

        config.pfs_config = PFSConfig(
            info=pfs_info,
            maximum_fee=config.services.pathfinding_max_fee,
            iou_timeout=config.services.pathfinding_iou_timeout,
            max_paths=config.services.pathfinding_max_paths,
        )
    else:
        config.pfs_config = None

    return ServicesBundle(
        user_deposit=cast(UserDeposit, proxies.get("user_deposit")),
        service_registry=cast(ServiceRegistry, proxies.get("service_registry")),
        monitoring_service=cast(MonitoringService, proxies.get("monitoring_service")),
        one_to_n=cast(OneToN, proxies.get("one_to_n")),
    )
Ejemplo n.º 7
0
    def start_mediated_transfer_with_secret(
            self,
            token_network_identifier: TokenNetworkID,
            amount: PaymentAmount,
            target: TargetAddress,
            identifier: PaymentID,
            secret: Secret,
            secret_hash: SecretHash = None,
    ) -> PaymentStatus:

        if secret_hash is None:
            secret_hash = sha3(secret)

        # LEFTODO: Supply a proper block id
        secret_registered = self.default_secret_registry.check_registered(
            secrethash=secret_hash,
            block_identifier='latest',
        )
        if secret_registered:
            raise RaidenUnrecoverableError(
                f'Attempted to initiate a locked transfer with secrethash {pex(secret_hash)}.'
                f' That secret is already registered onchain.',
            )

        self.start_health_check_for(Address(target))

        if identifier is None:
            identifier = create_default_identifier()

        with self.payment_identifier_lock:
            payment_status = self.targets_to_identifiers_to_statuses[target].get(identifier)
            if payment_status:
                payment_status_matches = payment_status.matches(
                    token_network_identifier,
                    amount,
                )
                if not payment_status_matches:
                    raise PaymentConflict(
                        'Another payment with the same id is in flight',
                    )

                return payment_status

            payment_status = PaymentStatus(
                payment_identifier=identifier,
                amount=amount,
                token_network_identifier=token_network_identifier,
                payment_done=AsyncResult(),
                secret=secret,
                secret_hash=secret_hash,
            )
            self.targets_to_identifiers_to_statuses[target][identifier] = payment_status

        init_initiator_statechange = initiator_init(
            raiden=self,
            transfer_identifier=identifier,
            transfer_amount=amount,
            transfer_secret=secret,
            token_network_identifier=token_network_identifier,
            target_address=target,
        )

        # Dispatch the state change even if there are no routes to create the
        # wal entry.
        self.handle_state_change(init_initiator_statechange)

        return payment_status
Ejemplo n.º 8
0
    def _add_token(
        self,
        token_address: TokenAddress,
        channel_participant_deposit_limit: TokenAmount,
        token_network_deposit_limit: TokenAmount,
        log_details: Dict[Any, Any],
    ) -> Tuple[TransactionHash, TokenNetworkAddress]:
        token_network_address = None

        kwargs = {
            "_token_address": token_address,
            "_channel_participant_deposit_limit":
            channel_participant_deposit_limit,
            "_token_network_deposit_limit": token_network_deposit_limit,
        }
        estimated_transaction = self.rpc_client.estimate_gas(
            self.proxy, "createERC20TokenNetwork", log_details, **kwargs)

        if estimated_transaction is not None:
            estimated_transaction.estimated_gas = safe_gas_limit(
                estimated_transaction.estimated_gas,
                self.gas_measurements[
                    "TokenNetworkRegistry createERC20TokenNetwork"],
            )

            transaction_sent = self.rpc_client.transact(estimated_transaction)
            transaction_mined = self.rpc_client.poll_transaction(
                transaction_sent)
            receipt = transaction_mined.receipt

            if not was_transaction_successfully_mined(transaction_mined):
                failed_at_blocknumber = BlockNumber(receipt["blockNumber"])

                max_token_networks = self.get_max_token_networks(
                    block_identifier=failed_at_blocknumber)
                token_networks_created = self.get_token_network_created(
                    block_identifier=failed_at_blocknumber)
                already_registered = self.get_token_network(
                    token_address=token_address,
                    block_identifier=failed_at_blocknumber)
                deprecation_executor = self.get_deprecation_executor(
                    block_identifier=failed_at_blocknumber)
                settlement_timeout_min = self.settlement_timeout_min(
                    block_identifier=failed_at_blocknumber)
                settlement_timeout_max = self.settlement_timeout_max(
                    block_identifier=failed_at_blocknumber)
                chain_id = self.get_chain_id(
                    block_identifier=failed_at_blocknumber)
                secret_registry_address = self.get_secret_registry_address(
                    block_identifier=failed_at_blocknumber)

                try:
                    # Creating a new instance to run the constructor checks.
                    token_proxy = Token(
                        jsonrpc_client=self.rpc_client,
                        token_address=token_address,
                        contract_manager=self.proxy_manager.contract_manager,
                        block_identifier=failed_at_blocknumber,
                    )
                except AddressWithoutCode:
                    # This cannot be an unrecoverable error, since the ERC20
                    # code is external.
                    raise RaidenRecoverableError(
                        "Token disappeared! The address "
                        f"{to_checksum_address(token_address)} did have code at "
                        f"block {log_details['given_block_identifier']}, however "
                        f"at block {failed_at_blocknumber} when the registration "
                        "transaction was mined the address didn't have code "
                        "anymore.")

                check_transaction_failure(transaction_mined, self.rpc_client)

                check_address_has_code_handle_pruned_block(
                    client=self.rpc_client,
                    address=Address(secret_registry_address),
                    contract_name=CONTRACT_SECRET_REGISTRY,
                    expected_code=decode_hex(
                        self.proxy_manager.contract_manager.
                        get_runtime_hexcode(CONTRACT_SECRET_REGISTRY)),
                    given_block_identifier=failed_at_blocknumber,
                )

                if token_networks_created >= max_token_networks:
                    raise RaidenRecoverableError(
                        "The number of existing token networks reached the maximum allowed"
                    )

                if already_registered:
                    # Race condition lost, the token network was created in a different
                    # transaction which got mined first.
                    raise RaidenRecoverableError(
                        "The token was already registered in the TokenNetworkRegistry."
                    )

                if deprecation_executor == NULL_ADDRESS_BYTES:
                    raise RaidenUnrecoverableError(
                        "The deprecation executor property for the "
                        "TokenNetworkRegistry is invalid.")

                if chain_id == 0:
                    raise RaidenUnrecoverableError(
                        "The chain ID property for the TokenNetworkRegistry is invalid."
                    )

                if chain_id != self.rpc_client.chain_id:
                    raise RaidenUnrecoverableError(
                        f"The provided chain ID {chain_id} does not match the "
                        f"network Raiden is running on: {self.rpc_client.chain_id}."
                    )

                if secret_registry_address == NULL_ADDRESS_BYTES:
                    raise RaidenUnrecoverableError(
                        "The secret registry address for the token network is invalid."
                    )

                if settlement_timeout_min == 0:
                    raise RaidenUnrecoverableError(
                        "The minimum settlement timeout for the token network "
                        "should be larger than zero.")

                if settlement_timeout_max <= settlement_timeout_min:
                    raise RaidenUnrecoverableError(
                        "The maximum settlement timeout for the token network "
                        "should be larger than the minimum settlement timeout."
                    )

                total_supply = token_proxy.total_supply(
                    block_identifier=failed_at_blocknumber)
                if not total_supply or total_supply <= 0:
                    raise RaidenRecoverableError(
                        f"The given token address is not a valid ERC20 token, "
                        f"total_supply() returned an invalid value {total_supply}."
                    )

                # At this point, the TokenNetworkRegistry fails to instantiate
                # a new TokenNetwork.
                raise RaidenUnrecoverableError(
                    "createERC20TokenNetwork failed for an unknown reason, even "
                    "though the gas estimation succeeded.")

            succeeded_at_blockhash = receipt["blockHash"]
            token_network_address = self.get_token_network(
                token_address, succeeded_at_blockhash)
            if token_network_address is None:
                msg = "createERC20TokenNetwork succeeded but token network address is Null"
                raise RaidenUnrecoverableError(msg)
        else:  # `estimated_transaction` is None
            # The latest block can not be used reliably because of reorgs,
            # therefore every call using this block has to handle pruned data.
            failed_at_block = self.rpc_client.get_block(BLOCK_ID_LATEST)
            failed_at_blockhash = failed_at_block["hash"].hex()
            failed_at_blocknumber = failed_at_block["number"]

            max_token_networks = self.get_max_token_networks(
                block_identifier=failed_at_blocknumber)
            token_networks_created = self.get_token_network_created(
                block_identifier=failed_at_blocknumber)

            already_registered = self.get_token_network(
                token_address=token_address,
                block_identifier=failed_at_blocknumber)
            deprecation_executor = self.get_deprecation_executor(
                block_identifier=failed_at_blocknumber)
            settlement_timeout_min = self.settlement_timeout_min(
                block_identifier=failed_at_blocknumber)
            settlement_timeout_max = self.settlement_timeout_max(
                block_identifier=failed_at_blocknumber)
            chain_id = self.get_chain_id(
                block_identifier=failed_at_blocknumber)
            secret_registry_address = self.get_secret_registry_address(
                block_identifier=failed_at_blocknumber)

            try:
                # Creating a new instance to run the constructor checks.
                token_proxy = Token(
                    jsonrpc_client=self.rpc_client,
                    token_address=token_address,
                    contract_manager=self.proxy_manager.contract_manager,
                    block_identifier=failed_at_blocknumber,
                )
            except AddressWithoutCode:
                # This cannot be an unrecoverable error, since the ERC20
                # code is external.
                raise RaidenRecoverableError(
                    "Token disappeared! The address "
                    "{to_checksum_address(token_address)} did have code at "
                    "block {log_details['given_block_identifier']}, however "
                    "at block {failed_at_blocknumber} when the registration "
                    "transaction was mined the address didn't have code "
                    "anymore.")

            check_address_has_code_handle_pruned_block(
                client=self.rpc_client,
                address=Address(secret_registry_address),
                contract_name=CONTRACT_SECRET_REGISTRY,
                expected_code=decode_hex(
                    self.proxy_manager.contract_manager.get_runtime_hexcode(
                        CONTRACT_SECRET_REGISTRY)),
                given_block_identifier=failed_at_blocknumber,
            )

            required_gas = self.gas_measurements[
                "TokenNetworkRegistry createERC20TokenNetwork"]

            self.rpc_client.check_for_insufficient_eth(
                transaction_name="createERC20TokenNetwork",
                transaction_executed=False,
                required_gas=required_gas,
                block_identifier=failed_at_blocknumber,
            )

            if token_networks_created >= max_token_networks:
                raise RaidenRecoverableError(
                    "The number of existing token networks reached the maximum allowed"
                )

            if already_registered:
                # Race condition lost, the token network was created in a different
                # transaction which got mined first.
                raise RaidenRecoverableError(
                    "The token was already registered in the TokenNetworkRegistry."
                )

            if deprecation_executor == NULL_ADDRESS_BYTES:
                raise RaidenUnrecoverableError(
                    "The deprecation executor property for the TokenNetworkRegistry is invalid."
                )

            if chain_id == 0:
                raise RaidenUnrecoverableError(
                    "The chain ID property for the TokenNetworkRegistry is invalid."
                )

            if chain_id != self.rpc_client.chain_id:
                raise RaidenUnrecoverableError(
                    f"The provided chain ID {chain_id} does not match the "
                    f"network Raiden is running on: {self.rpc_client.chain_id}."
                )

            if secret_registry_address == NULL_ADDRESS_BYTES:
                raise RaidenUnrecoverableError(
                    "The secret registry address for the token network is invalid."
                )

            if settlement_timeout_min <= 0:
                raise RaidenUnrecoverableError(
                    "The minimum settlement timeout for the token network "
                    "should be larger than zero.")

            if settlement_timeout_max <= settlement_timeout_min:
                raise RaidenUnrecoverableError(
                    "The maximum settlement timeout for the token network "
                    "should be larger than the minimum settlement timeout.")

            total_supply = token_proxy.total_supply(
                block_identifier=failed_at_blocknumber)
            if not total_supply or total_supply <= 0:
                raise RaidenRecoverableError(
                    f"The given token address is not a valid ERC20 token, "
                    f"total_supply() returned an invalid value {total_supply}."
                )

            # At this point, the TokenNetworkRegistry fails to instantiate
            # a new TokenNetwork.
            raise RaidenUnrecoverableError(
                f"createERC20TokenNetwork gas estimation failed for an unknown "
                f"reason. Reference block {failed_at_blockhash} "
                f"{failed_at_blocknumber}.")
        return (
            TransactionHash(transaction_mined.transaction_hash),
            TokenNetworkAddress(token_network_address),
        )
Ejemplo n.º 9
0
 def get_deprecation_executor(self,
                              block_identifier: BlockIdentifier) -> Address:
     return Address(
         to_canonical_address(
             self.proxy.functions.deprecation_executor().call(
                 block_identifier=block_identifier)))
Ejemplo n.º 10
0
    def handle_message_lockedtransfer(
        raiden: "RaidenService", message: LockedTransfer  # pylint: disable=unused-argument
    ) -> List[StateChange]:
        secrethash = message.lock.secrethash
        # We must check if the secret was registered against the latest block,
        # even if the block is forked away and the transaction that registers
        # the secret is removed from the blockchain. The rationale here is that
        # someone else does know the secret, regardless of the chain state, so
        # the node must not use it to start a payment.
        #
        # For this particular case, it's preferable to use `latest` instead of
        # having a specific block_hash, because it's preferable to know if the secret
        # was ever known, rather than having a consistent view of the blockchain.
        registered = raiden.default_secret_registry.is_secret_registered(
            secrethash=secrethash, block_identifier=BLOCK_ID_LATEST
        )
        if registered:
            log.warning(
                f"Ignoring received locked transfer with secrethash {to_hex(secrethash)} "
                f"since it is already registered in the secret registry"
            )
            return []

        assert message.sender, "Invalid message dispatched, it should be signed"

        if message.target == TargetAddress(raiden.address):
            raiden.immediate_health_check_for(Address(message.initiator))

            from_transfer = lockedtransfersigned_from_message(message)
            from_hop = HopState(
                node_address=message.sender,
                # pylint: disable=E1101
                channel_identifier=from_transfer.balance_proof.channel_identifier,
            )
            init_target_statechange = ActionInitTarget(
                from_hop=from_hop,
                transfer=from_transfer,
                balance_proof=from_transfer.balance_proof,
                sender=from_transfer.balance_proof.sender,  # pylint: disable=no-member
            )
            return [init_target_statechange]
        else:
            from_transfer = lockedtransfersigned_from_message(message)
            from_hop = HopState(
                message.sender,
                from_transfer.balance_proof.channel_identifier,  # pylint: disable=E1101
            )
            token_network_address = (
                from_transfer.balance_proof.token_network_address  # pylint: disable=E1101
            )
            route_states = routing.resolve_routes(
                routes=message.metadata.routes,
                token_network_address=token_network_address,
                chain_state=views.state_from_raiden(raiden),
            )
            init_mediator_statechange = ActionInitMediator(
                from_hop=from_hop,
                route_states=route_states,
                from_transfer=from_transfer,
                balance_proof=from_transfer.balance_proof,
                sender=from_transfer.balance_proof.sender,  # pylint: disable=no-member
            )
            return [init_mediator_statechange]
Ejemplo n.º 11
0
from raiden.tests.utils import factories
from raiden.tests.utils.tests import fixture_all_combinations
from raiden.transfer.mediated_transfer.mediation_fee import FeeScheduleState
from raiden.transfer.mediated_transfer.state_change import (
    ReceiveLockExpired,
    ReceiveSecretRequest,
    ReceiveSecretReveal,
)
from raiden.transfer.state_change import ReceiveDelivered, ReceiveProcessed, ReceiveUnlock
from raiden.utils import sha3
from raiden.utils.packing import pack_balance_proof, pack_reward_proof, pack_signed_balance_proof
from raiden.utils.signer import LocalSigner, recover
from raiden.utils.typing import Address, TokenAmount
from raiden_contracts.constants import MessageTypeId

MSC_ADDRESS = Address(bytes([1] * 20))
PARTNER_PRIVKEY, PARTNER_ADDRESS = factories.make_privkey_address()
PRIVKEY, ADDRESS = factories.make_privkey_address()
signer = LocalSigner(PRIVKEY)


def test_signature():
    ping = Ping(nonce=0, current_protocol_version=0, signature=EMPTY_SIGNATURE)
    ping.sign(signer)
    assert ping.sender == ADDRESS


def test_request_monitoring() -> None:
    properties = factories.BalanceProofSignedStateProperties(pkey=PARTNER_PRIVKEY)
    balance_proof = factories.create(properties)
    partner_signed_balance_proof = SignedBlindedBalanceProof.from_balance_proof_signed_state(
Ejemplo n.º 12
0
def public_key_to_address(public_key: PublicKey) -> Address:
    """Converts a public key to an Ethereum address."""
    key_bytes = public_key.format(compressed=False)
    return Address(keccak(key_bytes[1:])[-20:])
Ejemplo n.º 13
0
    TokenAmount,
    TokenNetworkRegistryAddress,
)
from raiden_contracts.constants import (
    CONTRACT_SECRET_REGISTRY,
    CONTRACT_SERVICE_REGISTRY,
    CONTRACT_TOKEN_NETWORK_REGISTRY,
    CONTRACT_USER_DEPOSIT,
)
from raiden_contracts.utils.type_aliases import ChainID

token_network_registry_address_test_default = TokenNetworkRegistryAddress(
    to_canonical_address("0xB9633dd9a9a71F22C933bF121d7a22008f66B908")
)
user_deposit_address_test_default = Address(
    to_canonical_address("0x8888888888888888888888888888888888888888")
)

pfs_payment_address_default = to_canonical_address("0xB9633dd9a9a71F22C933bF121d7a22008f66B907")

PFS_INFO = PFSInfo(
    url="my-pfs",
    price=TokenAmount(12),
    chain_id=ChainID(5),
    token_network_registry_address=token_network_registry_address_test_default,
    user_deposit_address=user_deposit_address_test_default,
    payment_address=pfs_payment_address_default,
    confirmed_block_number=BlockNumber(1),
    message="This is your favorite pathfinding service",
    operator="John Doe",
    version="0.0.3",
Ejemplo n.º 14
0
def test_crash(tmpdir, mockchain):  # pylint: disable=too-many-locals
    """ Process blocks and compare results with/without crash

    A somewhat meaninful crash handling is simulated by not including the
    UpdatedHeadBlockEvent in every block.
    """
    token_address = Address(bytes([1] * 20))
    token_network_address = TokenNetworkAddress(bytes([2] * 20))
    channel_id = ChannelID(1)
    p1 = Address(bytes([3] * 20))
    p2 = Address(bytes([4] * 20))
    events = [
        [
            ReceiveTokenNetworkCreatedEvent(
                token_address=token_address,
                token_network_address=token_network_address,
                block_number=BlockNumber(1),
            )
        ],
        [UpdatedHeadBlockEvent(BlockNumber(2))],
        [
            ReceiveChannelOpenedEvent(
                token_network_address=token_network_address,
                channel_identifier=channel_id,
                participant1=p1,
                participant2=p2,
                settle_timeout=1000,
                block_number=BlockNumber(3),
            )
        ],
        [UpdatedHeadBlockEvent(BlockNumber(4))],
    ]
    mockchain(events)

    server_private_key = get_random_privkey()
    contracts = {
        CONTRACT_TOKEN_NETWORK_REGISTRY: ContractMock(),
        CONTRACT_USER_DEPOSIT: ContractMock(),
    }

    def new_service(filename):
        service = PathfindingService(
            web3=Web3Mock(),
            private_key=server_private_key,
            contracts=contracts,
            db_filename=os.path.join(tmpdir, filename),
        )
        return service

    # initialize stable service
    stable_service = new_service("stable.db")

    # process each block and compare results between crashy and stable service
    for to_block in range(len(events)):
        crashy_service = new_service(
            "crashy.db")  # new instance to simulate crash
        result_state: List[dict] = []
        for service in [stable_service, crashy_service]:
            service._process_new_blocks(BlockNumber(to_block))  # pylint: disable=protected-access
            result_state.append(
                dict(db_dump=list(service.database.conn.iterdump())))

        # both instances should have the same state after processing
        for stable_state, crashy_state in zip(result_state[0].values(),
                                              result_state[1].values()):
            # do asserts for each key separately to get better error messages
            assert stable_state == crashy_state
Ejemplo n.º 15
0
def test_register_secret_happy_path(
    secret_registry_proxy: SecretRegistry, contract_manager: ContractManager
) -> None:
    """Test happy path of SecretRegistry with a single secret.

    Test that `register_secret` changes the smart contract state by registering
    the secret, this can be verified by the block height and the existence of
    the SecretRegistered event.
    """
    secret = make_secret()
    secrethash = sha256_secrethash(secret)
    secret_unregistered = make_secret()
    secrethash_unregistered = sha256_secrethash(secret_unregistered)

    assert not secret_registry_proxy.is_secret_registered(
        secrethash=secrethash, block_identifier=BLOCK_ID_LATEST
    ), "Test setup is invalid, secret must be unknown"
    assert not secret_registry_proxy.is_secret_registered(
        secrethash=secrethash_unregistered, block_identifier=BLOCK_ID_LATEST
    ), "Test setup is invalid, secret must be unknown"

    secret_registry_proxy.client.wait_until_block(BlockNumber(STATE_PRUNING_AFTER_BLOCKS + 1))

    with pytest.raises(NoStateForBlockIdentifier):
        secret_registry_proxy.is_secret_registered(
            secrethash=secrethash_unregistered, block_identifier=BlockNumber(0)
        )

    secret_registry_proxy.register_secret(secret=secret)

    proxy_manager = ProxyManager(
        rpc_client=secret_registry_proxy.client,
        contract_manager=contract_manager,
        metadata=ProxyManagerMetadata(
            token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER,
            filters_start_at=GENESIS_BLOCK_NUMBER,
        ),
    )
    logs = get_contract_events(
        proxy_manager=proxy_manager,
        abi=proxy_manager.contract_manager.get_contract_abi(CONTRACT_SECRET_REGISTRY),
        contract_address=Address(secret_registry_proxy.address),
    )
    secret_registered = must_have_event(
        logs, {"event": "SecretRevealed", "args": {"secrethash": secrethash}}
    )

    msg = "SecretRegistry.register_secret returned but the SecretRevealed event was not emitted."
    assert secret_registered, msg

    registered_block = secret_registry_proxy.get_secret_registration_block_by_secrethash(
        secrethash=secrethash, block_identifier=BLOCK_ID_LATEST
    )
    msg = (
        "Block height returned by the SecretRegistry.get_secret_registration_block_by_secrethash "
        "does not match the block from the SecretRevealed event."
    )
    assert secret_registered["block_number"] == registered_block, msg

    block = secret_registry_proxy.get_secret_registration_block_by_secrethash(
        secrethash=secrethash_unregistered, block_identifier=BLOCK_ID_LATEST
    )
    assert block is None, "The secret that was not registered must not change block height!"
Ejemplo n.º 16
0
def test_payment_statuses_are_restored(  # pylint: disable=unused-argument
        raiden_network: List[App], token_addresses: List[TokenAddress],
        network_wait: float):
    """ Test that when the Raiden is restarted, the dictionary of
    `targets_to_identifiers_to_statuses` is populated before the transport
    is started.
    This should happen because if a client gets restarted during a transfer
    cycle, once restarted, the client will proceed with the cycle
    until the transfer is successfully sent. However, the dictionary
    `targets_to_identifiers_to_statuses` will not contain the payment
    identifiers that were originally registered when the previous client
    started the transfers.
    Related issue: https://github.com/raiden-network/raiden/issues/3432
    """
    app0, app1 = raiden_network

    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state, token_network_registry_address, token_address)
    assert token_network_address

    target_address = TargetAddress(app1.raiden.address)

    # make a few transfers from app0 to app1
    amount = PaymentAmount(1)
    spent_amount = TokenAmount(7)

    for identifier in range(spent_amount):
        # Make sure the transfer is not completed
        secret = make_secret(identifier)

        assert isinstance(app0.raiden.raiden_event_handler,
                          HoldRaidenEventHandler)  # for mypy
        app0.raiden.raiden_event_handler.hold(SendSecretReveal,
                                              {"secret": secret})

        identifier = identifier + 1
        payment_status = app0.raiden.mediated_transfer_async(
            token_network_address=token_network_address,
            amount=amount,
            target=target_address,
            identifier=PaymentID(identifier),
            secret=secret,
        )
        assert payment_status.payment_identifier == identifier

    app0_restart = App(
        config=app0.config,
        rpc_client=app0.raiden.rpc_client,
        proxy_manager=app0.raiden.proxy_manager,
        query_start_block=BlockNumber(0),
        default_registry=app0.raiden.default_registry,
        default_secret_registry=app0.raiden.default_secret_registry,
        default_service_registry=app0.raiden.default_service_registry,
        default_one_to_n_address=app0.raiden.default_one_to_n_address,
        default_msc_address=app0.raiden.default_msc_address,
        transport=MatrixTransport(
            config=app0.raiden.config.transport,
            environment=app0.raiden.config.environment_type),
        raiden_event_handler=RaidenEventHandler(),
        message_handler=MessageHandler(),
        routing_mode=RoutingMode.PRIVATE,
    )
    app0.stop()
    del app0  # from here on the app0_restart should be used
    # stop app1 to make sure that we don't complete the transfers before our checks
    app1.stop()
    app0_restart.start()

    # Check that the payment statuses were restored properly after restart
    for identifier in range(spent_amount):
        identifier = PaymentID(identifier + 1)
        mapping = app0_restart.raiden.targets_to_identifiers_to_statuses
        status = mapping[target_address][identifier]
        assert status.amount == 1
        assert status.payment_identifier == identifier
        assert status.token_network_address == token_network_address

    app1.start()  # now that our checks are done start app1 again

    with watch_for_unlock_failures(*raiden_network):
        waiting.wait_for_healthy(app0_restart.raiden, app1.raiden.address,
                                 network_wait)

        waiting.wait_for_payment_balance(
            raiden=app1.raiden,
            token_network_registry_address=token_network_registry_address,
            token_address=token_address,
            partner_address=app0_restart.raiden.address,
            target_address=Address(target_address),
            target_balance=spent_amount,
            retry_timeout=network_wait,
        )

    # Check that payments are completed after both nodes come online after restart
    for identifier in range(spent_amount):
        assert raiden_events_search_for_item(
            app0_restart.raiden,
            EventPaymentSentSuccess,
            {
                "identifier": identifier + 1,
                "amount": 1
            },
        )
Ejemplo n.º 17
0
def get_best_routes(
    chain_state: ChainState,
    token_network_id: TokenNetworkID,
    one_to_n_address: Optional[Address],
    from_address: InitiatorAddress,
    to_address: TargetAddress,
    amount: PaymentAmount,
    previous_address: Optional[Address],
    config: Dict[str, Any],
    privkey: bytes,
) -> Tuple[List[RouteState], Optional[UUID]]:
    services_config = config.get("services", None)

    # the pfs should not be requested when the target is linked via a direct channel
    if to_address in views.all_neighbour_nodes(chain_state):
        neighbours = get_best_routes_internal(
            chain_state=chain_state,
            token_network_id=token_network_id,
            from_address=from_address,
            to_address=to_address,
            amount=amount,
            previous_address=previous_address,
        )
        channel_state = views.get_channelstate_by_token_network_and_partner(
            chain_state=chain_state,
            token_network_id=token_network_id,
            partner_address=Address(to_address),
        )

        for route_state in neighbours:
            if to_address == route_state.node_address and (
                    channel_state
                    # other conditions about e.g. channel state are checked in best routes internal
                    and channel.get_distributable(
                        sender=channel_state.our_state,
                        receiver=channel_state.partner_state) >= amount):
                return [route_state], None

    if (services_config
            and services_config["pathfinding_service_address"] is not None
            and one_to_n_address is not None):
        pfs_answer_ok, pfs_routes, pfs_feedback_token = get_best_routes_pfs(
            chain_state=chain_state,
            token_network_id=token_network_id,
            one_to_n_address=one_to_n_address,
            from_address=from_address,
            to_address=to_address,
            amount=amount,
            previous_address=previous_address,
            config=services_config,
            privkey=privkey,
        )

        if pfs_answer_ok:
            log.info("Received route(s) from PFS",
                     routes=pfs_routes,
                     feedback_token=pfs_feedback_token)
            return pfs_routes, pfs_feedback_token
        else:
            log.warning("Request to Pathfinding Service was not successful, "
                        "falling back to internal routing.")

    return (
        get_best_routes_internal(
            chain_state=chain_state,
            token_network_id=token_network_id,
            from_address=from_address,
            to_address=to_address,
            amount=amount,
            previous_address=previous_address,
        ),
        None,
    )
Ejemplo n.º 18
0
def deploy_smoketest_contracts(
    client: JSONRPCClient,
    chain_id: ChainID,
    contract_manager: ContractManager,
    token_address: AddressHex,
) -> Dict[str, Address]:
    if client.eth_node is EthClient.GETH:
        client.web3.geth.personal.unlockAccount(client.web3.eth.accounts[0],
                                                DEFAULT_PASSPHRASE)
    elif client.eth_node is EthClient.PARITY:
        client.web3.parity.personal.unlockAccount(client.web3.eth.accounts[0],
                                                  DEFAULT_PASSPHRASE)

    contract_proxy, _ = client.deploy_single_contract(
        contract_name=CONTRACT_SECRET_REGISTRY,
        contract=contract_manager.get_contract(CONTRACT_SECRET_REGISTRY),
        constructor_parameters=None,
    )
    secret_registry_address = Address(
        to_canonical_address(contract_proxy.address))

    secret_registry_constructor_arguments = (
        to_checksum_address(secret_registry_address),
        chain_id,
        TEST_SETTLE_TIMEOUT_MIN,
        TEST_SETTLE_TIMEOUT_MAX,
        UINT256_MAX,
    )

    contract_proxy, _ = client.deploy_single_contract(
        contract_name=CONTRACT_TOKEN_NETWORK_REGISTRY,
        contract=contract_manager.get_contract(
            CONTRACT_TOKEN_NETWORK_REGISTRY),
        constructor_parameters=secret_registry_constructor_arguments,
    )
    token_network_registry_address = Address(
        to_canonical_address(contract_proxy.address))

    service_registry_constructor_arguments = (
        token_address,
        EMPTY_ADDRESS,
        int(500e18),
        6,
        5,
        180 * SECONDS_PER_DAY,
        1000,
        200 * SECONDS_PER_DAY,
    )
    service_registry_contract, _ = client.deploy_single_contract(
        contract_name=CONTRACT_SERVICE_REGISTRY,
        contract=contract_manager.get_contract(CONTRACT_SERVICE_REGISTRY),
        constructor_parameters=service_registry_constructor_arguments,
    )
    service_registry_address = Address(
        to_canonical_address(service_registry_contract.address))

    user_deposit_contract, _ = client.deploy_single_contract(
        contract_name=CONTRACT_USER_DEPOSIT,
        contract=contract_manager.get_contract(CONTRACT_USER_DEPOSIT),
        constructor_parameters=(token_address, UINT256_MAX),
    )
    user_deposit_address = Address(
        to_canonical_address(user_deposit_contract.address))

    monitoring_service_contract, _ = client.deploy_single_contract(
        contract_name=CONTRACT_MONITORING_SERVICE,
        contract=contract_manager.get_contract(CONTRACT_MONITORING_SERVICE),
        constructor_parameters=(
            token_address,
            service_registry_address,
            user_deposit_address,
            token_network_registry_address,
        ),
    )
    monitoring_service_address = Address(
        to_canonical_address(monitoring_service_contract.address))

    one_to_n_contract, _ = client.deploy_single_contract(
        contract_name=CONTRACT_ONE_TO_N,
        contract=contract_manager.get_contract(CONTRACT_ONE_TO_N),
        constructor_parameters=(user_deposit_address, chain_id,
                                service_registry_address),
    )
    one_to_n_address = Address(to_canonical_address(one_to_n_contract.address))

    proxy_manager = ProxyManager(
        rpc_client=client,
        contract_manager=contract_manager,
        metadata=ProxyManagerMetadata(
            token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER,
            filters_start_at=GENESIS_BLOCK_NUMBER,
        ),
    )
    user_deposit_proxy = UserDeposit(
        jsonrpc_client=client,
        user_deposit_address=UserDepositAddress(
            to_canonical_address(user_deposit_contract.address)),
        contract_manager=contract_manager,
        proxy_manager=proxy_manager,
        block_identifier=BLOCK_ID_LATEST,
    )
    transaction_hash = user_deposit_proxy.init(
        monitoring_service_address=MonitoringServiceAddress(
            monitoring_service_address),
        one_to_n_address=OneToNAddress(one_to_n_address),
        given_block_identifier=BLOCK_ID_LATEST,
    )
    assert is_tx_hash_bytes(transaction_hash)

    addresses = {
        CONTRACT_SECRET_REGISTRY: secret_registry_address,
        CONTRACT_TOKEN_NETWORK_REGISTRY: token_network_registry_address,
        CONTRACT_SERVICE_REGISTRY: service_registry_address,
        CONTRACT_USER_DEPOSIT: user_deposit_address,
        CONTRACT_MONITORING_SERVICE: monitoring_service_address,
        CONTRACT_ONE_TO_N: one_to_n_address,
    }

    return addresses
Ejemplo n.º 19
0
from raiden.utils.typing import Address

KEYSTORE_FILE_NAME = "keystore.txt"
KEYSTORE_PASSWORD = "******"
TEST_MSC_ADDRESS = Address(b"9" * 20)
Ejemplo n.º 20
0
def run_smoketest(print_step: StepPrinter, setup: RaidenTestSetup) -> None:
    print_step("Starting Raiden")

    app = None
    try:
        app = run_raiden_service(**setup.args)
        raiden_api = app.raiden_api
        assert raiden_api is not None  # for mypy
        partner_address = Address(b"1" * 20)

        block = BlockNumber(app.get_block_number() +
                            DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS)
        # Proxies now use the confirmed block hash to query the chain for
        # prerequisite checks. Wait a bit here to make sure that the confirmed
        # block hash contains the deployed token network or else things break
        wait_for_block(raiden=app, block_number=block, retry_timeout=1.0)

        raiden_api.channel_open(
            registry_address=TokenNetworkRegistryAddress(
                setup.contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]),
            token_address=TokenAddress(
                to_canonical_address(setup.token.address)),
            partner_address=partner_address,
        )
        raiden_api.set_total_channel_deposit(
            registry_address=TokenNetworkRegistryAddress(
                setup.contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]),
            token_address=TokenAddress(
                to_canonical_address(setup.token.address)),
            partner_address=partner_address,
            total_deposit=TEST_DEPOSIT_AMOUNT,
        )
        token_addresses = [to_checksum_address(setup.token.address)
                           ]  # type: ignore

        print_step("Running smoketest")

        raiden_service = app
        token_network_added_events = raiden_service.default_registry.filter_token_added_events(
        )
        events_token_addresses = [
            event["args"]["token_address"]
            for event in token_network_added_events
        ]

        assert events_token_addresses == token_addresses

        token_networks = views.get_token_identifiers(
            views.state_from_raiden(raiden_service),
            raiden_service.default_registry.address)
        assert len(token_networks) == 1

        channel_state = views.get_channelstate_for(
            chain_state=views.state_from_raiden(raiden_service),
            token_network_registry_address=raiden_service.default_registry.
            address,
            token_address=token_networks[0],
            partner_address=partner_address,
        )
        assert channel_state

        distributable = channel.get_distributable(channel_state.our_state,
                                                  channel_state.partner_state)
        assert distributable == TEST_DEPOSIT_AMOUNT
        assert Balance(
            distributable) == channel_state.our_state.contract_balance
        assert channel.get_status(channel_state) == ChannelState.STATE_OPENED

        port_number = raiden_service.config.rest_api.port
        response = requests.get(
            f"http://localhost:{port_number}/api/v1/channels")

        assert response.status_code == HTTPStatus.OK

        response_json = json.loads(response.content)
        assert response_json[0]["partner_address"] == to_checksum_address(
            partner_address)
        assert response_json[0]["state"] == "opened"
        assert int(response_json[0]["balance"]) > 0
    finally:
        if app is not None:
            app.stop()
            app.greenlet.get()
Ejemplo n.º 21
0
def get_best_routes(
    chain_state: ChainState,
    token_network_address: TokenNetworkAddress,
    one_to_n_address: Optional[OneToNAddress],
    from_address: InitiatorAddress,
    to_address: TargetAddress,
    amount: PaymentAmount,
    previous_address: Optional[Address],
    pfs_config: Optional[PFSConfig],
    privkey: PrivateKey,
) -> Tuple[Optional[str], List[RouteState], Optional[UUID]]:

    token_network = views.get_token_network_by_address(chain_state,
                                                       token_network_address)
    assert token_network, "The token network must be validated and exist."

    # Always use a direct channel if available:
    # - There are no race conditions and the capacity is guaranteed to be
    #   available.
    # - There will be no mediation fees
    # - The transfer will be faster
    if Address(
            to_address
    ) in token_network.partneraddresses_to_channelidentifiers.keys():
        for channel_id in token_network.partneraddresses_to_channelidentifiers[
                Address(to_address)]:
            channel_state = token_network.channelidentifiers_to_channels[
                channel_id]

            # direct channels don't have fees
            payment_with_fee_amount = PaymentWithFeeAmount(amount)
            is_usable = channel.is_channel_usable_for_new_transfer(
                channel_state, payment_with_fee_amount, None)

            if is_usable is channel.ChannelUsability.USABLE:
                direct_route = RouteState(
                    route=[Address(from_address),
                           Address(to_address)],
                    estimated_fee=FeeAmount(0))
                return None, [direct_route], None

    if pfs_config is None or one_to_n_address is None:
        log.warning("Pathfinding Service could not be used.")
        return "Pathfinding Service could not be used.", list(), None

    # Does any channel have sufficient capacity for the payment?
    channels = [
        token_network.channelidentifiers_to_channels[channel_id]
        for channels_to_partner in
        token_network.partneraddresses_to_channelidentifiers.values()
        for channel_id in channels_to_partner
    ]
    for channel_state in channels:
        payment_with_fee_amount = PaymentWithFeeAmount(amount)
        is_usable = channel.is_channel_usable_for_new_transfer(
            channel_state, payment_with_fee_amount, None)
        if is_usable is channel.ChannelUsability.USABLE:
            break
    else:
        return ("You have no suitable channel to initiate this payment.",
                list(), None)

    # Make sure that the PFS knows about the last channel we opened
    latest_channel_opened_at = 0
    for channel_state in token_network.channelidentifiers_to_channels.values():
        latest_channel_opened_at = max(
            latest_channel_opened_at,
            channel_state.open_transaction.finished_block_number)

    pfs_error_msg, pfs_routes, pfs_feedback_token = get_best_routes_pfs(
        chain_state=chain_state,
        token_network_address=token_network_address,
        one_to_n_address=one_to_n_address,
        from_address=from_address,
        to_address=to_address,
        amount=amount,
        previous_address=previous_address,
        pfs_config=pfs_config,
        privkey=privkey,
        pfs_wait_for_block=BlockNumber(latest_channel_opened_at),
    )

    if pfs_error_msg:
        log.warning(
            "Request to Pathfinding Service was not successful. "
            "No routes to the target were found.",
            pfs_message=pfs_error_msg,
        )
        return pfs_error_msg, list(), None

    if not pfs_routes:
        # As of version 0.5 it is possible for the PFS to return an empty
        # list of routes without an error message.
        return "PFS could not find any routes", list(), None

    log.info("Received route(s) from PFS",
             routes=pfs_routes,
             feedback_token=pfs_feedback_token)
    return pfs_error_msg, pfs_routes, pfs_feedback_token
Ejemplo n.º 22
0
def make_receive_transfer_mediated(
    channel_state: NettingChannelState,
    privkey: bytes,
    nonce: Nonce,
    transferred_amount: TokenAmount,
    lock: HashTimeLockState,
    pending_locks: PendingLocksState = None,
    locked_amount: Optional[PaymentWithFeeAmount] = None,
    chain_id: Optional[ChainID] = None,
) -> LockedTransferSignedState:

    typecheck(lock, HashTimeLockState)

    signer = LocalSigner(privkey)
    address = signer.address
    if address not in (channel_state.our_state.address,
                       channel_state.partner_state.address):
        raise ValueError("Private key does not match any of the participants.")

    if pending_locks is None:
        locks = make_empty_pending_locks_state()
        locks.locks.append(lock.encoded)
    else:
        assert bytes(lock.encoded) in pending_locks.locks
        locks = pending_locks

    if locked_amount is None:
        locked_amount = lock.amount

    assert locked_amount >= lock.amount

    locksroot = compute_locksroot(locks)

    payment_identifier = PaymentID(nonce)
    transfer_target = make_target_address()
    transfer_initiator = make_initiator_address()
    chain_id = chain_id or channel_state.chain_id

    transfer_metadata = Metadata(routes=[
        RouteMetadata(
            route=[channel_state.our_state.address,
                   Address(transfer_target)])
    ])

    mediated_transfer_msg = LockedTransfer(
        chain_id=chain_id,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=nonce,
        token_network_address=channel_state.token_network_address,
        token=channel_state.token_address,
        channel_identifier=channel_state.identifier,
        transferred_amount=transferred_amount,
        locked_amount=TokenAmount(locked_amount),
        recipient=channel_state.partner_state.address,
        locksroot=locksroot,
        lock=Lock(amount=lock.amount,
                  expiration=lock.expiration,
                  secrethash=lock.secrethash),
        target=transfer_target,
        initiator=transfer_initiator,
        signature=EMPTY_SIGNATURE,
        fee=0,
        metadata=transfer_metadata,
    )
    mediated_transfer_msg.sign(signer)

    receive_lockedtransfer = LockedTransferSignedState(
        payment_identifier=payment_identifier,
        token=channel_state.token_address,
        lock=lock,
        initiator=transfer_initiator,
        target=transfer_target,
        message_identifier=make_message_identifier(),
        balance_proof=balanceproof_from_envelope(mediated_transfer_msg),
        routes=[
            route_metadata.route for route_metadata in transfer_metadata.routes
        ],
    )

    return receive_lockedtransfer
Ejemplo n.º 23
0
def mock_matrix(
    monkeypatch,
    mock_raiden_service,
    retry_interval_initial,
    retry_interval_max,
    retries_before_backoff,
):

    from raiden.network.transport.matrix.client import GMatrixClient
    from raiden.network.transport.matrix.utils import UserPresence
    from raiden.network.transport.matrix import transport as transport_module

    def make_client_monkey(handle_messages_callback,
                           handle_member_join_callback, servers, *args,
                           **kwargs):  # pylint: disable=unused-argument
        return GMatrixClient(
            handle_messages_callback=handle_messages_callback,
            handle_member_join_callback=handle_member_join_callback,
            base_url=servers[0],
        )

    monkeypatch.setattr(User, "get_display_name",
                        lambda _: "random_display_name")
    monkeypatch.setattr(transport_module, "make_client", make_client_monkey)

    def mock_get_room_ids_for_address(  # pylint: disable=unused-argument
            klass, address: Address) -> List[str]:
        return ["!roomID:server"]

    def mock_set_room_id_for_address(  # pylint: disable=unused-argument
            self, address: Address, room_id: Optional[str]):
        pass

    def mock_on_messages(messages):  # pylint: disable=unused-argument
        for message in messages:
            assert message
            assert message.sender

    def mock_get_user_presence(self, user_id: str):  # pylint: disable=unused-argument
        return UserPresence.ONLINE

    config = MatrixTransportConfig(
        broadcast_rooms=[],
        retries_before_backoff=retries_before_backoff,
        retry_interval_initial=retry_interval_initial,
        retry_interval_max=retry_interval_max,
        server="http://none",
        available_servers=[],
    )

    def mock_join_room(self, room_id_or_alias):
        raise MatrixRequestError(code=404,
                                 content={
                                     "errcode": "M_UNKNOWN",
                                     "error": "No known servers"
                                 })

    transport = MatrixTransport(config=config,
                                environment=Environment.DEVELOPMENT)
    transport._raiden_service = mock_raiden_service
    transport._stop_event.clear()
    transport._address_mgr.add_userid_for_address(Address(factories.HOP1),
                                                  USERID1)
    transport._client.user_id = USERID0

    monkeypatch.setattr(MatrixTransport, "_get_room_ids_for_address",
                        mock_get_room_ids_for_address)
    monkeypatch.setattr(MatrixTransport, "_set_room_id_for_address",
                        mock_set_room_id_for_address)
    monkeypatch.setattr(transport._raiden_service, "on_messages",
                        mock_on_messages)
    monkeypatch.setattr(GMatrixClient, "get_user_presence",
                        mock_get_user_presence)
    monkeypatch.setattr(GMatrixClient, "join_room", mock_join_room)

    monkeypatch.setattr(transport._client.api, "leave_room",
                        lambda room_id: None)
    monkeypatch.setattr(transport._client, "sync_token", "already_synced")

    return transport
Ejemplo n.º 24
0
    def _deposit_check_result(
        self,
        transaction_sent: Optional[TransactionSent],
        token: Token,
        beneficiary: Address,
        total_deposit: TokenAmount,
        amount_to_deposit: TokenAmount,
    ) -> None:
        if transaction_sent is None:
            failed_at = self.client.get_block(BLOCK_ID_LATEST)
            failed_at_blocknumber = failed_at["number"]

            self.client.check_for_insufficient_eth(
                transaction_name="deposit",
                transaction_executed=False,
                required_gas=self.gas_measurements["UserDeposit.deposit"],
                block_identifier=failed_at_blocknumber,
            )

            latest_deposit = self.get_total_deposit(
                address=beneficiary, block_identifier=failed_at_blocknumber
            )
            amount_to_deposit = TokenAmount(total_deposit - latest_deposit)

            allowance = token.allowance(
                owner=self.node_address,
                spender=Address(self.address),
                block_identifier=failed_at_blocknumber,
            )
            whole_balance = self.whole_balance(block_identifier=failed_at_blocknumber)
            whole_balance_limit = self.whole_balance_limit(block_identifier=failed_at_blocknumber)

            if allowance < amount_to_deposit:
                msg = (
                    "The allowance is insufficient. Check concurrent deposits "
                    "for the same user deposit but different proxies."
                )
                raise RaidenRecoverableError(msg)

            if token.balance_of(self.node_address, failed_at_blocknumber) < amount_to_deposit:
                msg = "The address doesnt have enough tokens"
                raise RaidenRecoverableError(msg)

            if latest_deposit < total_deposit:
                msg = "Deposit amount did not increase after deposit transaction"
                raise RaidenRecoverableError(msg)

            if whole_balance + amount_to_deposit > UINT256_MAX:
                msg = (
                    f"Current whole balance is {whole_balance}. "
                    f"The new deposit of {amount_to_deposit} would lead to an overflow."
                )
                raise RaidenRecoverableError(msg)

            if whole_balance + amount_to_deposit > whole_balance_limit:
                msg = (
                    f"Current whole balance is {whole_balance}. "
                    f"With the new deposit of {amount_to_deposit}, the deposit "
                    f"limit of {whole_balance_limit} would be exceeded."
                )
                raise RaidenRecoverableError(msg)

            raise RaidenRecoverableError("Deposit failed of unknown reason")

        else:
            transaction_mined = self.client.poll_transaction(transaction_sent)

            if not was_transaction_successfully_mined(transaction_mined):
                failed_at_blocknumber = BlockNumber(transaction_mined.receipt["blockNumber"])

                latest_deposit = self.get_total_deposit(
                    address=beneficiary, block_identifier=failed_at_blocknumber
                )
                amount_to_deposit = TokenAmount(total_deposit - latest_deposit)

                allowance = token.allowance(
                    owner=self.node_address,
                    spender=Address(self.address),
                    block_identifier=failed_at_blocknumber,
                )

                whole_balance = self.whole_balance(block_identifier=failed_at_blocknumber)
                whole_balance_limit = self.whole_balance_limit(
                    block_identifier=failed_at_blocknumber
                )

                if latest_deposit >= total_deposit:
                    msg = "Deposit amount already increased after another transaction"
                    raise RaidenRecoverableError(msg)

                if allowance < amount_to_deposit:
                    msg = (
                        "The allowance is insufficient. Check concurrent deposits "
                        "for the same token network but different proxies."
                    )
                    raise RaidenRecoverableError(msg)

                # Because we acquired the lock for the token, and the gas estimation succeeded,
                # We know that the account had enough balance for the deposit transaction.
                if token.balance_of(self.node_address, failed_at_blocknumber) < amount_to_deposit:
                    msg = (
                        "Transaction failed and balance decreased unexpectedly. "
                        "This could be a bug in Raiden or a mallicious "
                        "ERC20 Token."
                    )
                    raise RaidenRecoverableError(msg)

                if whole_balance + amount_to_deposit > UINT256_MAX:
                    msg = (
                        f"Current whole balance is {whole_balance}. "
                        f"The new deposit of {amount_to_deposit} caused an overflow."
                    )
                    raise RaidenRecoverableError(msg)

                if whole_balance + amount_to_deposit > whole_balance_limit:
                    msg = (
                        f"Current whole balance is {whole_balance}. "
                        f"With the new deposit of {amount_to_deposit}, the deposit "
                        f"limit of {whole_balance_limit} was exceeded."
                    )
                    raise RaidenRecoverableError(msg)

                if latest_deposit < total_deposit:
                    msg = "Deposit amount did not increase after deposit transaction"
                    raise RaidenRecoverableError(msg)

                raise RaidenRecoverableError("Deposit failed of unknown reason")
Ejemplo n.º 25
0
def token_minting_proxy(client: JSONRPCClient,
                        address: TokenAddress) -> ContractProxy:
    return client.new_contract_proxy(abi=_MINT_ABI,
                                     contract_address=Address(address))
Ejemplo n.º 26
0
def handle_secretrequest(
    initiator_state: InitiatorTransferState,
    state_change: ReceiveSecretRequest,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
) -> TransitionResult[InitiatorTransferState]:

    is_message_from_target = (
        state_change.sender == initiator_state.transfer_description.target
        and state_change.secrethash
        == initiator_state.transfer_description.secrethash
        and state_change.payment_identifier
        == initiator_state.transfer_description.payment_identifier)

    lock = channel.get_lock(channel_state.our_state,
                            initiator_state.transfer_description.secrethash)

    # This should not ever happen. This task clears itself when the lock is
    # removed.
    assert lock is not None, "channel is does not have the transfer's lock"

    already_received_secret_request = initiator_state.received_secret_request

    # transfer_description.amount is the actual payment amount without fees.
    # For the transfer to be valid and the unlock allowed the target must
    # receive at least that amount.
    is_valid_secretrequest = (
        state_change.amount >= initiator_state.transfer_description.amount
        and state_change.expiration == lock.expiration
        and initiator_state.transfer_description.secret != ABSENT_SECRET)

    if already_received_secret_request and is_message_from_target:
        # A secret request was received earlier, all subsequent are ignored
        # as it might be an attack
        iteration = TransitionResult(initiator_state, list())

    elif is_valid_secretrequest and is_message_from_target:
        # Reveal the secret to the target node and wait for its confirmation.
        # At this point the transfer is not cancellable anymore as either the lock
        # timeouts or a secret reveal is received.
        #
        # Note: The target might be the first hop
        #
        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        transfer_description = initiator_state.transfer_description
        recipient = transfer_description.target
        revealsecret = SendSecretReveal(
            recipient=Address(recipient),
            message_identifier=message_identifier,
            secret=transfer_description.secret,
            canonical_identifier=CANONICAL_IDENTIFIER_GLOBAL_QUEUE,
        )

        initiator_state.transfer_state = "transfer_secret_revealed"
        initiator_state.received_secret_request = True
        iteration = TransitionResult(initiator_state, [revealsecret])

    elif not is_valid_secretrequest and is_message_from_target:
        initiator_state.received_secret_request = True
        invalid_request = EventInvalidSecretRequest(
            payment_identifier=state_change.payment_identifier,
            intended_amount=initiator_state.transfer_description.amount,
            actual_amount=state_change.amount,
        )
        iteration = TransitionResult(initiator_state, [invalid_request])

    else:
        iteration = TransitionResult(initiator_state, list())

    return iteration
Ejemplo n.º 27
0
def handle_inittarget(
        state_change: ActionInitTarget,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
        block_number: BlockNumber,
) -> TransitionResult[Optional[TargetTransferState]]:
    """ Handles an ActionInitTarget state change. """
    transfer = state_change.transfer
    route = state_change.route

    assert channel_state.identifier == transfer.balance_proof.channel_identifier
    is_valid, channel_events, errormsg = channel.handle_receive_lockedtransfer(
        channel_state,
        transfer,
    )

    if is_valid:
        # A valid balance proof does not mean the payment itself is still valid.
        # e.g. the lock may be near expiration or have expired. This is fine. The
        # message with an unusable lock must be handled to properly synchronize the
        # local view of the partner's channel state, allowing the next balance
        # proofs to be handled. This however, must only be done once, which is
        # enforced by the nonce increasing sequentially, which is verified by
        # the handler handle_receive_lockedtransfer.
        target_state = TargetTransferState(route, transfer)

        safe_to_wait, _ = is_safe_to_wait(
            transfer.lock.expiration,
            channel_state.reveal_timeout,
            block_number,
        )

        # If there is not enough time to safely unlock the lock on-chain
        # silently let the transfer expire. The target task must be created to
        # handle the ReceiveLockExpired state change, which will clear the
        # expired lock.
        if safe_to_wait:
            message_identifier = message_identifier_from_prng(pseudo_random_generator)
            recipient = transfer.initiator
            secret_request = SendSecretRequest(
                recipient=Address(recipient),
                channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
                message_identifier=message_identifier,
                payment_identifier=transfer.payment_identifier,
                amount=transfer.lock.amount,
                expiration=transfer.lock.expiration,
                secrethash=transfer.lock.secrethash,
            )
            channel_events.append(secret_request)

        iteration = TransitionResult(target_state, channel_events)
    else:
        # If the balance proof is not valid, do *not* create a task. Otherwise it's
        # possible for an attacker to send multiple invalid transfers, and increase
        # the memory usage of this Node.
        unlock_failed = EventUnlockClaimFailed(
            identifier=transfer.payment_identifier,
            secrethash=transfer.lock.secrethash,
            reason=errormsg,
        )
        channel_events.append(unlock_failed)
        iteration = TransitionResult(None, channel_events)

    return iteration
Ejemplo n.º 28
0
def setup_proxies_or_exit(
    config: Dict[str, Any],
    tokennetwork_registry_contract_address: Address,
    secret_registry_contract_address: Address,
    endpoint_registry_contract_address: Address,
    user_deposit_contract_address: Address,
    service_registry_contract_address: Address,
    blockchain_service: BlockChainService,
    contracts: Dict[str, Any],
    routing_mode: RoutingMode,
    pathfinding_service_address: str,
) -> Proxies:
    """
    Initialize and setup the contract proxies.

    Depending on the provided contract addresses via the CLI, the routing mode,
    the environment type and the network id try to initialize the proxies.
    Returns the initialized proxies or exits the application with an error if
    there is a problem.

    Also depending on the given arguments populate config with PFS related settings
    """
    node_network_id = config["chain_id"]
    environment_type = config["environment_type"]

    check_smart_contract_addresses(
        environment_type,
        node_network_id,
        tokennetwork_registry_contract_address,
        secret_registry_contract_address,
        endpoint_registry_contract_address,
        contracts,
    )
    try:
        registered_address: Address
        if tokennetwork_registry_contract_address is not None:
            registered_address = Address(
                tokennetwork_registry_contract_address)
        else:
            registered_address = to_canonical_address(
                contracts[CONTRACT_TOKEN_NETWORK_REGISTRY]["address"])
        token_network_registry = blockchain_service.token_network_registry(
            registered_address)
    except ContractVersionMismatch as e:
        handle_contract_version_mismatch(e)
    except AddressWithoutCode:
        handle_contract_no_code("token network registry",
                                tokennetwork_registry_contract_address)
    except AddressWrongContract:
        handle_contract_wrong_address("token network registry",
                                      tokennetwork_registry_contract_address)

    try:
        secret_registry = blockchain_service.secret_registry(
            secret_registry_contract_address or to_canonical_address(
                contracts[CONTRACT_SECRET_REGISTRY]["address"]))
    except ContractVersionMismatch as e:
        handle_contract_version_mismatch(e)
    except AddressWithoutCode:
        handle_contract_no_code("secret registry",
                                secret_registry_contract_address)
    except AddressWrongContract:
        handle_contract_wrong_address("secret registry",
                                      secret_registry_contract_address)

    # If services contracts are provided via the CLI use them instead
    if user_deposit_contract_address is not None:
        contracts[CONTRACT_USER_DEPOSIT] = user_deposit_contract_address
    if service_registry_contract_address is not None:
        contracts[
            CONTRACT_SERVICE_REGISTRY] = service_registry_contract_address

    user_deposit = None
    should_use_user_deposit = (
        environment_type == Environment.DEVELOPMENT
        and ID_TO_NETWORKNAME.get(node_network_id) != "smoketest"
        and CONTRACT_USER_DEPOSIT in contracts)
    if should_use_user_deposit:
        try:
            user_deposit = blockchain_service.user_deposit(
                user_deposit_contract_address or to_canonical_address(
                    contracts[CONTRACT_USER_DEPOSIT]["address"]))
        except ContractVersionMismatch as e:
            handle_contract_version_mismatch(e)
        except AddressWithoutCode:
            handle_contract_no_code("user deposit",
                                    user_deposit_contract_address)
        except AddressWrongContract:
            handle_contract_wrong_address("user_deposit",
                                          user_deposit_contract_address)

    service_registry = None
    if CONTRACT_SERVICE_REGISTRY in contracts or service_registry_contract_address:
        try:
            service_registry = blockchain_service.service_registry(
                service_registry_contract_address or to_canonical_address(
                    contracts[CONTRACT_SERVICE_REGISTRY]["address"]))
        except ContractVersionMismatch as e:
            handle_contract_version_mismatch(e)
        except AddressWithoutCode:
            handle_contract_no_code("service registry",
                                    service_registry_contract_address)
        except AddressWrongContract:
            handle_contract_wrong_address("secret registry",
                                          service_registry_contract_address)

    if routing_mode == RoutingMode.PFS:
        check_pfs_configuration(routing_mode, environment_type,
                                service_registry, pathfinding_service_address)

        pfs_config = configure_pfs_or_exit(
            pfs_address=pathfinding_service_address,
            routing_mode=routing_mode,
            service_registry=service_registry,
        )
        msg = "Eth address of selected pathfinding service is unknown."
        assert pfs_config.eth_address is not None, msg
        config["services"]["pathfinding_service_address"] = pfs_config.url
        config["services"]["pathfinding_eth_address"] = pfs_config.eth_address
        config["services"]["pathfinding_fee"] = pfs_config.fee
    else:
        config["services"]["pathfinding_service_address"] = None
        config["services"]["pathfinding_eth_address"] = None

    proxies = Proxies(
        token_network_registry=token_network_registry,
        secret_registry=secret_registry,
        user_deposit=user_deposit,
        service_registry=service_registry,
    )
    return proxies
Ejemplo n.º 29
0
                    "presence": presence.value
                },
            }
            self._presence_callback(event, next(self._presence_update_ids))


class NonValidatingUserAddressManager(UserAddressManager):
    @staticmethod
    def _validate_userid_signature(user: User) -> Optional[Address]:
        match = USERID_RE.match(user.user_id)
        if not match:
            return None
        return to_canonical_address(match.group(1))


ADDR1 = Address(b"\x11" * 20)
ADDR2 = Address(b'""""""""""""""""""""')
INVALID_USER_ID = "bla:bla"
USER0_ID = "@0x0000000000000000000000000000000000000000:server1"
USER1_S1_ID = "@0x1111111111111111111111111111111111111111:server1"
USER1_S2_ID = "@0x1111111111111111111111111111111111111111:server2"
USER2_S1_ID = "@0x2222222222222222222222222222222222222222:server1"
USER2_S2_ID = "@0x2222222222222222222222222222222222222222:server2"
USER1_S1 = User(api=None, user_id=USER1_S1_ID)
USER1_S2 = User(api=None, user_id=USER1_S2_ID)
USER2_S1 = User(api=None, user_id=USER2_S1_ID)
USER2_S2 = User(api=None, user_id=USER2_S2_ID)


@pytest.fixture
def user_directory_content():
Ejemplo n.º 30
0
    def set_total_channel_deposit(
        self,
        registry_address: TokenNetworkRegistryAddress,
        token_address: TokenAddress,
        partner_address: Address,
        total_deposit: TokenAmount,
        retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT,
    ) -> None:
        """ Set the `total_deposit` in the channel with the peer at `partner_address` and the
        given `token_address` in order to be able to do transfers.

        Raises:
            InvalidBinaryAddress: If either token_address or partner_address is not
                20 bytes long.
            RaidenRecoverableError: May happen for multiple reasons:
                - If the token approval fails, e.g. the token may validate if
                account has enough balance for the allowance.
                - The deposit failed, e.g. the allowance did not set the token
                aside for use and the user spent it before deposit was called.
                - The channel was closed/settled between the allowance call and
                the deposit call.
            AddressWithoutCode: The channel was settled during the deposit
                execution.
            DepositOverLimit: The total deposit amount is higher than the limit.
            UnexpectedChannelState: The channel is no longer in an open state.
        """
        chain_state = views.state_from_raiden(self.raiden)

        token_addresses = views.get_token_identifiers(chain_state,
                                                      registry_address)
        channel_state = views.get_channelstate_for(
            chain_state=chain_state,
            token_network_registry_address=registry_address,
            token_address=token_address,
            partner_address=partner_address,
        )

        if not is_binary_address(token_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for token in channel deposit")

        if not is_binary_address(partner_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for partner in channel deposit"
            )

        if token_address not in token_addresses:
            raise UnknownTokenAddress("Unknown token address")

        if channel_state is None:
            raise NonexistingChannel(
                "No channel with partner_address for the given token")

        confirmed_block_identifier = chain_state.block_hash
        token = self.raiden.proxy_manager.token(
            token_address, block_identifier=confirmed_block_identifier)
        token_network_registry = self.raiden.proxy_manager.token_network_registry(
            registry_address, block_identifier=confirmed_block_identifier)
        token_network_address = token_network_registry.get_token_network(
            token_address=token_address,
            block_identifier=confirmed_block_identifier)

        if token_network_address is None:
            raise UnknownTokenAddress(
                f"Token {to_checksum_address(token_address)} is not registered "
                f"with the network {to_checksum_address(registry_address)}.")

        token_network_proxy = self.raiden.proxy_manager.token_network(
            address=token_network_address,
            block_identifier=confirmed_block_identifier)
        channel_proxy = self.raiden.proxy_manager.payment_channel(
            channel_state=channel_state,
            block_identifier=confirmed_block_identifier)

        blockhash = chain_state.block_hash
        token_network_proxy = channel_proxy.token_network

        safety_deprecation_switch = token_network_proxy.safety_deprecation_switch(
            block_identifier=blockhash)

        balance = token.balance_of(self.raiden.address,
                                   block_identifier=blockhash)

        network_balance = token.balance_of(
            address=Address(token_network_address), block_identifier=blockhash)
        token_network_deposit_limit = token_network_proxy.token_network_deposit_limit(
            block_identifier=blockhash)

        addendum = total_deposit - channel_state.our_state.contract_balance

        channel_participant_deposit_limit = token_network_proxy.channel_participant_deposit_limit(
            block_identifier=blockhash)
        total_channel_deposit = total_deposit + channel_state.partner_state.contract_balance

        is_channel_open = channel.get_status(
            channel_state) == ChannelState.STATE_OPENED

        if not is_channel_open:
            raise UnexpectedChannelState("Channel is not in an open state.")

        if safety_deprecation_switch:
            msg = ("This token_network has been deprecated. "
                   "All channels in this network should be closed and "
                   "the usage of the newly deployed token network contract "
                   "is highly encouraged.")
            raise TokenNetworkDeprecated(msg)

        if total_deposit <= channel_state.our_state.contract_balance:
            raise DepositMismatch("Total deposit did not increase.")

        # If this check succeeds it does not imply the `deposit` will
        # succeed, since the `deposit` transaction may race with another
        # transaction.
        if not (balance >= addendum):
            msg = "Not enough balance to deposit. {} Available={} Needed={}".format(
                to_checksum_address(token_address), balance, addendum)
            raise InsufficientFunds(msg)

        if network_balance + addendum > token_network_deposit_limit:
            msg = f"Deposit of {addendum} would have exceeded the token network deposit limit."
            raise DepositOverLimit(msg)

        if total_deposit > channel_participant_deposit_limit:
            msg = (f"Deposit of {total_deposit} is larger than the "
                   f"channel participant deposit limit")
            raise DepositOverLimit(msg)

        if total_channel_deposit >= UINT256_MAX:
            raise DepositOverLimit("Deposit overflow")

        try:
            channel_proxy.approve_and_set_total_deposit(
                total_deposit=total_deposit, block_identifier=blockhash)
        except RaidenRecoverableError as e:
            log.info(f"Deposit failed. {str(e)}")

        target_address = self.raiden.address
        waiting.wait_for_participant_deposit(
            raiden=self.raiden,
            token_network_registry_address=registry_address,
            token_address=token_address,
            partner_address=partner_address,
            target_address=target_address,
            target_balance=total_deposit,
            retry_timeout=retry_timeout,
        )