def restore_from_latest_snapshot(transition_function, storage): snapshot = storage.get_latest_state_snapshot() if snapshot: log.debug('Restoring from snapshot') last_applied_state_change_id, state = snapshot unapplied_state_changes = storage.get_statechanges_by_identifier( from_identifier=last_applied_state_change_id, to_identifier='latest', ) else: log.debug('No snapshot found, replaying all state changes') state = None unapplied_state_changes = storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) state_manager = StateManager(transition_function, state) wal = WriteAheadLog(state_manager, storage) log.debug('Replaying state changes', num_state_changes=len(unapplied_state_changes)) for state_change in unapplied_state_changes: state_manager.dispatch(state_change) return wal
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
def test_state_wait_secretrequest_valid(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR routes = [factories.make_route(mediator_address, available_balance=amount)] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=SequenceGenerator(), identifier=identifier, ) hashlock = current_state.transfer.hashlock state_change = ReceiveSecretRequest( identifier=identifier, amount=amount, hashlock=hashlock, sender=target_address, ) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) events = initiator_state_machine.dispatch(state_change) assert all(isinstance(event, SendRevealSecret) for event in events) assert len(events) == 1
def test_no_valid_routes(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT - 1), factories.make_route(factories.HOP3, available_balance=1), ] init_state_change = make_init_statechange( from_transfer, from_route, routes, ) mediator_state_machine = StateManager( mediator.state_transition, None, ) assert mediator_state_machine.current_state is None events = mediator_state_machine.dispatch( init_state_change, ) assert mediator_state_machine.current_state is None assert len(events) == 1 assert isinstance(events[0], SendRefundTransfer)
def test_no_valid_routes(): from_route, from_transfer = make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT - 1), factories.make_route(factories.HOP3, available_balance=1), ] init_state_change = make_init_statechange( from_transfer, from_route, routes, ) mediator_state_machine = StateManager( mediator.state_transition, None, ) assert mediator_state_machine.current_state is None events = mediator_state_machine.dispatch( init_state_change, ) assert mediator_state_machine.current_state is None assert len(events) == 1 assert isinstance(events[0], SendRefundTransfer)
def test_cancel_transfer(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR routes = [ factories.make_route(mediator_address, available_balance=amount), ] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=SequenceGenerator(), identifier=identifier, ) state_change = ActionCancelTransfer( identifier=identifier ) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) assert initiator_state_machine.current_state is not None events = initiator_state_machine.dispatch(state_change) assert len(events) == 1 assert isinstance(events[0], EventTransferSentFailed) assert initiator_state_machine.current_state is None
def test_state_wait_secretrequest_valid(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR routes = [factories.make_route(mediator_address, available_balance=amount)] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=SequenceGenerator(), identifier=identifier, ) hashlock = current_state.transfer.hashlock state_change = ReceiveSecretRequest( identifier=identifier, amount=amount, hashlock=hashlock, sender=target_address, ) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) events = initiator_state_machine.dispatch(state_change) assert all(isinstance(event, SendRevealSecret) for event in events) assert len(events) == 1
def test_cancel_transfer(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR routes = [ factories.make_route(mediator_address, available_balance=amount), ] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=SequenceGenerator(), identifier=identifier, ) state_change = ActionCancelTransfer(identifier=identifier) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) assert initiator_state_machine.current_state is not None events = initiator_state_machine.dispatch(state_change) assert len(events) == 1 assert isinstance(events[0], EventTransferSentFailed) assert initiator_state_machine.current_state is None
def test_state_wait_unlock_valid(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR secret_generator = SequenceGenerator() token = factories.UNIT_TOKEN_ADDRESS routes = [factories.make_route(mediator_address, available_balance=amount)] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=secret_generator, identifier=identifier, token=token, ) secret = secret_generator.secrets[0] assert secret is not None # setup the state for the wait unlock current_state.revealsecret = SendRevealSecret( identifier, secret, token, target_address, our_address, ) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) state_change = ReceiveSecretReveal( secret=secret, sender=mediator_address, ) events = initiator_state_machine.dispatch(state_change) assert len(events) == 3 assert any(isinstance(e, SendBalanceProof) for e in events) assert any(isinstance(e, EventTransferSentSuccess) for e in events) assert any(isinstance(e, EventUnlockSuccess) for e in events) balance_proof = next(e for e in events if isinstance(e, SendBalanceProof)) complete = next(e for e in events if isinstance(e, EventTransferSentSuccess)) assert balance_proof.receiver == mediator_address assert complete.identifier == identifier assert initiator_state_machine.current_state is None, 'state must be cleaned'
def test_state_wait_unlock_valid(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR secret_generator = SequenceGenerator() token = factories.UNIT_TOKEN_ADDRESS routes = [factories.make_route(mediator_address, available_balance=amount)] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=secret_generator, identifier=identifier, token=token, ) secret = secret_generator.secrets[0] assert secret is not None # setup the state for the wait unlock current_state.revealsecret = SendRevealSecret( identifier, secret, token, target_address, our_address, ) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) state_change = ReceiveSecretReveal( secret=secret, sender=mediator_address, ) events = initiator_state_machine.dispatch(state_change) assert len(events) == 3 assert any(isinstance(e, SendBalanceProof) for e in events) assert any(isinstance(e, EventTransferSentSuccess) for e in events) assert any(isinstance(e, EventUnlockSuccess) for e in events) balance_proof = next(e for e in events if isinstance(e, SendBalanceProof)) complete = next(e for e in events if isinstance(e, EventTransferSentSuccess)) assert balance_proof.receiver == mediator_address assert complete.identifier == identifier assert initiator_state_machine.current_state is None, 'state must be cleaned'
def test_refund_transfer_next_route(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR routes = [ factories.make_route(mediator_address, available_balance=amount), factories.make_route(factories.HOP2, available_balance=amount), ] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=SequenceGenerator(), identifier=identifier, ) transfer = factories.make_transfer( amount, our_address, target_address, block_number + factories.UNIT_SETTLE_TIMEOUT, ) state_change = ReceiveTransferRefund( sender=mediator_address, transfer=transfer, ) prior_state = deepcopy(current_state) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) assert initiator_state_machine.current_state is not None events = initiator_state_machine.dispatch(state_change) assert len(events) == 1 assert any( isinstance(e, SendMediatedTransfer) for e in events ), 'No mediated transfer event emitted, should have tried a new route' assert initiator_state_machine.current_state is not None assert initiator_state_machine.current_state.routes.canceled_routes[ 0] == prior_state.route
def test_init_mediator(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT), ] init_state_change = make_init_statechange( from_transfer, from_route, routes, ) mediator_state_machine = StateManager( mediator.state_transition, None, ) assert mediator_state_machine.current_state is None events = mediator_state_machine.dispatch(init_state_change, ) mediator_state = mediator_state_machine.current_state assert isinstance(mediator_state, MediatorState) assert mediator_state.our_address == factories.ADDR assert mediator_state.block_number == init_state_change.block_number assert mediator_state.transfers_pair[0].payer_transfer == from_transfer assert mediator_state.transfers_pair[0].payer_route == from_route assert len( events ), 'we have a valid route, the mediated transfer event must be emited' mediated_transfers = [ e for e in events if isinstance(e, SendMediatedTransfer) ] assert len(mediated_transfers ) == 1, 'mediated_transfer should /not/ split the transfer' mediated_transfer = mediated_transfers[0] assert mediated_transfer.token == from_transfer.token, 'transfer token address mismatch' assert mediated_transfer.amount == from_transfer.amount, 'transfer amount mismatch' assert mediated_transfer.expiration < from_transfer.expiration, 'transfer expiration mismatch' assert mediated_transfer.hashlock == from_transfer.hashlock, 'wrong hashlock'
def test_refund_transfer_next_route(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR routes = [ factories.make_route(mediator_address, available_balance=amount), factories.make_route(factories.HOP2, available_balance=amount), ] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=SequenceGenerator(), identifier=identifier, ) transfer = factories.make_transfer( amount, our_address, target_address, block_number + factories.UNIT_SETTLE_TIMEOUT, ) state_change = ReceiveTransferRefund( sender=mediator_address, transfer=transfer, ) prior_state = deepcopy(current_state) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) assert initiator_state_machine.current_state is not None events = initiator_state_machine.dispatch(state_change) assert len(events) == 1 assert any( isinstance(e, SendMediatedTransfer) for e in events ), 'No mediated transfer event emitted, should have tried a new route' assert initiator_state_machine.current_state is not None assert initiator_state_machine.current_state.routes.canceled_routes[0] == prior_state.route
def test_init_mediator(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT), ] init_state_change = make_init_statechange( from_transfer, from_route, routes, ) mediator_state_machine = StateManager( mediator.state_transition, None, ) assert mediator_state_machine.current_state is None events = mediator_state_machine.dispatch( init_state_change, ) mediator_state = mediator_state_machine.current_state assert isinstance(mediator_state, MediatorState) assert mediator_state.our_address == factories.ADDR assert mediator_state.block_number == init_state_change.block_number assert mediator_state.transfers_pair[0].payer_transfer == from_transfer assert mediator_state.transfers_pair[0].payer_route == from_route assert len(events), 'we have a valid route, the mediated transfer event must be emited' mediated_transfers = [ e for e in events if isinstance(e, SendMediatedTransfer) ] assert len(mediated_transfers) == 1, 'mediated_transfer should /not/ split the transfer' mediated_transfer = mediated_transfers[0] assert mediated_transfer.token == from_transfer.token, 'transfer token address mismatch' assert mediated_transfer.amount == from_transfer.amount, 'transfer amount mismatch' assert mediated_transfer.expiration < from_transfer.expiration, 'transfer expiration mismatch' assert mediated_transfer.hashlock == from_transfer.hashlock, 'wrong hashlock'
def test_state_wait_unlock_invalid(): identifier = identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR secret_generator = SequenceGenerator() token = factories.UNIT_TOKEN_ADDRESS routes = [factories.make_route(mediator_address, available_balance=amount)] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=secret_generator, token=token, ) secret = secret_generator.secrets[0] assert secret is not None current_state.revealsecret = SendRevealSecret( identifier, secret, token, target_address, our_address, ) before_state = deepcopy(current_state) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) state_change = ReceiveSecretReveal( secret=secret, sender=factories.ADDR, ) events = initiator_state_machine.dispatch(state_change) assert len(events) == 0 assert initiator_state_machine.current_state.revealsecret is not None assert_state_equal(initiator_state_machine.current_state, current_state) assert_state_equal(current_state, before_state)
def test_state_wait_unlock_invalid(): identifier = identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR secret_generator = SequenceGenerator() token = factories.UNIT_TOKEN_ADDRESS routes = [factories.make_route(mediator_address, available_balance=amount)] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=secret_generator, token=token, ) secret = secret_generator.secrets[0] assert secret is not None current_state.revealsecret = SendRevealSecret( identifier, secret, token, target_address, our_address, ) before_state = deepcopy(current_state) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) state_change = ReceiveSecretReveal( secret=secret, sender=factories.ADDR, ) events = initiator_state_machine.dispatch(state_change) assert len(events) == 0 assert initiator_state_machine.current_state.revealsecret is not None assert_state_equal(initiator_state_machine.current_state, current_state) assert_state_equal(current_state, before_state)
def test_state_wait_unlock_valid(): identifier = identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR secret_generator = SequenceGenerator() routes = [factories.make_route(mediator_address, available_balance=amount)] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=secret_generator, ) secret = secret_generator.secrets[0] assert secret is not None # setup the state for the wait unlock current_state.revealsecret = SendRevealSecret( identifier, secret, target_address, our_address, ) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) state_change = ReceiveSecretReveal( identifier=identifier, secret=secret, target=our_address, sender=mediator_address, ) events = initiator_state_machine.dispatch(state_change) assert len(events) == 1 assert isinstance(events[0], SendRevealSecret) assert events[0].target == mediator_address assert initiator_state_machine.current_state is None, 'state must be cleaned'
def test_refund_transfer_invalid_sender(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR routes = [ factories.make_route(mediator_address, available_balance=amount), ] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=SequenceGenerator(), identifier=identifier, ) transfer = factories.make_transfer( amount, our_address, target_address, block_number + factories.UNIT_SETTLE_TIMEOUT, ) state_change = ReceiveTransferRefund( sender=our_address, transfer=transfer, ) prior_state = deepcopy(current_state) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) assert initiator_state_machine.current_state is not None events = initiator_state_machine.dispatch(state_change) assert len(events) == 0 assert initiator_state_machine.current_state is not None assert_state_equal(initiator_state_machine.current_state, prior_state)
def test_refund_transfer_invalid_sender(): identifier = 1 amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR routes = [ factories.make_route(mediator_address, available_balance=amount), ] current_state = make_initiator_state( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=SequenceGenerator(), identifier=identifier, ) transfer = factories.make_transfer( amount, our_address, target_address, block_number + factories.UNIT_SETTLE_TIMEOUT, ) state_change = ReceiveTransferRefund( sender=our_address, transfer=transfer, ) prior_state = deepcopy(current_state) initiator_state_machine = StateManager( initiator.state_transition, current_state, ) assert initiator_state_machine.current_state is not None events = initiator_state_machine.dispatch(state_change) assert len(events) == 0 assert initiator_state_machine.current_state is not None assert_state_equal(initiator_state_machine.current_state, prior_state)
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)
def restore_from_latest_snapshot(transition_function, storage): events = list() snapshot = storage.get_state_snapshot() if snapshot: last_applied_state_change_id, state = snapshot unapplied_state_changes = storage.get_statechanges_by_identifier( from_identifier=last_applied_state_change_id, to_identifier='latest', ) else: state = None unapplied_state_changes = list() state_manager = StateManager(transition_function, state) wal = WriteAheadLog(state_manager, storage) for state_change in unapplied_state_changes: events.extend(state_manager.dispatch(state_change)) return wal, events
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
def target_mediated_transfer(self, message): graph = self.channelgraphs[message.token] from_channel = graph.partneraddress_channel[message.sender] from_route = channel_to_routestate(from_channel, message.sender) from_transfer = lockedtransfer_from_message(message) our_address = self.address block_number = self.get_block_number() init_target = ActionInitTarget( our_address, from_route, from_transfer, block_number, ) state_manager = StateManager(target_task.state_transition, None) all_events = state_manager.dispatch(init_target) for event in all_events: self.state_machine_event_handler.on_event(event) identifier = message.identifier self.identifier_statemanager[identifier].append(state_manager)
def test_init_with_usable_routes(): amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR secret_generator = SequenceGenerator() routes = [factories.make_route(mediator_address, available_balance=amount)] init_state_change = make_init_statechange( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=secret_generator, ) expiration = block_number + factories.HOP1_TIMEOUT initiator_state_machine = StateManager( initiator.state_transition, None, ) assert initiator_state_machine.current_state is None events = initiator_state_machine.dispatch( init_state_change, ) initiator_state = initiator_state_machine.current_state assert isinstance(initiator_state, InitiatorState) assert initiator_state.our_address == our_address transfer = initiator_state.transfer assert isinstance(transfer, LockedTransferState) assert transfer.amount == amount assert transfer.target == target_address assert transfer.secret == secret_generator.secrets[0] assert transfer.hashlock == sha3(transfer.secret) assert len(events), 'we have a valid route, the mediated transfer event must be emited' mediated_transfers = [ e for e in events if isinstance(e, SendMediatedTransfer) ] assert len(mediated_transfers) == 1, 'mediated_transfer should /not/ split the transfer' mediated_transfer = mediated_transfers[0] assert mediated_transfer.token == factories.UNIT_TOKEN_ADDRESS assert mediated_transfer.amount == amount, 'transfer amount mismatch' assert mediated_transfer.expiration == expiration, 'transfer expiration mismatch' secret_hash = sha3(secret_generator.secrets[0]) assert mediated_transfer.hashlock == secret_hash, 'wrong hashlock' assert mediated_transfer.receiver == mediator_address, 'wrong mediator address' assert initiator_state.route == routes[0] assert len(initiator_state.routes.available_routes) == 0 assert len(initiator_state.routes.ignored_routes) == 0 assert len(initiator_state.routes.refunded_routes) == 0 assert len(initiator_state.routes.canceled_routes) == 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 ] 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) all_events = state_manager.dispatch(init_initiator) for event in all_events: self.state_machine_event_handler.on_event(event) async_result = AsyncResult() # TODO: implement the network timeout raiden.config['msg_timeout'] and # cancel the current transfer if it hapens (issue #374) self.identifier_statemanager[identifier].append(state_manager) self.identifier_result[identifier].append(async_result) return async_result
def test_init_with_usable_routes(): amount = factories.UNIT_TRANSFER_AMOUNT block_number = 1 mediator_address = factories.HOP1 target_address = factories.HOP2 our_address = factories.ADDR secret_generator = SequenceGenerator() routes = [factories.make_route(mediator_address, available_balance=amount)] init_state_change = make_init_statechange( routes, target_address, block_number=block_number, our_address=our_address, secret_generator=secret_generator, ) expiration = block_number + factories.HOP1_TIMEOUT initiator_state_machine = StateManager( initiator.state_transition, None, ) assert initiator_state_machine.current_state is None events = initiator_state_machine.dispatch(init_state_change, ) initiator_state = initiator_state_machine.current_state assert isinstance(initiator_state, InitiatorState) assert initiator_state.our_address == our_address transfer = initiator_state.transfer assert isinstance(transfer, LockedTransferState) assert transfer.amount == amount assert transfer.target == target_address assert transfer.secret == secret_generator.secrets[0] assert transfer.hashlock == sha3(transfer.secret) assert len( events ), 'we have a valid route, the mediated transfer event must be emited' mediated_transfers = [ e for e in events if isinstance(e, SendMediatedTransfer) ] assert len(mediated_transfers ) == 1, 'mediated_transfer should /not/ split the transfer' mediated_transfer = mediated_transfers[0] assert mediated_transfer.token == factories.UNIT_TOKEN_ADDRESS assert mediated_transfer.amount == amount, 'transfer amount mismatch' assert mediated_transfer.expiration == expiration, 'transfer expiration mismatch' assert mediated_transfer.hashlock == sha3( secret_generator.secrets[0]), 'wrong hashlock' assert mediated_transfer.receiver == mediator_address, 'wrong mediator address' assert initiator_state.route == routes[0] assert len(initiator_state.routes.available_routes) == 0 assert len(initiator_state.routes.ignored_routes) == 0 assert len(initiator_state.routes.refunded_routes) == 0 assert len(initiator_state.routes.canceled_routes) == 0