示例#1
0
def test_state_operators():
    a_route = RouteState('opened', ADDRESS, ADDRESS2, 5, 5, 5, 5)
    b_route = RouteState('opened', ADDRESS, ADDRESS2, 5, 5, 5, 5)
    c_route = RouteState('closed', ADDRESS3, ADDRESS2, 1, 2, 3, 4)

    assert a_route == b_route
    assert not a_route != b_route
    assert a_route != c_route
    assert not a_route == c_route

    d_route = RouteState('opened', ADDRESS4, ADDRESS, 1, 2, 3, 4)
    a = RoutesState([a_route, d_route])
    b = RoutesState([a_route, d_route])
    c = RoutesState([a_route, c_route])

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

    a = LockedTransferState(1, 2, ADDRESS, ADDRESS2, ADDRESS3, 4, HASH, 'secret')
    b = LockedTransferState(1, 2, ADDRESS, ADDRESS2, ADDRESS3, 4, HASH, 'secret')
    c = LockedTransferState(2, 4, ADDRESS3, ADDRESS4, ADDRESS, 4, HASH, 'secret')

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c
示例#2
0
def make_init_statechange(routes,
                          target,
                          amount=factories.UNIT_TRANSFER_AMOUNT,
                          block_number=1,
                          our_address=factories.ADDR,
                          secret_generator=None,
                          identifier=0,
                          token=factories.UNIT_TOKEN_ADDRESS):

    if secret_generator is None:
        secret_generator = SequenceGenerator()

    transfer = factories.make_transfer(
        amount,
        initiator=our_address,
        target=target,
        identifier=identifier,
        token=token,
        secret=None,
        hashlock=None,
        expiration=None,
    )

    init_state_change = ActionInitInitiator(
        our_address,
        transfer,
        RoutesState(routes),
        secret_generator,
        block_number,
    )

    return init_state_change
示例#3
0
def test_init_without_routes():
    amount = factories.UNIT_TRANSFER_AMOUNT
    block_number = 1
    our_address, target_address = factories.HOP1, factories.HOP3
    routes = []

    transfer = factories.make_transfer(
        amount,
        initiator=our_address,
        target=target_address,
        secret=None,
        hashlock=None,
        expiration=None,
    )
    init_state_change = ActionInitInitiator(
        our_address,
        transfer,
        RoutesState(routes),
        SequenceGenerator(),
        block_number,
    )

    initiator_state_machine = StateManager(
        initiator.state_transition,
        None,
    )

    assert initiator_state_machine.current_state is None

    events = initiator_state_machine.dispatch(init_state_change, )

    assert len(events) == 1
    assert any(isinstance(e, EventTransferSentFailed) for e in events)
    assert initiator_state_machine.current_state is None
示例#4
0
def test_next_transfer_pair():
    timeout_blocks = 47
    block_number = 3
    balance = 10

    payer_route = factories.make_route(factories.HOP1, balance)
    payer_transfer = factories.make_transfer(balance, factories.ADDR, expiration=50)

    routes = [
        factories.make_route(factories.HOP2, available_balance=balance),
    ]
    routes_state = RoutesState(list(routes))  # copy because the list will be modified inplace

    pair, events = mediator.next_transfer_pair(
        payer_route,
        payer_transfer,
        routes_state,
        timeout_blocks,
        block_number,
    )

    assert pair.payer_route == payer_route
    assert pair.payer_transfer == payer_transfer
    assert pair.payee_route == routes[0]
    assert pair.payee_transfer.expiration < pair.payer_transfer.expiration

    assert isinstance(events[0], SendMediatedTransfer)
    assert len(routes_state.available_routes) == 0
示例#5
0
def test_set_secret():
    amount = 10
    block_number = 7
    routes = []
    routes_state = RoutesState(routes)

    state = MediatorState(
        factories.ADDR,
        routes_state,
        block_number,
        factories.UNIT_HASHLOCK,
    )

    state.transfers_pair = make_transfers_pair(
        [factories.HOP1, factories.HOP2, factories.HOP3],
        factories.HOP6,
        amount,
    )

    mediator.set_secret(state, factories.UNIT_SECRET)
    assert state.secret == factories.UNIT_SECRET

    for pair in state.transfers_pair:
        assert pair.payer_transfer.secret == factories.UNIT_SECRET
        assert pair.payee_transfer.secret == factories.UNIT_SECRET
示例#6
0
def make_init_statechange(from_transfer,
                          from_route,
                          routes,
                          our_address=factories.ADDR):

    block_number = 1
    init_state_change = ActionInitMediator(
        our_address,
        from_transfer,
        RoutesState(routes),
        from_route,
        block_number,
    )
    return init_state_change
示例#7
0
def test_next_route_amount():
    """ Routes that dont have enough available_balance must be ignored. """
    amount = 10
    reveal_timeout = 30
    timeout_blocks = reveal_timeout + 10
    routes = [
        factories.make_route(
            factories.HOP2,
            available_balance=amount * 2,
            reveal_timeout=reveal_timeout,
        ),
        factories.make_route(
            factories.HOP1,
            available_balance=amount + 1,
            reveal_timeout=reveal_timeout,
        ),
        factories.make_route(
            factories.HOP3,
            available_balance=amount // 2,
            reveal_timeout=reveal_timeout,
        ),
        factories.make_route(
            factories.HOP4,
            available_balance=amount,
            reveal_timeout=reveal_timeout,
        ),
    ]

    routes_state = RoutesState(
        list(routes))  # copy because the list will be modified inplace

    route1 = mediator.next_route(routes_state, timeout_blocks, amount)
    assert route1 == routes[0]
    assert routes_state.available_routes == routes[1:]
    assert routes_state.ignored_routes == list()

    route2 = mediator.next_route(routes_state, timeout_blocks, amount)
    assert route2 == routes[1]
    assert routes_state.available_routes == routes[2:]
    assert routes_state.ignored_routes == list()

    route3 = mediator.next_route(routes_state, timeout_blocks, amount)
    assert route3 == routes[3]
    assert routes_state.available_routes == list()
    assert routes_state.ignored_routes == [routes[2]]

    assert mediator.next_route(routes_state, timeout_blocks, amount) is None
示例#8
0
def test_next_transfer_pair():
    timeout_blocks = 47
    block_number = 3
    balance = 10
    initiator = factories.HOP1
    target = factories.ADDR

    payer_route = factories.make_route(initiator, balance)
    payer_transfer = factories.make_transfer(balance,
                                             initiator,
                                             target,
                                             expiration=50)

    routes = [
        factories.make_route(factories.HOP2, available_balance=balance),
    ]
    routes_state = RoutesState(
        list(routes))  # copy because the list will be modified inplace

    pair, events = mediator.next_transfer_pair(
        payer_route,
        payer_transfer,
        routes_state,
        timeout_blocks,
        block_number,
    )

    assert pair.payer_route == payer_route
    assert pair.payer_transfer == payer_transfer
    assert pair.payee_route == routes[0]
    assert pair.payee_transfer.expiration < pair.payer_transfer.expiration

    assert isinstance(events[0], SendMediatedTransfer)
    transfer = events[0]
    assert transfer.identifier == payer_transfer.identifier
    assert transfer.token == payer_transfer.token
    assert transfer.amount == payer_transfer.amount
    assert transfer.hashlock == payer_transfer.hashlock
    assert transfer.initiator == payer_transfer.initiator
    assert transfer.target == payer_transfer.target
    assert transfer.expiration < payer_transfer.expiration
    assert transfer.receiver == pair.payee_route.node_address

    assert len(routes_state.available_routes) == 0
示例#9
0
    def mediate_mediated_transfer(self, message):
        # pylint: disable=too-many-locals
        identifier = message.identifier
        amount = message.lock.amount
        target = message.target
        token = message.token
        graph = self.channelgraphs[token]
        routes = graph.get_best_routes(
            self.address,
            target,
            amount,
            lock_timeout=None,
        )

        available_routes = [
            route
            for route in map(route_to_routestate, routes)
            if route.state == CHANNEL_STATE_OPENED
        ]

        from_channel = graph.partneraddress_channel[message.sender]
        from_route = channel_to_routestate(from_channel, message.sender)

        our_address = self.address
        from_transfer = lockedtransfer_from_message(message)
        route_state = RoutesState(available_routes)
        block_number = self.get_block_number()

        init_mediator = ActionInitMediator(
            our_address,
            from_transfer,
            route_state,
            from_route,
            block_number,
        )

        state_manager = StateManager(mediator.state_transition, None)
        all_events = state_manager.dispatch(init_mediator)

        for event in all_events:
            self.state_machine_event_handler.on_event(event)

        self.identifier_statemanager[identifier].append(state_manager)
示例#10
0
def make_init_statechange(routes,
                          target,
                          amount=factories.UNIT_TRANSFER_AMOUNT,
                          block_number=1,
                          our_address=factories.ADDR,
                          secret_generator=None,
                          identifier=0):

    if secret_generator is None:
        secret_generator = SequenceGenerator()

    init_state_change = ActionInitInitiator(
        our_address,
        make_hashlock_transfer(amount, target=target, identifier=identifier),
        RoutesState(routes),
        secret_generator,
        block_number,
    )

    return init_state_change
示例#11
0
def test_mediate_transfer():
    amount = 10
    block_number = 5
    expiration = 30

    routes = [
        factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT),
    ]

    routes_state = RoutesState(routes)
    state = MediatorState(
        factories.ADDR,
        routes_state,
        block_number,
        factories.UNIT_HASHLOCK,
    )

    payer_route, payer_transfer = make_from(amount, factories.HOP6, expiration)

    iteration = mediator.mediate_transfer(
        state,
        payer_route,
        payer_transfer,
    )

    events_mediated = [
        e
        for e in iteration.events
        if isinstance(e, SendMediatedTransfer)
    ]

    assert len(events_mediated) == 1
    transfer = events_mediated[0]
    assert transfer.identifier == payer_transfer.identifier
    assert transfer.token == payer_transfer.token
    assert transfer.amount == payer_transfer.amount
    assert transfer.hashlock == payer_transfer.hashlock
    assert transfer.target == payer_transfer.target
    assert payer_transfer.expiration > transfer.expiration
    assert transfer.node_address == payer_route.node_address
示例#12
0
def test_next_route_reveal_timeout():
    """ Routes with a larger reveal timeout than timeout_blocks must be ignored. """
    amount = 10
    balance = 20
    timeout_blocks = 10
    routes = [
        factories.make_route(
            factories.HOP1,
            available_balance=balance,
            reveal_timeout=timeout_blocks * 2,
        ),
        factories.make_route(
            factories.HOP2,
            available_balance=balance,
            reveal_timeout=timeout_blocks + 1,
        ),
        factories.make_route(
            factories.HOP3,
            available_balance=balance,
            reveal_timeout=timeout_blocks // 2,
        ),
        factories.make_route(
            factories.HOP4,
            available_balance=balance,
            reveal_timeout=timeout_blocks,
        ),
    ]

    routes_state = RoutesState(
        list(routes))  # copy because the list will be modified inplace
    route1 = mediator.next_route(routes_state, timeout_blocks, amount)
    assert route1 == routes[2]
    assert routes_state.available_routes == [
        routes[3],
    ]
    assert routes_state.ignored_routes == [routes[0], routes[1]]

    assert mediator.next_route(routes_state, timeout_blocks, amount) is None
    assert routes_state.available_routes == list()
    assert routes_state.ignored_routes == [routes[0], routes[1], routes[3]]
示例#13
0
    def mediate_mediated_transfer(self, message):
        # pylint: disable=too-many-locals
        identifier = message.identifier
        amount = message.lock.amount
        target = message.target
        token = message.token
        graph = self.token_to_channelgraph[token]

        available_routes = get_best_routes(
            graph,
            self.protocol.nodeaddresses_networkstatuses,
            self.address,
            target,
            amount,
            message.sender,
        )

        from_channel = graph.partneraddress_to_channel[message.sender]
        from_route = channel_to_routestate(from_channel, message.sender)

        our_address = self.address
        from_transfer = lockedtransfer_from_message(message)
        route_state = RoutesState(available_routes)
        block_number = self.get_block_number()

        init_mediator = ActionInitMediator(
            our_address,
            from_transfer,
            route_state,
            from_route,
            block_number,
        )

        state_manager = StateManager(mediator.state_transition, None)

        self.state_machine_event_handler.log_and_dispatch(
            state_manager, init_mediator)

        self.identifier_to_statemanagers[identifier].append(state_manager)
示例#14
0
    def start_mediated_transfer(self, token_address, amount, identifier,
                                target):
        # pylint: disable=too-many-locals

        async_result = AsyncResult()
        graph = self.token_to_channelgraph[token_address]

        available_routes = get_best_routes(
            graph,
            self.protocol.nodeaddresses_networkstatuses,
            self.address,
            target,
            amount,
            None,
        )

        if not available_routes:
            async_result.set(False)
            return async_result

        self.protocol.start_health_check(target)

        if identifier is None:
            identifier = create_default_identifier()

        route_state = RoutesState(available_routes)
        our_address = self.address
        block_number = self.get_block_number()

        transfer_state = LockedTransferState(
            identifier=identifier,
            amount=amount,
            token=token_address,
            initiator=self.address,
            target=target,
            expiration=None,
            hashlock=None,
            secret=None,
        )

        # Issue #489
        #
        # Raiden may fail after a state change using the random generator is
        # handled but right before the snapshot is taken. If that happens on
        # the next initialization when raiden is recovering and applying the
        # pending state changes a new secret will be generated and the
        # resulting events won't match, this breaks the architecture model,
        # since it's assumed the re-execution of a state change will always
        # produce the same events.
        #
        # TODO: Removed the secret generator from the InitiatorState and add
        # the secret into all state changes that require one, this way the
        # secret will be serialized with the state change and the recovery will
        # use the same /random/ secret.
        random_generator = RandomSecretGenerator()

        init_initiator = ActionInitInitiator(
            our_address=our_address,
            transfer=transfer_state,
            routes=route_state,
            random_generator=random_generator,
            block_number=block_number,
        )

        state_manager = StateManager(initiator.state_transition, None)
        self.state_machine_event_handler.log_and_dispatch(
            state_manager, init_initiator)

        # TODO: implement the network timeout raiden.config['msg_timeout'] and
        # cancel the current transfer if it hapens (issue #374)
        self.identifier_to_statemanagers[identifier].append(state_manager)
        self.identifier_to_results[identifier].append(async_result)

        return async_result
示例#15
0
    def start_mediated_transfer(self, token_address, amount, identifier,
                                target):
        # pylint: disable=too-many-locals
        graph = self.channelgraphs[token_address]
        routes = graph.get_best_routes(
            self.address,
            target,
            amount,
            lock_timeout=None,
        )

        available_routes = [
            route for route in map(route_to_routestate, routes)
            if route.state == CHANNEL_STATE_OPENED
        ]

        # send ping to target to make sure we can receive something back from target
        async_result = self.protocol.send_ping(target)
        async_result.wait(timeout=0.5)  # allow the ping to succeed
        if async_result.ready():
            log.debug("transfer target received invitation ping")
        else:
            log.debug(
                "transfer target did not receive invitation ping, probably behing NAT"
            )

        identifier = create_default_identifier(self.address, token_address,
                                               target)
        route_state = RoutesState(available_routes)
        our_address = self.address
        block_number = self.get_block_number()

        transfer_state = LockedTransferState(
            identifier=identifier,
            amount=amount,
            token=token_address,
            initiator=self.address,
            target=target,
            expiration=None,
            hashlock=None,
            secret=None,
        )

        # Issue #489
        #
        # Raiden may fail after a state change using the random generator is
        # handled but right before the snapshot is taken. If that happens on
        # the next initialization when raiden is recovering and applying the
        # pending state changes a new secret will be generated and the
        # resulting events won't match, this breaks the architecture model,
        # since it's assumed the re-execution of a state change will always
        # produce the same events.
        #
        # TODO: Removed the secret generator from the InitiatorState and add
        # the secret into all state changes that require one, this way the
        # secret will be serialized with the state change and the recovery will
        # use the same /random/ secret.
        random_generator = RandomSecretGenerator()

        init_initiator = ActionInitInitiator(
            our_address=our_address,
            transfer=transfer_state,
            routes=route_state,
            random_generator=random_generator,
            block_number=block_number,
        )

        state_manager = StateManager(initiator.state_transition, None)
        self.state_machine_event_handler.log_and_dispatch(
            state_manager, init_initiator)
        async_result = AsyncResult()

        # TODO: implement the network timeout raiden.config['msg_timeout'] and
        # cancel the current transfer if it hapens (issue #374)
        self.identifier_to_statemanagers[identifier].append(state_manager)
        self.identifier_to_results[identifier].append(async_result)

        return async_result