예제 #1
0
def prepare_mediation_fee_config(
    cli_token_to_flat_fee: Tuple[Tuple[TokenAddress, FeeAmount], ...],
    cli_token_to_proportional_fee: Tuple[Tuple[TokenAddress,
                                               ProportionalFeeAmount], ...],
    cli_token_to_proportional_imbalance_fee: Tuple[Tuple[
        TokenAddress, ProportionalFeeAmount], ...],
    cli_cap_mediation_fees: bool,
) -> MediationFeeConfig:
    """Converts the mediation fee CLI args to proper per-channel
    mediation fees."""
    tn_to_flat_fee: Dict[TokenAddress, FeeAmount] = {
        # Add the defaults for flat fees for DAI/WETH
        WETH_TOKEN_ADDRESS: FeeAmount(DEFAULT_WETH_FLAT_FEE // 2),
        DAI_TOKEN_ADDRESS: FeeAmount(DEFAULT_DAI_FLAT_FEE // 2),
    }

    # Store the flat fee settings for the given token addresses
    # The given flat fee is for the whole mediation, but that includes two channels.
    # Therefore divide by 2 here.
    for address, fee in cli_token_to_flat_fee:
        tn_to_flat_fee[address] = FeeAmount(fee // 2)

    tn_to_proportional_fee: Dict[TokenAddress, ProportionalFeeAmount] = {
        address: ppm_fee_per_channel(prop_fee)
        for address, prop_fee in cli_token_to_proportional_fee
    }

    tn_to_proportional_imbalance_fee: Dict[
        TokenAddress, ProportionalFeeAmount] = {
            address: prop_fee
            for address, prop_fee in cli_token_to_proportional_imbalance_fee
        }

    return MediationFeeConfig(
        token_to_flat_fee=tn_to_flat_fee,
        token_to_proportional_fee=tn_to_proportional_fee,
        token_to_proportional_imbalance_fee=tn_to_proportional_imbalance_fee,
        cap_meditation_fees=cli_cap_mediation_fees,
    )
예제 #2
0
def create_apps(
    chain_id: ChainID,
    contracts_path: str,
    blockchain_services: BlockchainServices,
    token_network_registry_address: TokenNetworkRegistryAddress,
    one_to_n_address: Optional[Address],
    secret_registry_address: SecretRegistryAddress,
    service_registry_address: Optional[Address],
    user_deposit_address: Address,
    monitoring_service_contract_address: Address,
    reveal_timeout: BlockTimeout,
    settle_timeout: BlockTimeout,
    database_basedir: str,
    retry_interval: float,
    retries_before_backoff: int,
    environment_type: Environment,
    unrecoverable_error_should_crash: bool,
    local_matrix_url: Optional[ParsedURL],
    broadcast_rooms: List[str],
    routing_mode: RoutingMode,
    blockchain_query_interval: float,
    resolver_ports: List[Optional[int]],
) -> List[App]:
    """ Create the apps."""
    # pylint: disable=too-many-locals
    services = blockchain_services

    apps = []
    for idx, proxy_manager in enumerate(services):
        database_path = database_from_privatekey(base_dir=database_basedir,
                                                 app_number=idx)
        assert len(resolver_ports) > idx
        resolver_port = resolver_ports[idx]

        config = {
            "chain_id": chain_id,
            "environment_type": environment_type,
            "unrecoverable_error_should_crash":
            unrecoverable_error_should_crash,
            "reveal_timeout": reveal_timeout,
            "settle_timeout": settle_timeout,
            "contracts_path": contracts_path,
            "database_path": database_path,
            "blockchain": {
                "confirmation_blocks": DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS,
                "query_interval": blockchain_query_interval,
            },
            "transport": {},
            "rpc": True,
            "console": False,
            "mediation_fees": MediationFeeConfig(),
        }

        if local_matrix_url is not None:
            merge_dict(
                config,
                {
                    "transport_type": "matrix",
                    "transport": {
                        "matrix": {
                            "broadcast_rooms": broadcast_rooms,
                            "retries_before_backoff": retries_before_backoff,
                            "retry_interval": retry_interval,
                            "server": local_matrix_url,
                            "server_name": local_matrix_url.netloc,
                            "available_servers": [],
                        }
                    },
                },
            )

        if resolver_port is not None:
            merge_dict(config, {
                "resolver_endpoint":
                "http://localhost:" + str(resolver_port)
            })

        config_copy = deepcopy(App.DEFAULT_CONFIG)
        config_copy.update(config)

        registry = proxy_manager.token_network_registry(
            token_network_registry_address)
        secret_registry = proxy_manager.secret_registry(
            secret_registry_address)

        service_registry = None
        if service_registry_address:
            service_registry = proxy_manager.service_registry(
                service_registry_address)

        user_deposit = None
        if user_deposit_address:
            user_deposit = proxy_manager.user_deposit(user_deposit_address)

        transport = MatrixTransport(config["transport"]["matrix"])

        raiden_event_handler = RaidenEventHandler()
        hold_handler = HoldRaidenEventHandler(raiden_event_handler)
        message_handler = WaitForMessage()

        app = App(
            config=config_copy,
            rpc_client=proxy_manager.client,
            proxy_manager=proxy_manager,
            query_start_block=BlockNumber(0),
            default_registry=registry,
            default_one_to_n_address=one_to_n_address,
            default_secret_registry=secret_registry,
            default_service_registry=service_registry,
            default_msc_address=monitoring_service_contract_address,
            transport=transport,
            raiden_event_handler=hold_handler,
            message_handler=message_handler,
            user_deposit=user_deposit,
            routing_mode=routing_mode,
        )
        apps.append(app)

    return apps
예제 #3
0
def create_apps(
    chain_id: ChainID,
    contracts_path: Path,
    blockchain_services: BlockchainServices,
    token_network_registry_address: TokenNetworkRegistryAddress,
    one_to_n_address: Optional[OneToNAddress],
    secret_registry_address: SecretRegistryAddress,
    service_registry_address: Optional[ServiceRegistryAddress],
    user_deposit_address: Optional[UserDepositAddress],
    monitoring_service_contract_address: MonitoringServiceAddress,
    reveal_timeout: BlockTimeout,
    settle_timeout: BlockTimeout,
    database_basedir: str,
    retry_interval_initial: float,
    retry_interval_max: float,
    retries_before_backoff: int,
    environment_type: Environment,
    unrecoverable_error_should_crash: bool,
    local_matrix_url: Optional[ParsedURL],
    broadcast_rooms: List[str],
    routing_mode: RoutingMode,
    blockchain_query_interval: float,
    resolver_ports: List[Optional[int]],
    enable_rest_api: bool,
    port_generator: Iterator[Port],
    capabilities_config: CapabilitiesConfig,
) -> List[App]:
    """ Create the apps."""
    # pylint: disable=too-many-locals
    services = blockchain_services

    apps = []
    for idx, proxy_manager in enumerate(services):
        database_path = database_from_privatekey(base_dir=database_basedir,
                                                 app_number=idx)
        assert len(resolver_ports) > idx
        resolver_port = resolver_ports[idx]

        config = RaidenConfig(
            chain_id=chain_id,
            environment_type=environment_type,
            unrecoverable_error_should_crash=unrecoverable_error_should_crash,
            reveal_timeout=reveal_timeout,
            settle_timeout=settle_timeout,
            contracts_path=contracts_path,
            database_path=database_path,
            blockchain=BlockchainConfig(
                confirmation_blocks=DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS,
                query_interval=blockchain_query_interval,
            ),
            mediation_fees=MediationFeeConfig(),
            services=ServiceConfig(monitoring_enabled=False),
            rest_api=RestApiConfig(rest_api_enabled=enable_rest_api,
                                   host=Host("localhost"),
                                   port=next(port_generator)),
            console=False,
            transport_type="matrix",
        )
        config.transport.capabilities_config = capabilities_config

        if local_matrix_url is not None:
            config.transport = MatrixTransportConfig(
                broadcast_rooms=broadcast_rooms,
                retries_before_backoff=retries_before_backoff,
                retry_interval_initial=retry_interval_initial,
                retry_interval_max=retry_interval_max,
                server=local_matrix_url,
                available_servers=[],
                capabilities_config=capabilities_config,
            )

        assert config.transport.capabilities_config is not None
        if resolver_port is not None:
            config.resolver_endpoint = f"http://localhost:{resolver_port}"

        registry = proxy_manager.token_network_registry(
            token_network_registry_address, block_identifier=BLOCK_ID_LATEST)
        secret_registry = proxy_manager.secret_registry(
            secret_registry_address, block_identifier=BLOCK_ID_LATEST)

        service_registry = None
        if service_registry_address:
            service_registry = proxy_manager.service_registry(
                service_registry_address, block_identifier=BLOCK_ID_LATEST)

        user_deposit = None
        if user_deposit_address:
            user_deposit = proxy_manager.user_deposit(
                user_deposit_address, block_identifier=BLOCK_ID_LATEST)

        # Use `TestMatrixTransport` that saves sent messages for assertions in tests
        assert config.transport.capabilities_config is not None
        transport = TestMatrixTransport(config=config.transport,
                                        environment=environment_type)

        raiden_event_handler = RaidenEventHandler()
        hold_handler = HoldRaidenEventHandler(raiden_event_handler)
        message_handler = WaitForMessage()

        api_server = None
        if enable_rest_api:
            api_server = start_api_server(rpc_client=proxy_manager.client,
                                          config=config.rest_api,
                                          eth_rpc_endpoint="bla")

        app = App(
            config=config,
            rpc_client=proxy_manager.client,
            proxy_manager=proxy_manager,
            query_start_block=BlockNumber(0),
            default_registry=registry,
            default_secret_registry=secret_registry,
            default_service_registry=service_registry,
            default_user_deposit=user_deposit,
            default_one_to_n_address=one_to_n_address,
            default_msc_address=monitoring_service_contract_address,
            transport=transport,
            raiden_event_handler=hold_handler,
            message_handler=message_handler,
            routing_mode=routing_mode,
            api_server=api_server,
        )
        apps.append(app)

    return apps
def test_pfs_send_unique_capacity_and_fee_updates_during_mediated_transfer(
        raiden_network):
    """
    Tests that PFSCapacityUpdates and PFSFeeUpdates are being
    sent only once with the most recent state change in a batch.
    """
    app0, app1 = raiden_network
    chain_state = views.state_from_app(app0)

    # There have been two PFSCapacityUpdates and two PFSFeeUpdates per channel per node
    assert len(get_messages(app0)) == 4
    # The mediator has two channels
    assert len(get_messages(app1)) == 4

    # Now we create two state_changes (Deposit) regarding the same channel
    # and trigger handle_state_changes() of node0. The expected outcome
    # is that only 1 PFSCapacityUpdate and 1 PFSFeeUpdate is being sent
    # not one per state change
    pfs_fee_update_1_of_app0 = get_messages(app0)[1]
    assert isinstance(pfs_fee_update_1_of_app0, PFSFeeUpdate)
    pfs_capacity_update_2_of_app0 = get_messages(app0)[2]
    assert isinstance(pfs_capacity_update_2_of_app0, PFSCapacityUpdate)
    canonical_identifier = pfs_fee_update_1_of_app0.canonical_identifier
    new_total_deposit_1 = pfs_capacity_update_2_of_app0.other_capacity * 2

    deposit_transaction_1 = TransactionChannelDeposit(
        app1.raiden.address, TokenAmount(new_total_deposit_1),
        chain_state.block_number)
    channel_deposit_1 = ContractReceiveChannelDeposit(
        transaction_hash=make_transaction_hash(),
        canonical_identifier=canonical_identifier,
        deposit_transaction=deposit_transaction_1,
        block_number=chain_state.block_number,
        block_hash=chain_state.block_hash,
        fee_config=MediationFeeConfig(),
    )

    new_total_deposit_2 = new_total_deposit_1 * 2
    deposit_transaction_2 = TransactionChannelDeposit(
        app1.raiden.address, TokenAmount(new_total_deposit_2),
        chain_state.block_number)

    channel_deposit_2 = ContractReceiveChannelDeposit(
        transaction_hash=make_transaction_hash(),
        canonical_identifier=canonical_identifier,
        deposit_transaction=deposit_transaction_2,
        block_number=chain_state.block_number,
        block_hash=chain_state.block_hash,
        fee_config=MediationFeeConfig(),
    )

    state_changes = [channel_deposit_1, channel_deposit_2]

    app0.raiden.handle_state_changes(state_changes=state_changes)

    # Now we should see that app0 send 2 new messages,
    # one PFSCapacityUpdate and one PFSFeeUpdate with
    # the updated amount of the initial amount * 4
    # so sending should only be triggered by the second state change

    pfs_capacity_update_3_of_app0 = get_messages(app0)[4]
    assert isinstance(pfs_capacity_update_3_of_app0, PFSCapacityUpdate)
    assert len(get_messages(app0)) == 6
    assert (pfs_capacity_update_3_of_app0.other_capacity ==
            pfs_capacity_update_2_of_app0.updating_capacity * 4)

    # Now we want to test if this also works with a state_change
    # that triggers only a PFSCapacityUpdate and no PFSFeeUpdate.
    # So at the end we expect 1 more PFSCapacityUpdate in the room.

    lock_secret_1 = keccak(b"test_end_state")
    unlock_message_1 = Unlock(
        chain_id=chain_state.chain_id,
        message_identifier=MessageID(123132),
        payment_identifier=PaymentID(1),
        nonce=Nonce(2),
        token_network_address=canonical_identifier.token_network_address,
        channel_identifier=canonical_identifier.channel_identifier,
        transferred_amount=TokenAmount(400),
        locked_amount=LockedAmount(0),
        locksroot=Locksroot(keccak(b"")),
        secret=Secret(lock_secret_1),
        signature=Signature(bytes(65)),
    )
    unlock_message_1.sign(app1.raiden.signer)
    balance_proof_1 = balanceproof_from_envelope(unlock_message_1)

    unlock_1 = ReceiveUnlock(
        message_identifier=MessageID(5135),
        secret=Secret(lock_secret_1),
        balance_proof=balance_proof_1,
        sender=balance_proof_1.sender,
    )

    lock_secret_2 = keccak(b"test_end_state_again")

    unlock_message_2 = Unlock(
        chain_id=chain_state.chain_id,
        message_identifier=MessageID(223132),
        payment_identifier=PaymentID(2),
        nonce=Nonce(2),
        token_network_address=canonical_identifier.token_network_address,
        channel_identifier=canonical_identifier.channel_identifier,
        transferred_amount=TokenAmount(500),
        locked_amount=LockedAmount(0),
        locksroot=Locksroot(keccak(b"")),
        secret=Secret(lock_secret_2),
        signature=Signature(bytes(65)),
    )

    unlock_message_2.sign(app1.raiden.signer)

    balance_proof_2 = balanceproof_from_envelope(unlock_message_2)

    unlock_2 = ReceiveUnlock(
        message_identifier=MessageID(5135),
        secret=Secret(lock_secret_2),
        balance_proof=balance_proof_2,
        sender=balance_proof_2.sender,
    )

    state_changes_2 = [unlock_1, unlock_2]

    app0.raiden.handle_state_changes(state_changes=state_changes_2)

    assert len(get_messages(app0)) == 7
    assert len([
        x for x in get_messages(app0) if isinstance(x, PFSCapacityUpdate)
    ]) == 4