Ejemplo n.º 1
0
def make_transfer_pair(payer,
                       payee,
                       initiator,
                       target,
                       amount,
                       expiration,
                       secret=None,
                       reveal_timeout=factories.UNIT_REVEAL_TIMEOUT):

    payer_expiration = expiration
    payee_expiration = expiration - reveal_timeout

    return MediationPairState(
        factories.make_route(payer, amount),
        factories.make_transfer(amount,
                                initiator,
                                target,
                                payer_expiration,
                                secret=secret),
        factories.make_route(payee, amount),
        factories.make_transfer(amount,
                                initiator,
                                target,
                                payee_expiration,
                                secret=secret),
    )
Ejemplo n.º 2
0
def next_transfer_pair(payer_route, payer_transfer, routes_state,
                       timeout_blocks, block_number):
    """ Given a payer transfer tries a new route to proceed with the mediation.

    Args:
        payer_route (RouteState): The previous route in the path that provides
            the token for the mediation.
        payer_transfer (LockedTransferState): The transfer received from the
            payer_route.
        routes_state (RoutesState): Current available routes that may be used,
            it's assumed that the available_routes list is ordered from best to
            worst.
        timeout_blocks (int): Base number of available blocks used to compute
            the lock timeout.
        block_number (int): The current block number.
    """
    assert timeout_blocks > 0
    assert timeout_blocks <= payer_transfer.expiration - block_number

    transfer_pair = None
    mediated_events = list()

    payee_route = next_route(
        routes_state,
        timeout_blocks,
        payer_transfer.amount,
    )

    if payee_route:
        assert payee_route.reveal_timeout < timeout_blocks

        lock_timeout = timeout_blocks - payee_route.reveal_timeout
        lock_expiration = lock_timeout + block_number

        payee_transfer = LockedTransferState(
            payer_transfer.identifier,
            payer_transfer.amount,
            payer_transfer.token,
            payer_transfer.initiator,
            payer_transfer.target,
            lock_expiration,
            payer_transfer.hashlock,
            payer_transfer.secret,
        )

        transfer_pair = MediationPairState(
            payer_route,
            payer_transfer,
            payee_route,
            payee_transfer,
        )

        mediated_events = [
            mediatedtransfer(payee_transfer, payee_route.node_address),
        ]

    return (
        transfer_pair,
        mediated_events,
    )
Ejemplo n.º 3
0
def test_mediator_task_view():
    """Same as above for mediator tasks."""
    secret1 = factories.make_secret(1)
    locked_amount1 = 11
    payee_transfer = factories.create(
        factories.LockedTransferUnsignedStateProperties(secret=secret1))
    payer_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            secret=secret1, payment_identifier=1,
            locked_amount=locked_amount1))
    secrethash1 = payee_transfer.lock.secrethash
    initiator = payee_transfer.initiator
    initiator_channel = factories.create(
        factories.NettingChannelStateProperties(
            partner_state=factories.NettingChannelEndStateProperties(
                address=initiator, balance=100)))
    routes = [factories.make_route_from_channel(initiator_channel)]
    transfer_state1 = MediatorTransferState(secrethash=secrethash1,
                                            routes=routes)
    transfer_state1.transfers_pair.append(
        MediationPairState(
            payer_transfer=payer_transfer,
            payee_transfer=payee_transfer,
            payee_address=payee_transfer.target,
        ))
    task1 = MediatorTask(
        token_network_identifier=factories.UNIT_TOKEN_NETWORK_ADDRESS,
        mediator_state=transfer_state1,
    )

    secret2 = factories.make_secret(2)
    locked_amount2 = 13
    transfer2 = factories.create(
        factories.LockedTransferSignedStateProperties(
            secret=secret2, payment_identifier=2,
            locked_amount=locked_amount2))
    secrethash2 = transfer2.lock.secrethash
    transfer_state2 = MediatorTransferState(secrethash=secrethash2,
                                            routes=routes)
    transfer_state2.waiting_transfer = WaitingTransferState(transfer=transfer2)
    task2 = MediatorTask(
        token_network_identifier=factories.UNIT_TOKEN_NETWORK_ADDRESS,
        mediator_state=transfer_state2,
    )

    payment_mapping = {secrethash1: task1, secrethash2: task2}
    view = transfer_tasks_view(payment_mapping)

    assert len(view) == 2
    if view[0].get("payment_identifier") == "1":
        pending_transfer, waiting_transfer = view
    else:
        waiting_transfer, pending_transfer = view

    assert pending_transfer.get("role") == waiting_transfer.get(
        "role") == "mediator"
    assert pending_transfer.get("payment_identifier") == "1"
    assert waiting_transfer.get("payment_identifier") == "2"
    assert pending_transfer.get("locked_amount") == str(locked_amount1)
    assert waiting_transfer.get("locked_amount") == str(locked_amount2)
Ejemplo n.º 4
0
def test_mediator_task_view():
    """Same as above for mediator tasks."""
    secret1 = factories.make_secret(1)
    locked_amount1 = TokenAmount(11)
    payee_transfer = factories.create(
        factories.LockedTransferUnsignedStateProperties(secret=secret1))
    payer_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            secret=secret1,
            payment_identifier=PaymentID(1),
            locked_amount=locked_amount1))
    secrethash1 = payee_transfer.lock.secrethash
    route_state = RouteState(route=[payee_transfer.target])

    transfer_state1 = MediatorTransferState(secrethash=secrethash1,
                                            routes=[route_state])
    # pylint: disable=E1101
    transfer_state1.transfers_pair.append(
        MediationPairState(
            payer_transfer=payer_transfer,
            payee_transfer=payee_transfer,
            payee_address=payee_transfer.target,
        ))
    task1 = MediatorTask(
        token_network_address=factories.UNIT_TOKEN_NETWORK_ADDRESS,
        mediator_state=transfer_state1)

    secret2 = factories.make_secret(2)
    locked_amount2 = TokenAmount(13)
    transfer2 = factories.create(
        factories.LockedTransferSignedStateProperties(
            secret=secret2,
            payment_identifier=PaymentID(2),
            locked_amount=locked_amount2))
    secrethash2 = transfer2.lock.secrethash
    transfer_state2 = MediatorTransferState(secrethash=secrethash2,
                                            routes=[route_state])
    transfer_state2.waiting_transfer = WaitingTransferState(transfer=transfer2)
    task2 = MediatorTask(
        token_network_address=factories.UNIT_TOKEN_NETWORK_ADDRESS,
        mediator_state=transfer_state2)

    payment_mapping = {
        secrethash1: cast(TransferTask, task1),
        secrethash2: cast(TransferTask, task2),
    }
    view = transfer_tasks_view(payment_mapping)

    assert len(view) == 2
    if view[0].get("payment_identifier") == "1":
        pending_transfer, waiting_transfer = view
    else:
        waiting_transfer, pending_transfer = view

    assert pending_transfer.get("role") == waiting_transfer.get(
        "role") == "mediator"
    assert pending_transfer.get("payment_identifier") == "1"
    assert waiting_transfer.get("payment_identifier") == "2"
    assert pending_transfer.get("locked_amount") == str(locked_amount1)
    assert waiting_transfer.get("locked_amount") == str(locked_amount2)
Ejemplo n.º 5
0
def next_transfer_pair(
    payer_transfer: LockedTransferSignedState,
    available_routes: List['RouteState'],
    channelidentifiers_to_channels: Dict,
    pseudo_random_generator: random.Random,
    block_number: typing.BlockNumber,
):
    """ Given a payer transfer tries a new route to proceed with the mediation.
    Args:
        payer_transfer: The transfer received from the payer_channel.
        available_routes: Current available routes that may be used, it's
            assumed that the routes list is ordered from best to worst.
        channelidentifiers_to_channels: All the channels available for this
            transfer.
        pseudo_random_generator: Number generator to generate a message id.
        block_number: The current block number.
    """
    transfer_pair = None
    mediated_events = list()
    lock_timeout = payer_transfer.lock.expiration - block_number

    payee_channel = next_channel_from_routes(
        available_routes,
        channelidentifiers_to_channels,
        payer_transfer.lock.amount,
        lock_timeout,
    )

    if payee_channel:
        assert payee_channel.settle_timeout >= lock_timeout
        assert payee_channel.token_address == payer_transfer.token

        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        lockedtransfer_event = channel.send_lockedtransfer(
            payee_channel,
            payer_transfer.initiator,
            payer_transfer.target,
            payer_transfer.lock.amount,
            message_identifier,
            payer_transfer.payment_identifier,
            payer_transfer.lock.expiration,
            payer_transfer.lock.secrethash,
        )
        assert lockedtransfer_event

        transfer_pair = MediationPairState(
            payer_transfer,
            payee_channel.partner_state.address,
            lockedtransfer_event.transfer,
        )

        mediated_events = [lockedtransfer_event]

    return (
        transfer_pair,
        mediated_events,
    )
Ejemplo n.º 6
0
def next_transfer_pair(registry_address: typing.Address,
                       payer_transfer: LockedTransferSignedState,
                       available_routes: List['RouteState'],
                       channelidentifiers_to_channels: Dict,
                       pseudo_random_generator: random.Random,
                       timeout_blocks: int, block_number: int):
    """ Given a payer transfer tries a new route to proceed with the mediation.
    Args:
        payer_transfer: The transfer received from the payer_channel.
        routes: Current available routes that may be used, it's assumed that
            the routes list is ordered from best to worst.
        timeout_blocks: Base number of available blocks used to compute
            the lock timeout.
        block_number: The current block number.
    """
    assert timeout_blocks > 0
    assert timeout_blocks <= payer_transfer.lock.expiration - block_number

    transfer_pair = None
    mediated_events = list()

    payee_channel = next_channel_from_routes(
        available_routes,
        channelidentifiers_to_channels,
        payer_transfer.lock.amount,
        timeout_blocks,
    )

    if payee_channel:
        assert payee_channel.reveal_timeout < timeout_blocks
        assert payee_channel.token_address == payer_transfer.token

        lock_timeout = timeout_blocks - payee_channel.reveal_timeout
        lock_expiration = lock_timeout + block_number

        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        lockedtransfer_event = channel.send_lockedtransfer(
            registry_address, payee_channel, payer_transfer.initiator,
            payer_transfer.target, payer_transfer.lock.amount,
            message_identifier, payer_transfer.payment_identifier,
            lock_expiration, payer_transfer.lock.secrethash)
        assert lockedtransfer_event

        transfer_pair = MediationPairState(
            payer_transfer,
            payee_channel.partner_state.address,
            lockedtransfer_event.transfer,
        )

        mediated_events = [lockedtransfer_event]

    return (
        transfer_pair,
        mediated_events,
    )
Ejemplo n.º 7
0
def backward_transfer_pair(
        backward_channel: NettingChannelState,
        payer_transfer: LockedTransferSignedState,
        pseudo_random_generator: random.Random,
        block_number: typing.BlockNumber,
) -> typing.Tuple[typing.Optional[MediationPairState], typing.List[Event]]:
    """ Sends a transfer backwards, allowing the previous hop to try a new
    route.

    When all the routes available for this node failed, send a transfer
    backwards with the same amount and secrethash, allowing the previous hop to
    do a retry.

    Args:
        backward_channel: The original channel which sent the mediated transfer
            to this node.
        payer_transfer: The *latest* payer transfer which is backing the
            mediation.
        block_number: The current block number.

    Returns:
        The mediator pair and the correspoding refund event.
    """
    transfer_pair = None
    events = list()

    lock = payer_transfer.lock
    lock_timeout = lock.expiration - block_number

    # Ensure the refund transfer's lock has a safe expiration, otherwise don't
    # do anything and wait for the received lock to expire.
    if is_channel_usable(backward_channel, lock.amount, lock_timeout):
        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        refund_transfer = channel.send_refundtransfer(
            channel_state=backward_channel,
            initiator=payer_transfer.initiator,
            target=payer_transfer.target,
            amount=lock.amount,
            message_identifier=message_identifier,
            payment_identifier=payer_transfer.payment_identifier,
            expiration=lock.expiration,
            secrethash=lock.secrethash,
        )

        transfer_pair = MediationPairState(
            payer_transfer,
            backward_channel.partner_state.address,
            refund_transfer.transfer,
        )

        events.append(refund_transfer)

    return (transfer_pair, events)
def test_invalid_instantiation_mediation_pair_state():
    valid = MediationPairState(
        payer_transfer=factories.create(factories.LockedTransferSignedStateProperties()),
        payee_address=factories.make_address(),
        payee_transfer=factories.create(factories.LockedTransferUnsignedStateProperties()),
    )

    unsigned_transfer = factories.create(factories.LockedTransferUnsignedStateProperties())
    with pytest.raises(ValueError):
        replace(valid, payer_transfer=unsigned_transfer)

    signed_transfer = factories.create(factories.LockedTransferSignedStateProperties())
    with pytest.raises(ValueError):
        replace(valid, payee_transfer=signed_transfer)

    hex_instead_of_binary = factories.make_checksum_address()
    with pytest.raises(ValueError):
        replace(valid, payee_address=hex_instead_of_binary)
Ejemplo n.º 9
0
def make_transfers_pair(number_of_channels: int,
                        amount: int = UNIT_TRANSFER_AMOUNT,
                        block_number: int = 5) -> MediatorTransfersPair:

    deposit = 5 * amount
    defaults = create_properties(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=deposit),
            partner_state=NettingChannelEndStateProperties(balance=deposit),
            open_transaction=TransactionExecutionStatusProperties(
                finished_block_number=10),
        ))
    properties_list = [
        NettingChannelStateProperties(
            canonical_identifier=make_canonical_identifier(
                channel_identifier=i),
            our_state=NettingChannelEndStateProperties(
                address=ChannelSet.ADDRESSES[0],
                privatekey=ChannelSet.PKEYS[0]),
            partner_state=NettingChannelEndStateProperties(
                address=ChannelSet.ADDRESSES[i + 1],
                privatekey=ChannelSet.PKEYS[i + 1]),
        ) for i in range(number_of_channels)
    ]
    channels = make_channel_set(properties_list, defaults)

    lock_expiration = block_number + UNIT_REVEAL_TIMEOUT * 2
    pseudo_random_generator = random.Random()
    transfers_pairs = list()

    for payer_index in range(number_of_channels - 1):
        payee_index = payer_index + 1

        receiver_channel = channels[payer_index]
        received_transfer = create(
            LockedTransferSignedStateProperties(
                amount=amount,
                expiration=lock_expiration,
                payment_identifier=UNIT_TRANSFER_IDENTIFIER,
                canonical_identifier=receiver_channel.canonical_identifier,
                sender=channels.partner_address(payer_index),
                pkey=channels.partner_privatekeys[payer_index],
            ))

        is_valid, _, msg = channel.handle_receive_lockedtransfer(
            receiver_channel, received_transfer)
        assert is_valid, msg

        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        lockedtransfer_event = channel.send_lockedtransfer(
            channel_state=channels[payee_index],
            initiator=UNIT_TRANSFER_INITIATOR,
            target=UNIT_TRANSFER_TARGET,
            amount=amount,
            message_identifier=message_identifier,
            payment_identifier=UNIT_TRANSFER_IDENTIFIER,
            expiration=lock_expiration,
            secrethash=UNIT_SECRETHASH,
        )
        assert lockedtransfer_event

        lock_timeout = lock_expiration - block_number
        assert mediator.is_channel_usable(
            candidate_channel_state=channels[payee_index],
            transfer_amount=amount,
            lock_timeout=lock_timeout,
        )
        sent_transfer = lockedtransfer_event.transfer

        pair = MediationPairState(received_transfer,
                                  lockedtransfer_event.recipient,
                                  sent_transfer)
        transfers_pairs.append(pair)

    return MediatorTransfersPair(
        channels=channels,
        transfers_pair=transfers_pairs,
        amount=amount,
        block_number=block_number,
        block_hash=make_block_hash(),
    )
Ejemplo n.º 10
0
def make_transfers_pair(privatekeys, amount, block_number):
    transfers_pair = list()
    channel_map = dict()
    pseudo_random_generator = random.Random()

    addresses = list()
    for pkey in privatekeys:
        pubkey = pkey.public_key.format(compressed=False)
        address = publickey_to_address(pubkey)
        addresses.append(address)

    key_address = list(zip(privatekeys, addresses))

    deposit_amount = amount * 5
    channels_state = {
        address: make_channel(
            our_address=HOP1,
            our_balance=deposit_amount,
            partner_balance=deposit_amount,
            partner_address=address,
            token_address=UNIT_TOKEN_ADDRESS,
            token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
        )
        for address in addresses
    }

    lock_expiration = block_number + UNIT_REVEAL_TIMEOUT * 2
    for (payer_key,
         payer_address), payee_address in zip(key_address[:-1], addresses[1:]):
        pay_channel = channels_state[payee_address]
        receive_channel = channels_state[payer_address]

        received_transfer = make_signed_transfer(
            amount=amount,
            initiator=UNIT_TRANSFER_INITIATOR,
            target=UNIT_TRANSFER_TARGET,
            expiration=lock_expiration,
            secret=UNIT_SECRET,
            payment_identifier=UNIT_TRANSFER_IDENTIFIER,
            channel_identifier=receive_channel.identifier,
            pkey=payer_key,
            sender=payer_address,
        )

        is_valid, _, msg = channel.handle_receive_lockedtransfer(
            receive_channel,
            received_transfer,
        )
        assert is_valid, msg

        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        lockedtransfer_event = channel.send_lockedtransfer(
            channel_state=pay_channel,
            initiator=UNIT_TRANSFER_INITIATOR,
            target=UNIT_TRANSFER_TARGET,
            amount=amount,
            message_identifier=message_identifier,
            payment_identifier=UNIT_TRANSFER_IDENTIFIER,
            expiration=lock_expiration,
            secrethash=UNIT_SECRETHASH,
        )
        assert lockedtransfer_event
        lock_timeout = lock_expiration - block_number
        assert mediator.is_channel_usable(
            candidate_channel_state=pay_channel,
            transfer_amount=amount,
            lock_timeout=lock_timeout,
        )
        sent_transfer = lockedtransfer_event.transfer

        pair = MediationPairState(
            received_transfer,
            lockedtransfer_event.recipient,
            sent_transfer,
        )
        transfers_pair.append(pair)

        channel_map[receive_channel.identifier] = receive_channel
        channel_map[pay_channel.identifier] = pay_channel

        assert channel.is_lock_locked(receive_channel.partner_state,
                                      UNIT_SECRETHASH)
        assert channel.is_lock_locked(pay_channel.our_state, UNIT_SECRETHASH)

    return channel_map, transfers_pair