Exemplo n.º 1
0
def test_event_operators():
    a = EventTransferSentSuccess(2)
    b = EventTransferSentSuccess(2)
    c = EventTransferSentSuccess(3)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = EventTransferSentFailed(2, 'BECAUSE')
    b = EventTransferSentFailed(2, 'BECAUSE')
    c = EventTransferSentFailed(3, 'UNKNOWN')

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = EventTransferReceivedSuccess(2, 5, sha3('initiator'))
    b = EventTransferReceivedSuccess(2, 5, sha3('initiator'))
    c = EventTransferReceivedSuccess(3, 5, sha3('initiator'))
    d = EventTransferReceivedSuccess(3, 5, sha3('other initiator'))

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c
    assert c != d
    assert not c == d
Exemplo n.º 2
0
def test_event_operators():
    a = EventTransferSentSuccess(2)
    b = EventTransferSentSuccess(2)
    c = EventTransferSentSuccess(3)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = EventTransferSentFailed(2, 'BECAUSE')
    b = EventTransferSentFailed(2, 'BECAUSE')
    c = EventTransferSentFailed(3, 'UNKNOWN')

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = EventTransferReceivedSuccess(2)
    b = EventTransferReceivedSuccess(2)
    c = EventTransferReceivedSuccess(3)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c
Exemplo n.º 3
0
def test_event_operators():
    a = EventTransferSentSuccess(2, 5, sha3(b'target'))
    b = EventTransferSentSuccess(2, 5, sha3(b'target'))
    c = EventTransferSentSuccess(3, 4, sha3(b'target'))
    d = EventTransferSentSuccess(3, 4, sha3(b'differenttarget'))

    # pylint: disable=unneeded-not
    assert a == b
    assert not a != b
    assert a != c
    assert not a == c
    assert not c == d

    a = EventTransferSentFailed(2, 'BECAUSE')
    b = EventTransferSentFailed(2, 'BECAUSE')
    c = EventTransferSentFailed(3, 'UNKNOWN')

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = EventTransferReceivedSuccess(2, 5, sha3(b'initiator'))
    b = EventTransferReceivedSuccess(2, 5, sha3(b'initiator'))
    c = EventTransferReceivedSuccess(3, 5, sha3(b'initiator'))
    d = EventTransferReceivedSuccess(3, 5, sha3(b'other initiator'))

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c
    assert c != d
    assert not c == d
Exemplo n.º 4
0
def handle_send_directtransfer(
    channel_state,
    state_change,
    pseudo_random_generator,
):
    events = list()

    amount = state_change.amount
    payment_identifier = state_change.payment_identifier
    distributable_amount = get_distributable(channel_state.our_state,
                                             channel_state.partner_state)

    is_open = get_status(channel_state) == CHANNEL_STATE_OPENED
    is_valid = amount > 0
    can_pay = amount <= distributable_amount

    if is_open and is_valid and can_pay:
        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        direct_transfer = send_directtransfer(
            state_change.payment_network_identifier,
            channel_state,
            amount,
            message_identifier,
            payment_identifier,
        )
        events.append(direct_transfer)
    else:
        if not is_open:
            failure = EventTransferSentFailed(payment_identifier,
                                              'Channel is not opened')
            events.append(failure)

        elif not is_valid:
            msg = 'Transfer amount is invalid. Transfer: {}'.format(amount)
            failure = EventTransferSentFailed(payment_identifier, msg)
            events.append(failure)

        elif not can_pay:
            msg = ('Transfer amount exceeds the available capacity. '
                   'Capacity: {}, Transfer: {}').format(
                       distributable_amount,
                       amount,
                   )

            failure = EventTransferSentFailed(payment_identifier, msg)
            events.append(failure)

    return TransitionResult(channel_state, events)
Exemplo n.º 5
0
def handle_action_transfer_direct(
    token_network_state,
    state_change,
    pseudo_random_generator,
    block_number,
):
    receiver_address = state_change.receiver_address
    channel_state = token_network_state.partneraddresses_to_channels.get(
        receiver_address)

    if channel_state:
        iteration = channel.state_transition(
            channel_state,
            state_change,
            pseudo_random_generator,
            block_number,
        )
        events = iteration.events
    else:
        failure = EventTransferSentFailed(
            state_change.identifier,
            'Unknown partner channel',
        )
        events = [failure]

    return TransitionResult(token_network_state, events)
Exemplo n.º 6
0
def handle_secretrequest(
        initiator_state: InitiatorTransferState,
        state_change: ReceiveSecretRequest,
        pseudo_random_generator: random.Random,
) -> TransitionResult:

    request_from_target = (
        state_change.sender == initiator_state.transfer_description.target and
        state_change.secrethash == initiator_state.transfer_description.secrethash
    )

    is_valid_payment_id = (
        state_change.payment_identifier == initiator_state.transfer_description.payment_identifier
    )

    valid_secretrequest = (
        request_from_target and
        is_valid_payment_id and
        state_change.amount == initiator_state.transfer_description.amount
    )

    invalid_secretrequest = request_from_target and (
        is_valid_payment_id or
        state_change.amount != initiator_state.transfer_description.amount
    )

    if valid_secretrequest:
        # 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
        queue_name = b'global'
        revealsecret = SendRevealSecret(
            recipient,
            queue_name,
            message_identifier,
            transfer_description.secret,
            transfer_description.token,
        )

        initiator_state.revealsecret = revealsecret
        iteration = TransitionResult(initiator_state, [revealsecret])

    elif invalid_secretrequest:
        cancel = EventTransferSentFailed(
            identifier=initiator_state.transfer_description.payment_identifier,
            reason='bad secret request message from target',
        )
        iteration = TransitionResult(None, [cancel])

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

    return iteration
Exemplo n.º 7
0
def test_write_read_events(tmpdir, in_memory_database):
    log = init_database(tmpdir, in_memory_database)
    event = EventTransferSentFailed(1, 'whatever')
    with pytest.raises(sqlite3.IntegrityError):
        log.storage.write_state_events(1, [(None, 1, 1, log.serializer.serialize(event))])
    assert(len(get_all_state_events(log)) == 0)

    log.storage.write_state_change('statechangedata')
    log.storage.write_state_events(1, [(None, 1, 1, log.serializer.serialize(event))])
    logged_events = get_all_state_events(log)
    assert(len(logged_events) == 1)
    assert(logged_events[0].identifier == 1)
    assert(logged_events[0].state_change_id == 1)
    assert(isinstance(logged_events[0].event_object, EventTransferSentFailed))
Exemplo n.º 8
0
def handle_secretrequest(
    initiator_state: InitiatorTransferState,
    state_change: ReceiveSecretRequest,
) -> TransitionResult:

    request_from_target = (state_change.sender
                           == initiator_state.transfer_description.target
                           and state_change.hashlock
                           == initiator_state.transfer_description.hashlock)

    valid_secretrequest = (request_from_target and state_change.identifier
                           == initiator_state.transfer_description.identifier
                           and state_change.amount
                           == initiator_state.transfer_description.amount)

    invalid_secretrequest = request_from_target and (
        state_change.identifier !=
        initiator_state.transfer_description.identifier
        or state_change.amount != initiator_state.transfer_description.amount)

    if valid_secretrequest:
        # 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
        #
        transfer_description = initiator_state.transfer_description
        reveal_secret = SendRevealSecret(
            transfer_description.identifier,
            transfer_description.secret,
            transfer_description.token,
            transfer_description.target,
        )

        initiator_state.revealsecret = reveal_secret
        iteration = TransitionResult(initiator_state, [reveal_secret])

    elif invalid_secretrequest:
        cancel = EventTransferSentFailed(
            identifier=initiator_state.transfer_description.identifier,
            reason='bad secret request message from target',
        )
        iteration = TransitionResult(None, [cancel])

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

    return iteration
Exemplo n.º 9
0
def try_new_route(
        registry_address: typing.Address,
        channelidentifiers_to_channels: ChannelMap,
        available_routes: typing.List[RouteState],
        transfer_description: TransferDescriptionWithSecretState,
        pseudo_random_generator: random.Random,
        block_number: typing.BlockNumber,
) -> TransitionResult:

    channel_state = next_channel_from_routes(
        available_routes,
        channelidentifiers_to_channels,
        transfer_description.amount,
    )

    events = list()
    if channel_state is None:
        if not available_routes:
            reason = 'there is no route available'
        else:
            reason = 'none of the available routes could be used'

        transfer_failed = EventTransferSentFailed(
            identifier=transfer_description.payment_identifier,
            reason=reason,
        )
        events.append(transfer_failed)

        initiator_state = None

    else:
        initiator_state = InitiatorTransferState(
            transfer_description,
            channel_state.identifier,
        )

        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        lockedtransfer_event = send_lockedtransfer(
            registry_address,
            initiator_state,
            channel_state,
            message_identifier,
            block_number,
        )
        assert lockedtransfer_event

        events.append(lockedtransfer_event)

    return TransitionResult(initiator_state, events)
Exemplo n.º 10
0
def handle_cancelpayment(payment_state):
    """ Cancel the payment. """
    assert can_cancel(
        payment_state), 'Cannot cancel a transfer after the secret is revealed'

    transfer_description = payment_state.initiator.transfer_description
    cancel_events = cancel_current_route(payment_state)

    cancel = EventTransferSentFailed(
        identifier=transfer_description.identifier,
        reason='user canceled transfer',
    )
    cancel_events.append(cancel)

    return TransitionResult(None, cancel_events)
Exemplo n.º 11
0
def user_cancel_transfer(state):
    """ Cancel the current in-transit message. """
    assert state.revealsecret is None, 'cannot cancel a transfer with a RevealSecret in flight'

    state.transfer.secret = None
    state.transfer.hashlock = None
    state.message = None
    state.route = None
    state.secretrequest = None
    state.revealsecret = None

    cancel = EventTransferSentFailed(
        identifier=state.transfer.identifier,
        reason='user canceled transfer',
    )
    iteration = TransitionResult(None, [cancel])

    return iteration
Exemplo n.º 12
0
def try_new_route(
    channelidentifiers_to_channels: ChannelMap,
    available_routes: typing.List[RouteState],
    transfer_description: TransferDescriptionWithSecretState,
    block_number: typing.BlockNumber,
) -> TransitionResult:

    channel_state = next_channel_from_routes(
        available_routes,
        channelidentifiers_to_channels,
        transfer_description.amount,
    )

    events = list()
    if channel_state is None:
        if not available_routes:
            reason = 'there is no route available'
        else:
            reason = 'none of the available routes could be used'

        transfer_failed = EventTransferSentFailed(
            identifier=transfer_description.identifier,
            reason=reason,
        )
        events.append(transfer_failed)

        initiator_state = None

    else:
        initiator_state = InitiatorTransferState(
            transfer_description,
            channel_state.identifier,
        )

        mediatedtransfer_event = send_mediatedtransfer(
            initiator_state,
            channel_state,
            block_number,
        )
        assert mediatedtransfer_event

        events.append(mediatedtransfer_event)

    return TransitionResult(initiator_state, events)
Exemplo n.º 13
0
def test_write_read_events():
    wal = new_wal()

    event = EventTransferSentFailed(1, 'whatever')
    event_list = [event]
    block_number = 10

    with pytest.raises(sqlite3.IntegrityError):
        unexisting_state_change_id = 1
        wal.storage.write_events(
            unexisting_state_change_id,
            block_number,
            event_list,
        )

    previous_events = wal.storage.get_events_by_identifier(
        from_identifier=0,
        to_identifier='latest',
    )

    state_change_id = wal.storage.write_state_change('statechangedata')
    wal.storage.write_events(
        state_change_id,
        block_number,
        event_list,
    )

    new_events = wal.storage.get_events_by_identifier(
        from_identifier=0,
        to_identifier='latest',
    )
    assert len(previous_events) + 1 == len(new_events)

    latest_event = new_events[-1]
    assert latest_event[0] == block_number
    assert isinstance(latest_event[1], EventTransferSentFailed)
Exemplo n.º 14
0
def try_new_route(state):
    assert state.route is None, 'cannot try a new route while one is being used'

    # TODO:
    # - Route ranking. An upper layer should rate each route to optimize
    #   the fee price/quality of each route and add a rate from in the range
    #   [0.0,1.0].
    # - Add in a policy per route:
    #   - filtering, e.g. so the user may have a per route maximum transfer
    #     value based on fixed value or reputation.
    #   - reveal time computation
    #   - These policy details are better hidden from this implementation and
    #     changes should be applied through the use of Route state changes.

    # Find a single route that may fulfill the request, this uses a single
    # route intentionally
    try_route = None
    while state.routes.available_routes:
        route = state.routes.available_routes.pop(0)

        if route.available_balance < state.transfer.amount:
            state.routes.ignored_routes.append(route)
        else:
            try_route = route
            break

    unlock_failed = None
    if state.message:
        unlock_failed = EventUnlockFailed(
            identifier=state.transfer.identifier,
            hashlock=state.transfer.hashlock,
            reason='route was canceled',
        )

    if try_route is None:
        # No available route has sufficient balance for the current transfer,
        # cancel it.
        #
        # At this point we can just discard all the state data, this is only
        # valid because we are the initiator and we know that the secret was
        # not released.
        transfer_failed = EventTransferSentFailed(
            identifier=state.transfer.identifier,
            reason='no route available',
        )

        events = [transfer_failed]
        if unlock_failed:
            events.append(unlock_failed)
        iteration = TransitionResult(None, events)

    else:
        state.route = try_route

        secret = next(state.random_generator)
        hashlock = sha3(secret)

        # The initiator doesn't need to learn the secret, so there is no need
        # to decrement reveal_timeout from the lock timeout.
        #
        # The lock_expiration could be set to a value larger than
        # settle_timeout, this is not useful since the next hop will take this
        # channel settle_timeout as an upper limit for expiration.
        #
        # The two nodes will most likely disagree on latest block, as far as
        # the expiration goes this is no problem.
        lock_expiration = state.block_number + try_route.settle_timeout

        identifier = state.transfer.identifier

        transfer = LockedTransferState(
            identifier,
            state.transfer.amount,
            state.transfer.token,
            state.transfer.initiator,
            state.transfer.target,
            lock_expiration,
            hashlock,
            secret,
        )

        message = SendMediatedTransfer(
            transfer.identifier,
            transfer.token,
            transfer.amount,
            transfer.hashlock,
            state.our_address,
            transfer.target,
            lock_expiration,
            try_route.node_address,
        )

        state.transfer = transfer
        state.message = message

        events = [message]
        if unlock_failed:
            events.append(unlock_failed)

        iteration = TransitionResult(state, events)

    return iteration