def get_network_graph(self, token_network_address): chain_state = views.state_from_raiden(self.raiden) token_network_state = views.get_token_network_by_identifier( chain_state=chain_state, token_network_id=token_network_address ) return token_network_state.network_graph
def handle_token_network_action( chain_state: ChainState, state_change: StateChange, ) -> TransitionResult: token_network_state = views.get_token_network_by_identifier( chain_state, state_change.token_network_identifier, ) payment_network_state = views.get_token_network_registry_by_token_network_identifier( chain_state, state_change.token_network_identifier, ) assert payment_network_state, 'We should always get a payment_network_state' payment_network_id = payment_network_state.address events = list() if token_network_state: pseudo_random_generator = chain_state.pseudo_random_generator iteration = token_network.state_transition( payment_network_id, token_network_state, state_change, pseudo_random_generator, chain_state.block_number, ) assert iteration.new_state, 'No token network state transition leads to None' events = iteration.events return TransitionResult(chain_state, events)
def handle_token_network_action(node_state, state_change): token_network_state = views.get_token_network_by_identifier( node_state, state_change.token_network_identifier, ) events = list() if token_network_state: pseudo_random_generator = node_state.pseudo_random_generator iteration = token_network.state_transition( token_network_state, state_change, pseudo_random_generator, node_state.block_number, ) if iteration.new_state is None: payment_network_state = views.search_payment_network_by_token_network_id( node_state, state_change.token_network_identifier, ) del payment_network_state.tokenaddresses_to_tokennetworks[ token_network_state.token_address ] del payment_network_state.tokenidentifiers_to_tokennetworks[ token_network_state.address ] events = iteration.events return TransitionResult(node_state, events)
def __init__(self, raiden, token_network_identifier): chain_state = views.state_from_raiden(raiden) token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) token_network_registry = views.get_token_network_registry_by_token_network_identifier( chain_state, token_network_identifier, ) # TODO: # - Add timeout for transaction polling, used to overwrite the RaidenAPI # defaults # - Add a proper selection strategy (#576) self.funds = 0 self.initial_channel_target = 0 self.joinable_funds_target = 0 self.raiden = raiden self.registry_address = token_network_registry.address self.token_network_identifier = token_network_identifier self.token_address = token_network_state.token_address self.lock = Semaphore() #: protects self.funds and self.initial_channel_target self.api = RaidenAPI(raiden)
def _is_internal_event( self, event, token_address, ): if hasattr(event, 'transfer') and event.transfer.token == token_address: return True elif getattr(event, 'token', None) == token_address: return True elif getattr(event, 'token_address', None) == token_address: return True elif isinstance(event, EVENTS_PAYMENT_HISTORY_RELATED): token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_raiden(self.raiden), event.payment_network_identifier, token_address, ) if token_network_identifier == event.token_network_identifier: return True elif type(event) == ContractSendChannelSettle: token_network_state = views.get_token_network_by_identifier( views.state_from_raiden(self.raiden), event.token_network_identifier, ) if token_network_state.token_address == token_address: return True return False
def handle_channel_batch_unlock( node_state: NodeState, state_change: ContractReceiveChannelBatchUnlock, ) -> TransitionResult: token_network_identifier = state_change.token_network_identifier token_network_state = views.get_token_network_by_identifier( node_state, token_network_identifier, ) events = [] if token_network_state: pseudo_random_generator = node_state.pseudo_random_generator sub_iteration = token_network.subdispatch_to_channel_by_id( token_network_state, state_change, pseudo_random_generator, node_state.block_number, ) events.extend(sub_iteration.events) if sub_iteration.new_state is None: payment_network_state = views.get_payment_network_by_identifier( node_state, token_network_state.address, ) del payment_network_state.tokenaddresses_to_tokennetworks[ token_network_state.token_address] del payment_network_state.tokenidentifiers_to_tokennetworks[ token_network_identifier] return TransitionResult(node_state, events)
def subdispatch_mediatortask( chain_state: ChainState, state_change: StateChange, token_network_identifier: TokenNetworkID, secrethash: SecretHash, ) -> TransitionResult[ChainState]: block_number = chain_state.block_number block_hash = chain_state.block_hash sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) if not sub_task: is_valid_subtask = True mediator_state = None elif sub_task and isinstance(sub_task, MediatorTask): is_valid_subtask = ( token_network_identifier == sub_task.token_network_identifier) mediator_state = sub_task.mediator_state else: is_valid_subtask = False events: List[Event] = list() if is_valid_subtask: token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) pseudo_random_generator = chain_state.pseudo_random_generator iteration = mediator.state_transition( mediator_state=mediator_state, state_change=state_change, channelidentifiers_to_channels=token_network_state. channelidentifiers_to_channels, nodeaddresses_to_networkstates=chain_state. nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_number, block_hash=block_hash, ) events = iteration.events if iteration.new_state: sub_task = MediatorTask( token_network_identifier, iteration.new_state, ) chain_state.payment_mapping.secrethashes_to_task[ secrethash] = sub_task elif secrethash in chain_state.payment_mapping.secrethashes_to_task: del chain_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(chain_state, events)
def handle_channel_batch_unlock( chain_state: ChainState, state_change: ContractReceiveChannelBatchUnlock, ) -> TransitionResult: token_network_identifier = state_change.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) events = [] if token_network_state: payment_network_state = views.get_token_network_registry_by_token_network_identifier( chain_state, token_network_state.address, ) pseudo_random_generator = chain_state.pseudo_random_generator participant1 = state_change.participant participant2 = state_change.partner for channel_state in token_network_state.channelidentifiers_to_channels.values(): are_addresses_valid1 = ( channel_state.our_state.address == participant1 and channel_state.partner_state.address == participant2 ) are_addresses_valid2 = ( channel_state.our_state.address == participant2 and channel_state.partner_state.address == participant1 ) is_valid_locksroot = True is_valid_channel = ( (are_addresses_valid1 or are_addresses_valid2) and is_valid_locksroot ) if is_valid_channel: sub_iteration = channel.state_transition( channel_state, state_change, pseudo_random_generator, chain_state.block_number, ) events.extend(sub_iteration.events) if sub_iteration.new_state is None: del payment_network_state.tokenaddresses_to_tokennetworks[ token_network_state.token_address ] del payment_network_state.tokenidentifiers_to_tokennetworks[ token_network_identifier ] return TransitionResult(chain_state, events)
def subdispatch_mediatortask( chain_state: ChainState, state_change: StateChange, token_network_identifier: TokenNetworkID, secrethash: SecretHash, ) -> TransitionResult: block_number = chain_state.block_number sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) if not sub_task: is_valid_subtask = True mediator_state = None elif sub_task and isinstance(sub_task, MediatorTask): is_valid_subtask = ( token_network_identifier == sub_task.token_network_identifier ) mediator_state = sub_task.mediator_state else: is_valid_subtask = False events = list() if is_valid_subtask: token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) pseudo_random_generator = chain_state.pseudo_random_generator iteration = mediator.state_transition( mediator_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = iteration.events if iteration.new_state: sub_task = MediatorTask( token_network_identifier, iteration.new_state, ) chain_state.payment_mapping.secrethashes_to_task[secrethash] = sub_task elif secrethash in chain_state.payment_mapping.secrethashes_to_task: del chain_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(chain_state, events)
def subdispatch_mediatortask( node_state, state_change, token_network_identifier, secrethash, ): block_number = node_state.block_number sub_task = node_state.payment_mapping.secrethashes_to_task.get(secrethash) if not sub_task: is_valid_subtask = True mediator_state = None elif sub_task and isinstance(sub_task, PaymentMappingState.MediatorTask): is_valid_subtask = ( token_network_identifier == sub_task.token_network_identifier ) mediator_state = sub_task.mediator_state else: is_valid_subtask = False events = list() if is_valid_subtask: token_network_state = views.get_token_network_by_identifier( node_state, token_network_identifier, ) pseudo_random_generator = node_state.pseudo_random_generator iteration = mediator.state_transition( mediator_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = iteration.events if iteration.new_state: sub_task = PaymentMappingState.MediatorTask( token_network_identifier, iteration.new_state, ) node_state.payment_mapping.secrethashes_to_task[secrethash] = sub_task elif secrethash in node_state.payment_mapping.secrethashes_to_task: del node_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(node_state, events)
def subdispatch_initiatortask( chain_state: ChainState, state_change: StateChange, token_network_identifier: typing.TokenNetworkID, secrethash: typing.SecretHash, ) -> TransitionResult: block_number = chain_state.block_number sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) if not sub_task: is_valid_subtask = True manager_state = None elif sub_task and isinstance(sub_task, InitiatorTask): is_valid_subtask = ( token_network_identifier == sub_task.token_network_identifier ) manager_state = sub_task.manager_state else: is_valid_subtask = False events = list() if is_valid_subtask: pseudo_random_generator = chain_state.pseudo_random_generator token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) iteration = initiator_manager.state_transition( manager_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = iteration.events if iteration.new_state: sub_task = InitiatorTask( token_network_identifier, iteration.new_state, ) chain_state.payment_mapping.secrethashes_to_task[secrethash] = sub_task elif secrethash in chain_state.payment_mapping.secrethashes_to_task: del chain_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(chain_state, events)
def get_best_routes_internal( chain_state: ChainState, token_network_id: typing.TokenNetworkID, from_address: typing.InitiatorAddress, to_address: typing.TargetAddress, amount: int, previous_address: typing.Optional[typing.Address], ) -> List[RouteState]: """ Returns a list of channels that can be used to make a transfer. This will filter out channels that are not open and don't have enough capacity. """ # TODO: Route ranking. # Rate each route to optimize the fee price/quality of each route and add a # rate from in the range [0.0,1.0]. available_routes = list() token_network = views.get_token_network_by_identifier( chain_state, token_network_id, ) neighbors_heap = list() try: all_neighbors = networkx.all_neighbors(token_network.network_graph.network, from_address) except networkx.NetworkXError: # If `our_address` is not in the graph, no channels opened with the # address return list() for partner_address in all_neighbors: # don't send the message backwards if partner_address == previous_address: continue channel_state = views.get_channelstate_by_token_network_and_partner( chain_state, token_network_id, partner_address, ) if channel.get_status(channel_state) != CHANNEL_STATE_OPENED: log.info( 'Channel is not opened, ignoring', from_address=pex(from_address), partner_address=pex(partner_address), routing_source='Internal Routing', ) continue nonrefundable = amount > channel.get_distributable( channel_state.partner_state, channel_state.our_state, ) try: length = networkx.shortest_path_length( token_network.network_graph.network, partner_address, to_address, ) heappush( neighbors_heap, (length, nonrefundable, partner_address, channel_state.identifier), ) except (networkx.NetworkXNoPath, networkx.NodeNotFound): pass if not neighbors_heap: log.warning( 'No routes available', from_address=pex(from_address), to_address=pex(to_address), ) return list() while neighbors_heap: *_, partner_address, channel_state_id = heappop(neighbors_heap) route_state = RouteState(partner_address, channel_state_id) available_routes.append(route_state) return available_routes
def test_clear_closed_queue(raiden_network, token_addresses, deposit): """ Closing a channel clears the respective message queue. """ app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] chain_state0 = views.state_from_app(app0) token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state0, app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( chain_state0, token_network_identifier, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address ] app1.raiden.transport.stop() app1.raiden.transport.get() # make a direct transfer to ensure the nodes have communicated amount = 10 payment_identifier = 1337 app0.raiden.direct_transfer_async( token_network_identifier, amount, app1.raiden.address, identifier=payment_identifier, ) # assert the specific queue is present chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue_id.channel_identifier == channel_identifier and queue ] # A ChannelClose event will be generated, this will be polled by both apps RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) exception = ValueError('Could not get close event') with gevent.Timeout(seconds=30, exception=exception): waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) # assert all queues with this partner are gone or empty chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert not [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue ] chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) assert not [ (queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue ]
def test_settle_is_automatically_called(raiden_network, token_addresses): """Settle is automatically called by one of the nodes.""" app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(app0), token_network_identifier, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address ] # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) channel_state = views.get_channelstate_for( views.state_from_raiden(app0.raiden), registry_address, token_address, app1.raiden.address, ) assert channel_state.close_transaction.finished_block_number waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) token_network = views.get_token_network_by_identifier( views.state_from_app(app0), token_network_identifier, ) assert channel_identifier not in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address ] state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry(state_changes, ContractReceiveChannelClosed, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'transaction_from': app1.raiden.address, 'block_number': channel_state.close_transaction.finished_block_number, }) assert must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_lock_expiry(raiden_network, token_addresses, deposit): """Test lock expiry and removal.""" alice_app, bob_app = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) hold_event_handler = HoldOffChainSecretRequest() wait_message_handler = WaitForMessage() bob_app.raiden.message_handler = wait_message_handler bob_app.raiden.raiden_event_handler = hold_event_handler token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) channel_identifier = channel_state.identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ bob_app.raiden.address ] alice_to_bob_amount = 10 identifier = 1 target = bob_app.raiden.address transfer_1_secret = factories.make_secret(0) transfer_1_secrethash = sha3(transfer_1_secret) transfer_2_secret = factories.make_secret(1) transfer_2_secrethash = sha3(transfer_2_secret) hold_event_handler.hold_secretrequest_for(secrethash=transfer_1_secrethash) transfer1_received = wait_message_handler.wait_for_message( LockedTransfer, {'lock': {'secrethash': transfer_1_secrethash}}, ) transfer2_received = wait_message_handler.wait_for_message( LockedTransfer, {'lock': {'secrethash': transfer_2_secrethash}}, ) remove_expired_lock_received = wait_message_handler.wait_for_message( LockExpired, {'secrethash': transfer_1_secrethash}, ) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier, alice_to_bob_amount, target, identifier, transfer_1_secret, ) transfer1_received.wait() alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # Verify lock is registered in both channel states alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task remove_expired_lock_received.wait() alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks # Verify Bob received the message and processed the LockExpired message bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task # Make another transfer alice_to_bob_amount = 10 identifier = 2 hold_event_handler.hold_secretrequest_for(secrethash=transfer_2_secrethash) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier, alice_to_bob_amount, target, identifier, transfer_2_secret, ) transfer2_received.wait() # Make sure the other transfer still exists alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks
def test_batch_unlock(raiden_network, token_addresses, secret_registry_address, deposit): """Batch unlock can be called after the channel is settled.""" alice_app, bob_app = raiden_network registry_address = alice_app.raiden.default_registry.address token_address = token_addresses[0] token_proxy = alice_app.raiden.chain.token(token_address) token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) hold_event_handler = HoldOffChainSecretRequest() bob_app.raiden.raiden_event_handler = hold_event_handler # Take a snapshot early on alice_app.raiden.wal.snapshot() token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_identifier = get_channelstate(alice_app, bob_app, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ bob_app.raiden.address ] alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address) bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address) # Take snapshot before transfer alice_app.raiden.wal.snapshot() alice_to_bob_amount = 10 identifier = 1 target = bob_app.raiden.address secret = sha3(target) secrethash = sha3(secret) hold_event_handler.hold_secretrequest_for(secrethash=secrethash) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier, alice_to_bob_amount, target, identifier, secret, ) gevent.sleep(1) # wait for the messages to be exchanged alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # Take a snapshot early on alice_app.raiden.wal.snapshot() our_balance_proof = alice_bob_channel_state.our_state.balance_proof # Test WAL restore to return the latest channel state restored_channel_state = channel_state_until_state_change( raiden=alice_app.raiden, payment_network_identifier=alice_app.raiden.default_registry.address, token_address=token_address, channel_identifier=alice_bob_channel_state.identifier, state_change_identifier='latest', ) our_restored_balance_proof = restored_channel_state.our_state.balance_proof assert our_balance_proof == our_restored_balance_proof # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(bob_app.raiden).channel_close( registry_address, token_address, alice_app.raiden.address, ) secret_registry_proxy = alice_app.raiden.chain.secret_registry( secret_registry_address, ) secret_registry_proxy.register_secret(secret) assert lock, 'the lock must still be part of the node state' msg = 'the secret must be registered before the lock expires' assert lock.expiration > alice_app.raiden.get_block_number(), msg assert lock.secrethash == sha3(secret) waiting.wait_for_settle( alice_app.raiden, registry_address, token_address, [alice_bob_channel_state.identifier], alice_app.raiden.alarm.sleep_time, ) token_network = views.get_token_network_by_identifier( views.state_from_app(bob_app), token_network_identifier, ) assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ alice_app.raiden.address ] # wait for the node to call batch unlock with gevent.Timeout(10): wait_for_batch_unlock( bob_app, token_network_identifier, alice_bob_channel_state.partner_state.address, alice_bob_channel_state.our_state.address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(bob_app), token_network_identifier, ) assert channel_identifier not in token_network.partneraddresses_to_channelidentifiers[ alice_app.raiden.address ] alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount assert token_proxy.balance_of(alice_app.raiden.address) == alice_new_balance assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance
def get_best_routes_internal( chain_state: ChainState, token_network_id: typing.TokenNetworkID, from_address: typing.InitiatorAddress, to_address: typing.TargetAddress, amount: int, previous_address: typing.Optional[typing.Address], ) -> List[RouteState]: """ Returns a list of channels that can be used to make a transfer. This will filter out channels that are not open and don't have enough capacity. """ # TODO: Route ranking. # Rate each route to optimize the fee price/quality of each route and add a # rate from in the range [0.0,1.0]. available_routes = list() token_network = views.get_token_network_by_identifier( chain_state, token_network_id, ) network_statuses = views.get_networkstatuses(chain_state) neighbors_heap = list() try: all_neighbors = networkx.all_neighbors(token_network.network_graph.network, from_address) except networkx.NetworkXError: # If `our_address` is not in the graph, no channels opened with the # address return list() for partner_address in all_neighbors: # don't send the message backwards if partner_address == previous_address: continue channel_state = views.get_channelstate_by_token_network_and_partner( chain_state, token_network_id, partner_address, ) channel_constraints_fulfilled = check_channel_constraints( channel_state=channel_state, from_address=from_address, partner_address=partner_address, amount=amount, network_statuses=network_statuses, routing_module='Internal Routing', ) if not channel_constraints_fulfilled: continue nonrefundable = amount > channel.get_distributable( channel_state.partner_state, channel_state.our_state, ) try: length = networkx.shortest_path_length( token_network.network_graph.network, partner_address, to_address, ) heappush( neighbors_heap, (length, nonrefundable, partner_address, channel_state.identifier), ) except (networkx.NetworkXNoPath, networkx.NodeNotFound): pass if not neighbors_heap: log.warning( 'No routes available', from_address=pex(from_address), to_address=pex(to_address), ) return list() while neighbors_heap: *_, partner_address, channel_state_id = heappop(neighbors_heap) route_state = RouteState(partner_address, channel_state_id) available_routes.append(route_state) return available_routes
def test_batch_unlock(raiden_network, token_addresses, secret_registry_address, deposit): """Batch unlock can be called after the channel is settled.""" alice_app, bob_app = raiden_network registry_address = alice_app.raiden.default_registry.address token_address = token_addresses[0] token_proxy = alice_app.raiden.chain.token(token_address) token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) hold_event_handler = HoldOffChainSecretRequest() bob_app.raiden.raiden_event_handler = hold_event_handler # Take a snapshot early on alice_app.raiden.wal.snapshot() token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_identifier = get_channelstate(alice_app, bob_app, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ bob_app.raiden.address] alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address) bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address) # Take snapshot before transfer alice_app.raiden.wal.snapshot() alice_to_bob_amount = 10 identifier = 1 target = bob_app.raiden.address secret = sha3(target) secrethash = sha3(secret) hold_event_handler.hold_secretrequest_for(secrethash=secrethash) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier, alice_to_bob_amount, target, identifier, secret, ) gevent.sleep(1) # wait for the messages to be exchanged alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # Take a snapshot early on alice_app.raiden.wal.snapshot() our_balance_proof = alice_bob_channel_state.our_state.balance_proof # Test WAL restore to return the latest channel state restored_channel_state = channel_state_until_state_change( raiden=alice_app.raiden, payment_network_identifier=alice_app.raiden.default_registry.address, token_address=token_address, channel_identifier=alice_bob_channel_state.identifier, state_change_identifier='latest', ) our_restored_balance_proof = restored_channel_state.our_state.balance_proof assert our_balance_proof == our_restored_balance_proof # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(bob_app.raiden).channel_close( registry_address, token_address, alice_app.raiden.address, ) secret_registry_proxy = alice_app.raiden.chain.secret_registry( secret_registry_address, ) secret_registry_proxy.register_secret(secret) assert lock, 'the lock must still be part of the node state' msg = 'the secret must be registered before the lock expires' assert lock.expiration > alice_app.raiden.get_block_number(), msg assert lock.secrethash == sha3(secret) waiting.wait_for_settle( alice_app.raiden, registry_address, token_address, [alice_bob_channel_state.identifier], alice_app.raiden.alarm.sleep_time, ) token_network = views.get_token_network_by_identifier( views.state_from_app(bob_app), token_network_identifier, ) assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ alice_app.raiden.address] # wait for the node to call batch unlock with gevent.Timeout(10): wait_for_batch_unlock( bob_app, token_network_identifier, alice_bob_channel_state.partner_state.address, alice_bob_channel_state.our_state.address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(bob_app), token_network_identifier, ) assert channel_identifier not in token_network.partneraddresses_to_channelidentifiers[ alice_app.raiden.address] alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount assert token_proxy.balance_of( alice_app.raiden.address) == alice_new_balance assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance
def test_mediator_clear_pairs_after_batch_unlock(chain_state, token_network_state, our_address, channel_properties): """ Regression test for https://github.com/raiden-network/raiden/issues/2932 The mediator must also clear the transfer pairs once a ReceiveBatchUnlock where he is a participant is received. """ open_block_number = 10 open_block_hash = factories.make_block_hash() properties, pkey = channel_properties address = properties.partner_state.address channel_state = factories.create(properties) channel_new_state_change = ContractReceiveChannelNew( transaction_hash=factories.make_transaction_hash(), channel_state=channel_state, block_number=open_block_number, block_hash=open_block_hash, ) channel_new_iteration = token_network.state_transition( token_network_state=token_network_state, state_change=channel_new_state_change, block_number=open_block_number, block_hash=open_block_hash, ) lock_amount = 30 lock_expiration = 20 lock_secret = sha3(b"test_end_state") lock_secrethash = sha3(lock_secret) lock = HashTimeLockState(lock_amount, lock_expiration, lock_secrethash) mediated_transfer = make_receive_transfer_mediated( channel_state=channel_state, privkey=pkey, nonce=1, transferred_amount=0, lock=lock) from_route = factories.make_route_from_channel(channel_state) init_mediator = ActionInitMediator(routes=[from_route], from_route=from_route, from_transfer=mediated_transfer) node.state_transition(chain_state, init_mediator, None) closed_block_number = open_block_number + 10 closed_block_hash = factories.make_block_hash() channel_close_state_change = ContractReceiveChannelClosed( transaction_hash=factories.make_transaction_hash(), transaction_from=channel_state.partner_state.address, canonical_identifier=channel_state.canonical_identifier, block_number=closed_block_number, block_hash=closed_block_hash, ) channel_closed_iteration = token_network.state_transition( token_network_state=channel_new_iteration.new_state, state_change=channel_close_state_change, block_number=closed_block_number, block_hash=closed_block_hash, ) settle_block_number = closed_block_number + channel_state.settle_timeout + 1 channel_settled_state_change = ContractReceiveChannelSettled( transaction_hash=factories.make_transaction_hash(), canonical_identifier=channel_state.canonical_identifier, block_number=settle_block_number, block_hash=factories.make_block_hash(), our_onchain_locksroot=factories.make_32bytes(), partner_onchain_locksroot=EMPTY_MERKLE_ROOT, ) channel_settled_iteration = token_network.state_transition( token_network_state=channel_closed_iteration.new_state, state_change=channel_settled_state_change, block_number=closed_block_number, block_hash=closed_block_hash, ) token_network_state_after_settle = channel_settled_iteration.new_state ids_to_channels = token_network_state_after_settle.channelidentifiers_to_channels assert len(ids_to_channels) == 1 assert channel_state.identifier in ids_to_channels block_number = closed_block_number + 1 channel_batch_unlock_state_change = ContractReceiveChannelBatchUnlock( transaction_hash=factories.make_transaction_hash(), canonical_identifier=channel_state.canonical_identifier, participant=address, partner=our_address, locksroot=lock_secrethash, unlocked_amount=lock_amount, returned_tokens=0, block_number=block_number, block_hash=factories.make_block_hash(), ) channel_unlock_iteration = node.state_transition( chain_state=chain_state, state_change=channel_batch_unlock_state_change, storage=None) chain_state = channel_unlock_iteration.new_state token_network_state = views.get_token_network_by_identifier( chain_state=chain_state, token_network_id=token_network_state.address) ids_to_channels = token_network_state.channelidentifiers_to_channels assert len(ids_to_channels) == 0 # Make sure that all is fine in the next block block = Block(block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash()) iteration = node.state_transition(chain_state=chain_state, state_change=block, storage=None) assert iteration.new_state # Make sure that mediator task was cleared during the next block processing # since the channel was removed mediator_task = chain_state.payment_mapping.secrethashes_to_task.get( lock_secrethash) assert not mediator_task
def subdispatch_to_paymenttask( chain_state: ChainState, state_change: StateChange, secrethash: SecretHash, ) -> TransitionResult[ChainState]: block_number = chain_state.block_number block_hash = chain_state.block_hash sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) events: List[Event] = list() sub_iteration = None if sub_task: pseudo_random_generator = chain_state.pseudo_random_generator if isinstance(sub_task, InitiatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) if token_network_state: sub_iteration = initiator_manager.state_transition( sub_task.manager_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, MediatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) if token_network_state: channelids_to_channels = token_network_state.channelidentifiers_to_channels sub_iteration = mediator.state_transition( mediator_state=sub_task.mediator_state, state_change=state_change, channelidentifiers_to_channels=channelids_to_channels, nodeaddresses_to_networkstates=chain_state. nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_number, block_hash=block_hash, ) events = sub_iteration.events elif isinstance(sub_task, TargetTask): token_network_identifier = sub_task.token_network_identifier channel_identifier = sub_task.channel_identifier channel_state = views.get_channelstate_by_token_network_identifier( chain_state, token_network_identifier, channel_identifier, ) if channel_state: sub_iteration = target.state_transition( sub_task.target_state, state_change, channel_state, pseudo_random_generator, block_number, ) events = sub_iteration.events if sub_iteration and sub_iteration.new_state is None: del chain_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(chain_state, events)
def subdispatch_to_paymenttask(node_state, state_change, secrethash): block_number = node_state.block_number sub_task = node_state.payment_mapping.secrethashes_to_task.get(secrethash) events = list() sub_iteration = None if sub_task: pseudo_random_generator = node_state.pseudo_random_generator if isinstance(sub_task, PaymentMappingState.InitiatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( node_state, token_network_identifier, ) if token_network_state: sub_iteration = initiator_manager.state_transition( sub_task.manager_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, PaymentMappingState.MediatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( node_state, token_network_identifier, ) if token_network_state: sub_iteration = mediator.state_transition( sub_task.mediator_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, PaymentMappingState.TargetTask): token_network_identifier = sub_task.token_network_identifier channel_identifier = sub_task.channel_identifier token_network_state = views.get_token_network_by_identifier( node_state, token_network_identifier, ) channel_state = views.get_channelstate_by_token_network_identifier( node_state, token_network_identifier, channel_identifier, ) if channel_state: sub_iteration = target.state_transition( sub_task.target_state, state_change, channel_state, pseudo_random_generator, block_number, ) events = sub_iteration.events if sub_iteration and sub_iteration.new_state is None: del node_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(node_state, events)
def test_clear_closed_queue(raiden_network, token_addresses, deposit, network_wait): """ Closing a channel clears the respective message queue. """ app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] chain_state0 = views.state_from_app(app0) token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state0, app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( chain_state0, token_network_identifier, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address ] with dont_handle_secret_request_mock(app0): # make an unconfirmed transfer to ensure the nodes have communicated amount = 10 payment_identifier = 1337 app0.raiden.mediated_transfer_async( token_network_identifier=token_network_identifier, amount=amount, target=app1.raiden.address, identifier=payment_identifier, ) app1.raiden.transport.stop() app1.raiden.transport.get() # make sure to wait until the queue is created def has_initiator_events(): initiator_events = app0.raiden.wal.storage.get_events() return must_contain_entry(initiator_events, SendLockedTransfer, {}) assert wait_until(has_initiator_events, network_wait) # assert the specific queue is present chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue_id.channel_identifier == channel_identifier and queue ] # A ChannelClose event will be generated, this will be polled by both apps RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) exception = ValueError('Could not get close event') with gevent.Timeout(seconds=30, exception=exception): waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) # assert all queues with this partner are gone or empty chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert not [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue ] chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) assert not [ (queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue ]
def run_test_batch_unlock_after_restart(raiden_network, token_addresses, deposit): """Simulate the case where: - A sends B a transfer - B sends A a transfer - Secrets were never revealed - B closes channel - A crashes - Wait for settle - Wait for unlock from B - Restart A At this point, the current unlock logic will try to unlock iff the node gains from unlocking. Which means that the node will try to unlock either side. In the above scenario, each node will unlock its side. This test makes sure that we do NOT invalidate A's unlock transaction based on the ContractReceiveChannelBatchUnlock caused by B's unlock. """ alice_app, bob_app = raiden_network registry_address = alice_app.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_app(alice_app), payment_network_id=alice_app.raiden.default_registry.address, token_address=token_address, ) hold_event_handler = HoldOffChainSecretRequest() bob_app.raiden.raiden_event_handler = hold_event_handler alice_app.raiden.raiden_event_handler = hold_event_handler token_network = views.get_token_network_by_identifier( chain_state=views.state_from_app(alice_app), token_network_id=token_network_identifier) channel_identifier = get_channelstate(alice_app, bob_app, token_network_identifier).identifier assert (channel_identifier in token_network.partneraddresses_to_channelidentifiers[ bob_app.raiden.address]) alice_to_bob_amount = 10 identifier = 1 alice_transfer_secret = sha3(alice_app.raiden.address) alice_transfer_secrethash = sha3(alice_transfer_secret) bob_transfer_secret = sha3(bob_app.raiden.address) bob_transfer_secrethash = sha3(bob_transfer_secret) alice_transfer_hold = hold_event_handler.hold_secretrequest_for( secrethash=alice_transfer_secrethash) bob_transfer_hold = hold_event_handler.hold_secretrequest_for( secrethash=bob_transfer_secrethash) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=alice_to_bob_amount, fee=0, target=bob_app.raiden.address, identifier=identifier, secret=alice_transfer_secret, ) bob_app.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=alice_to_bob_amount, fee=0, target=alice_app.raiden.address, identifier=identifier + 1, secret=bob_transfer_secret, ) alice_transfer_hold.wait() bob_transfer_hold.wait() alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) alice_lock = channel.get_lock(alice_bob_channel_state.our_state, alice_transfer_secrethash) bob_lock = channel.get_lock(alice_bob_channel_state.partner_state, bob_transfer_secrethash) # This is the current state of protocol: # # A -> B LockedTransfer # - protocol didn't continue assert_synced_channel_state( token_network_identifier=token_network_identifier, app0=alice_app, balance0=deposit, pending_locks0=[alice_lock], app1=bob_app, balance1=deposit, pending_locks1=[bob_lock], ) # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(bob_app.raiden).channel_close( registry_address=registry_address, token_address=token_address, partner_address=alice_app.raiden.address, ) alice_app.stop() waiting.wait_for_settle( raiden=alice_app.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[alice_bob_channel_state.identifier], retry_timeout=alice_app.raiden.alarm.sleep_time, ) # wait for the node to call batch unlock timeout = 10 with gevent.Timeout(timeout): wait_for_batch_unlock( app=bob_app, token_network_id=token_network_identifier, participant=alice_bob_channel_state.partner_state.address, partner=alice_bob_channel_state.our_state.address, ) alice_app.start() with gevent.Timeout(timeout): wait_for_batch_unlock( app=alice_app, token_network_id=token_network_identifier, participant=alice_bob_channel_state.partner_state.address, partner=alice_bob_channel_state.our_state.address, )
def test_mediator_clear_pairs_after_batch_unlock( chain_state, token_network_state, our_address, ): """ Regression test for https://github.com/raiden-network/raiden/issues/2932 The mediator must also clear the transfer pairs once a ReceiveBatchUnlock where he is a participant is received. """ open_block_number = 10 pseudo_random_generator = random.Random() pkey, address = factories.make_privkey_address() amount = 30 our_balance = amount + 50 channel_state = factories.make_channel( our_balance=our_balance, our_address=our_address, partner_balance=our_balance, partner_address=address, token_network_identifier=token_network_state.address, ) payment_network_identifier = factories.make_payment_network_identifier() channel_new_state_change = ContractReceiveChannelNew( factories.make_transaction_hash(), token_network_state.address, channel_state, open_block_number, ) channel_new_iteration = token_network.state_transition( payment_network_identifier, token_network_state, channel_new_state_change, pseudo_random_generator, open_block_number, ) lock_amount = 30 lock_expiration = 20 lock_secret = sha3(b'test_end_state') lock_secrethash = sha3(lock_secret) lock = HashTimeLockState( lock_amount, lock_expiration, lock_secrethash, ) mediated_transfer = make_receive_transfer_mediated( channel_state=channel_state, privkey=pkey, nonce=1, transferred_amount=0, lock=lock, ) from_route = factories.route_from_channel(channel_state) init_mediator = ActionInitMediator( routes=[from_route], from_route=from_route, from_transfer=mediated_transfer, ) node.state_transition(chain_state, init_mediator) closed_block_number = open_block_number + 10 channel_close_state_change = ContractReceiveChannelClosed( factories.make_transaction_hash(), channel_state.partner_state.address, token_network_state.address, channel_state.identifier, closed_block_number, ) channel_closed_iteration = token_network.state_transition( payment_network_identifier, channel_new_iteration.new_state, channel_close_state_change, pseudo_random_generator, closed_block_number, ) settle_block_number = closed_block_number + channel_state.settle_timeout + 1 channel_settled_state_change = ContractReceiveChannelSettled( factories.make_transaction_hash(), token_network_state.address, channel_state.identifier, settle_block_number, ) channel_settled_iteration = token_network.state_transition( payment_network_identifier, channel_closed_iteration.new_state, channel_settled_state_change, pseudo_random_generator, closed_block_number, ) token_network_state_after_settle = channel_settled_iteration.new_state ids_to_channels = token_network_state_after_settle.channelidentifiers_to_channels assert len(ids_to_channels) == 1 assert channel_state.identifier in ids_to_channels block_number = closed_block_number + 1 channel_batch_unlock_state_change = ContractReceiveChannelBatchUnlock( transaction_hash=factories.make_transaction_hash(), token_network_identifier=token_network_state.address, participant=our_address, partner=address, locksroot=lock_secrethash, unlocked_amount=lock_amount, returned_tokens=0, block_number=block_number, ) channel_unlock_iteration = node.state_transition( chain_state=chain_state, state_change=channel_batch_unlock_state_change, ) chain_state = channel_unlock_iteration.new_state token_network_state = views.get_token_network_by_identifier( chain_state=chain_state, token_network_id=token_network_state.address, ) ids_to_channels = token_network_state.channelidentifiers_to_channels assert len(ids_to_channels) == 0 # Make sure that all is fine in the next block block = Block( block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = node.state_transition( chain_state=chain_state, state_change=block, ) assert iteration.new_state # Make sure that mediator task was cleared during the next block processing # since the channel was removed mediator_task = chain_state.payment_mapping.secrethashes_to_task.get( lock_secrethash) assert not mediator_task
def handle_channel_batch_unlock(raiden: "RaidenService", event: Event): assert raiden.wal, "The Raiden Service must be initialize to handle events" token_network_identifier = event.originating_contract data = event.event_data args = data["args"] block_number = data["block_number"] block_hash = data["block_hash"] transaction_hash = data["transaction_hash"] participant1 = args["participant"] participant2 = args["partner"] locksroot = args["locksroot"] chain_state = views.state_from_raiden(raiden) token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier) assert token_network_state is not None if participant1 == raiden.address: partner = participant2 elif participant2 == raiden.address: partner = participant1 else: log.debug( "Discarding unlock event, we're not part of it", participant1=pex(participant1), participant2=pex(participant2), ) return channel_identifiers = token_network_state.partneraddresses_to_channelidentifiers[ partner] canonical_identifier = None for channel_identifier in channel_identifiers: if partner == args["partner"]: state_change_record = get_state_change_with_balance_proof_by_locksroot( storage=raiden.wal.storage, canonical_identifier=CanonicalIdentifier( chain_identifier=raiden.chain.network_id, token_network_address=token_network_identifier, channel_identifier=channel_identifier, ), locksroot=locksroot, sender=partner, ) if state_change_record.state_change_identifier: canonical_identifier = state_change_record.data.balance_proof.canonical_identifier break elif partner == args["participant"]: event_record = get_event_with_balance_proof_by_locksroot( storage=raiden.wal.storage, canonical_identifier=CanonicalIdentifier( chain_identifier=raiden.chain.network_id, token_network_address=token_network_identifier, channel_identifier=channel_identifier, ), locksroot=locksroot, recipient=partner, ) if event_record.event_identifier: canonical_identifier = event_record.data.balance_proof.canonical_identifier break msg = ( f"Can not resolve channel_id for unlock with locksroot {pex(locksroot)} and " f"partner {pex(partner)}.") assert canonical_identifier is not None, msg unlock_state_change = ContractReceiveChannelBatchUnlock( transaction_hash=transaction_hash, canonical_identifier=canonical_identifier, participant=args["participant"], partner=args["partner"], locksroot=args["locksroot"], unlocked_amount=args["unlocked_amount"], returned_tokens=args["returned_tokens"], block_number=block_number, block_hash=block_hash, ) raiden.handle_and_track_state_change(unlock_state_change)
def test_mediator_clear_pairs_after_batch_unlock( chain_state, token_network_state, our_address, ): """ Regression test for https://github.com/raiden-network/raiden/issues/2932 The mediator must also clear the transfer pairs once a ReceiveBatchUnlock where he is a participant is received. """ open_block_number = 10 pseudo_random_generator = random.Random() pkey, address = factories.make_privkey_address() amount = 30 our_balance = amount + 50 channel_state = factories.make_channel( our_balance=our_balance, our_address=our_address, partner_balance=our_balance, partner_address=address, token_network_identifier=token_network_state.address, ) payment_network_identifier = factories.make_payment_network_identifier() channel_new_state_change = ContractReceiveChannelNew( factories.make_transaction_hash(), token_network_state.address, channel_state, open_block_number, ) channel_new_iteration = token_network.state_transition( payment_network_identifier, token_network_state, channel_new_state_change, pseudo_random_generator, open_block_number, ) lock_amount = 30 lock_expiration = 20 lock_secret = sha3(b'test_end_state') lock_secrethash = sha3(lock_secret) lock = HashTimeLockState( lock_amount, lock_expiration, lock_secrethash, ) mediated_transfer = make_receive_transfer_mediated( channel_state=channel_state, privkey=pkey, nonce=1, transferred_amount=0, lock=lock, ) from_route = factories.route_from_channel(channel_state) init_mediator = ActionInitMediator( routes=[from_route], from_route=from_route, from_transfer=mediated_transfer, ) node.state_transition(chain_state, init_mediator) closed_block_number = open_block_number + 10 channel_close_state_change = ContractReceiveChannelClosed( factories.make_transaction_hash(), channel_state.partner_state.address, token_network_state.address, channel_state.identifier, closed_block_number, ) channel_closed_iteration = token_network.state_transition( payment_network_identifier, channel_new_iteration.new_state, channel_close_state_change, pseudo_random_generator, closed_block_number, ) settle_block_number = closed_block_number + channel_state.settle_timeout + 1 channel_settled_state_change = ContractReceiveChannelSettled( factories.make_transaction_hash(), token_network_state.address, channel_state.identifier, settle_block_number, ) channel_settled_iteration = token_network.state_transition( payment_network_identifier, channel_closed_iteration.new_state, channel_settled_state_change, pseudo_random_generator, closed_block_number, ) token_network_state_after_settle = channel_settled_iteration.new_state ids_to_channels = token_network_state_after_settle.channelidentifiers_to_channels assert len(ids_to_channels) == 1 assert channel_state.identifier in ids_to_channels block_number = closed_block_number + 1 channel_batch_unlock_state_change = ContractReceiveChannelBatchUnlock( transaction_hash=factories.make_transaction_hash(), token_network_identifier=token_network_state.address, participant=our_address, partner=address, locksroot=lock_secrethash, unlocked_amount=lock_amount, returned_tokens=0, block_number=block_number, ) channel_unlock_iteration = node.state_transition( chain_state=chain_state, state_change=channel_batch_unlock_state_change, ) chain_state = channel_unlock_iteration.new_state token_network_state = views.get_token_network_by_identifier( chain_state=chain_state, token_network_id=token_network_state.address, ) ids_to_channels = token_network_state.channelidentifiers_to_channels assert len(ids_to_channels) == 0 # Make sure that all is fine in the next block block = Block( block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = node.state_transition( chain_state=chain_state, state_change=block, ) assert iteration.new_state # Make sure that mediator task was cleared during the next block processing # since the channel was removed mediator_task = chain_state.payment_mapping.secrethashes_to_task.get(lock_secrethash) assert not mediator_task
def run_test_lock_expiry(raiden_network, token_addresses, deposit): alice_app, bob_app = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address ) hold_event_handler = bob_app.raiden.raiden_event_handler wait_message_handler = bob_app.raiden.message_handler token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier ) channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) channel_identifier = channel_state.identifier assert ( channel_identifier in token_network.partneraddresses_to_channelidentifiers[bob_app.raiden.address] ) alice_to_bob_amount = 10 identifier = 1 target = bob_app.raiden.address transfer_1_secret = factories.make_secret(0) transfer_1_secrethash = sha3(transfer_1_secret) transfer_2_secret = factories.make_secret(1) transfer_2_secrethash = sha3(transfer_2_secret) hold_event_handler.hold_secretrequest_for(secrethash=transfer_1_secrethash) transfer1_received = wait_message_handler.wait_for_message( LockedTransfer, {"lock": {"secrethash": transfer_1_secrethash}} ) transfer2_received = wait_message_handler.wait_for_message( LockedTransfer, {"lock": {"secrethash": transfer_2_secrethash}} ) remove_expired_lock_received = wait_message_handler.wait_for_message( LockExpired, {"secrethash": transfer_1_secrethash} ) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=alice_to_bob_amount, fee=0, target=target, identifier=identifier, payment_hash_invoice=EMPTY_PAYMENT_HASH_INVOICE, secret=transfer_1_secret, ) transfer1_received.wait() alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [] ) # Verify lock is registered in both channel states alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task remove_expired_lock_received.wait() alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks # Verify Bob received the message and processed the LockExpired message bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task # Make another transfer alice_to_bob_amount = 10 identifier = 2 hold_event_handler.hold_secretrequest_for(secrethash=transfer_2_secrethash) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=alice_to_bob_amount, fee=0, target=target, identifier=identifier, payment_hash_invoice=EMPTY_PAYMENT_HASH_INVOICE, secret=transfer_2_secret, ) transfer2_received.wait() # Make sure the other transfer still exists alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks
def test_batch_unlock(raiden_network, token_addresses, secret_registry_address, deposit): """Batch unlock can be called after the channel is settled.""" alice_app, bob_app = raiden_network registry_address = alice_app.raiden.default_registry.address token_address = token_addresses[0] token_proxy = alice_app.raiden.chain.token(token_address) token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_identifier = get_channelstate(alice_app, bob_app, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channels[ bob_app.raiden.address] alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address) bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address) alice_to_bob_amount = 10 identifier = 1 secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) secrethash = sha3(secret) alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(bob_app.raiden).channel_close( registry_address, token_address, alice_app.raiden.address, ) secret_registry_proxy = alice_app.raiden.chain.secret_registry( secret_registry_address, ) secret_registry_proxy.register_secret(secret) assert lock, 'the lock must still be part of the node state' msg = 'the secret must be registered before the lock expires' assert lock.expiration > alice_app.raiden.get_block_number(), msg assert lock.secrethash == sha3(secret) waiting.wait_for_settle( alice_app.raiden, registry_address, token_address, [alice_bob_channel_state.identifier], alice_app.raiden.alarm.sleep_time, ) token_network = views.get_token_network_by_identifier( views.state_from_app(bob_app), token_network_identifier, ) assert channel_identifier in token_network.partneraddresses_to_channels[ alice_app.raiden.address] # wait for the node to call batch unlock with gevent.Timeout(10): wait_for_batch_unlock( bob_app, token_network_identifier, alice_bob_channel_state.partner_state.address, alice_bob_channel_state.our_state.address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(bob_app), token_network_identifier, ) assert channel_identifier not in token_network.partneraddresses_to_channels[ alice_app.raiden.address] alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount assert token_proxy.balance_of( alice_app.raiden.address) == alice_new_balance assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance
def subdispatch_to_paymenttask( chain_state: ChainState, state_change: StateChange, secrethash: SecretHash, ) -> TransitionResult: block_number = chain_state.block_number sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) events = list() sub_iteration = None if sub_task: pseudo_random_generator = chain_state.pseudo_random_generator if isinstance(sub_task, InitiatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) if token_network_state: sub_iteration = initiator_manager.state_transition( sub_task.manager_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, MediatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) if token_network_state: sub_iteration = mediator.state_transition( sub_task.mediator_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, TargetTask): token_network_identifier = sub_task.token_network_identifier channel_identifier = sub_task.channel_identifier channel_state = views.get_channelstate_by_token_network_identifier( chain_state, token_network_identifier, channel_identifier, ) if channel_state: sub_iteration = target.state_transition( sub_task.target_state, state_change, channel_state, pseudo_random_generator, block_number, ) events = sub_iteration.events if sub_iteration and sub_iteration.new_state is None: del chain_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(chain_state, events)
def test_lock_expiry(raiden_network, token_addresses, secret_registry_address, deposit): """Test lock expiry and removal.""" alice_app, bob_app = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) channel_identifier = channel_state.identifier assert channel_identifier in token_network.partneraddresses_to_channels[ bob_app.raiden.address] alice_to_bob_amount = 10 identifier = 1 transfer_1_secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) transfer_1_secrethash = sha3(transfer_1_secret) alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # Verify lock is registered in both channel states alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task # Wait for the expiration to trigger with some additional buffer # time for processing (+2) blocks. waiting.wait_for_block( alice_app.raiden, lock.expiration + (DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK + 2), DEFAULT_RETRY_TIMEOUT, ) alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks # Verify Bob received the message and processed the LockExpired message bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task # Make another transfer alice_to_bob_amount = 10 identifier = 2 transfer_2_secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) transfer_2_secrethash = sha3(transfer_2_secret) # Make sure the other transfer still exists alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks
def test_clear_closed_queue(raiden_network, token_addresses, deposit, network_wait): """ Closing a channel clears the respective message queue. """ app0, app1 = raiden_network hold_event_handler = HoldOffChainSecretRequest() app1.raiden.raiden_event_handler = hold_event_handler registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] chain_state0 = views.state_from_app(app0) token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state0, app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( chain_state0, token_network_identifier, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address] target = app1.raiden.address secret = sha3(target) secrethash = sha3(secret) hold_event_handler.hold_secretrequest_for(secrethash=secrethash) # make an unconfirmed transfer to ensure the nodes have communicated amount = 10 payment_identifier = 1337 app0.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=amount, target=target, identifier=payment_identifier, secret=secret, ) app1.raiden.transport.stop() app1.raiden.transport.get() # make sure to wait until the queue is created def has_initiator_events(): initiator_events = app0.raiden.wal.storage.get_events() return search_for_item(initiator_events, SendLockedTransfer, {}) assert wait_until(has_initiator_events, network_wait) # assert the specific queue is present chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert [(queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue_id.channel_identifier == channel_identifier and queue] # A ChannelClose event will be generated, this will be polled by both apps RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) exception = ValueError('Could not get close event') with gevent.Timeout(seconds=30, exception=exception): waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) # assert all queues with this partner are gone or empty chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert not [(queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue] chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) assert not [(queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue]
def test_settle_is_automatically_called(raiden_network, token_addresses, deposit): """Settle is automatically called by one of the nodes.""" app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(app0), token_network_identifier, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channels[ app1.raiden.address] # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) channel_state = views.get_channelstate_for( views.state_from_raiden(app0.raiden), registry_address, token_address, app1.raiden.address, ) assert channel_state.close_transaction.finished_block_number waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) token_network = views.get_token_network_by_identifier( views.state_from_app(app0), token_network_identifier, ) assert channel_identifier not in token_network.partneraddresses_to_channels[ app1.raiden.address] state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry( state_changes, ContractReceiveChannelClosed, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'transaction_from': app1.raiden.address, 'closed_block_number': channel_state.close_transaction.finished_block_number, }) assert must_contain_entry( state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_lock_expiry(raiden_network, token_addresses, deposit): """Test lock expiry and removal.""" alice_app, bob_app = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) hold_event_handler = HoldOffChainSecretRequest() wait_message_handler = WaitForMessage() bob_app.raiden.message_handler = wait_message_handler bob_app.raiden.raiden_event_handler = hold_event_handler token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) channel_identifier = channel_state.identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ bob_app.raiden.address] alice_to_bob_amount = 10 identifier = 1 target = bob_app.raiden.address transfer_1_secret = factories.make_secret(0) transfer_1_secrethash = sha3(transfer_1_secret) transfer_2_secret = factories.make_secret(1) transfer_2_secrethash = sha3(transfer_2_secret) hold_event_handler.hold_secretrequest_for(secrethash=transfer_1_secrethash) transfer1_received = wait_message_handler.wait_for_message( LockedTransfer, {'lock': { 'secrethash': transfer_1_secrethash }}, ) transfer2_received = wait_message_handler.wait_for_message( LockedTransfer, {'lock': { 'secrethash': transfer_2_secrethash }}, ) remove_expired_lock_received = wait_message_handler.wait_for_message( LockExpired, {'secrethash': transfer_1_secrethash}, ) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier, alice_to_bob_amount, target, identifier, transfer_1_secret, ) transfer1_received.wait() alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # Verify lock is registered in both channel states alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task remove_expired_lock_received.wait() alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks # Verify Bob received the message and processed the LockExpired message bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task # Make another transfer alice_to_bob_amount = 10 identifier = 2 hold_event_handler.hold_secretrequest_for(secrethash=transfer_2_secrethash) alice_app.raiden.start_mediated_transfer_with_secret( token_network_identifier, alice_to_bob_amount, target, identifier, transfer_2_secret, ) transfer2_received.wait() # Make sure the other transfer still exists alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks
def get_best_routes( node_state: NodeState, token_network_id: typing.Address, from_address: typing.Address, to_address: typing.Address, amount: int, previous_address: typing.Address, ) -> List[RouteState]: """ Returns a list of channels that can be used to make a transfer. This will filter out channels that are not open and don't have enough capacity. """ # TODO: Route ranking. # Rate each route to optimize the fee price/quality of each route and add a # rate from in the range [0.0,1.0]. available_routes = list() token_network = views.get_token_network_by_identifier( node_state, token_network_id, ) network_statuses = views.get_networkstatuses(node_state) neighbors_heap = get_ordered_partners( token_network.network_graph.network, from_address, to_address, ) if not neighbors_heap: log.warning( 'No routes available from %s to %s' % (pex(from_address), pex(to_address)), ) while neighbors_heap: _, partner_address = heappop(neighbors_heap) channel_state = views.get_channelstate_by_token_network_and_partner( node_state, token_network_id, partner_address, ) # don't send the message backwards if partner_address == previous_address: continue if channel.get_status(channel_state) != CHANNEL_STATE_OPENED: log.info( 'channel %s - %s is not opened, ignoring' % (pex(from_address), pex(partner_address)), ) continue distributable = channel.get_distributable( channel_state.our_state, channel_state.partner_state, ) if amount > distributable: log.info( 'channel %s - %s doesnt have enough funds [%s], ignoring' % (pex(from_address), pex(partner_address), amount), ) continue network_state = network_statuses.get(partner_address, NODE_NETWORK_UNKNOWN) if network_state != NODE_NETWORK_REACHABLE: log.info( 'partner for channel %s - %s is not %s, ignoring' % (pex(from_address), pex(partner_address), NODE_NETWORK_REACHABLE), ) continue route_state = RouteState(partner_address, channel_state.identifier) available_routes.append(route_state) return available_routes
def get_best_routes( chain_state: ChainState, token_network_id: typing.Address, from_address: typing.Address, to_address: typing.Address, amount: int, previous_address: typing.Address, ) -> List[RouteState]: """ Returns a list of channels that can be used to make a transfer. This will filter out channels that are not open and don't have enough capacity. """ # TODO: Route ranking. # Rate each route to optimize the fee price/quality of each route and add a # rate from in the range [0.0,1.0]. available_routes = list() token_network = views.get_token_network_by_identifier( chain_state, token_network_id, ) network_statuses = views.get_networkstatuses(chain_state) neighbors_heap = get_ordered_partners( token_network.network_graph.network, from_address, to_address, ) if not neighbors_heap: log.warning( 'No routes available from %s to %s' % (pex(from_address), pex(to_address)), ) while neighbors_heap: _, partner_address = heappop(neighbors_heap) channel_state = views.get_channelstate_by_token_network_and_partner( chain_state, token_network_id, partner_address, ) # don't send the message backwards if partner_address == previous_address: continue if channel.get_status(channel_state) != CHANNEL_STATE_OPENED: log.info( 'channel %s - %s is not opened, ignoring' % (pex(from_address), pex(partner_address)), ) continue distributable = channel.get_distributable( channel_state.our_state, channel_state.partner_state, ) if amount > distributable: log.info( 'channel %s - %s doesnt have enough funds [%s], ignoring' % (pex(from_address), pex(partner_address), amount), ) continue network_state = network_statuses.get(partner_address, NODE_NETWORK_UNKNOWN) if network_state != NODE_NETWORK_REACHABLE: log.info( 'partner for channel %s - %s is not %s, ignoring' % (pex(from_address), pex(partner_address), NODE_NETWORK_REACHABLE), ) continue route_state = RouteState(partner_address, channel_state.identifier) available_routes.append(route_state) return available_routes