def next_channel_from_routes( available_routes: typing.List[RouteState], channelidentifiers_to_channels: typing.ChannelMap, transfer_amount: typing.TokenAmount, ) -> typing.Optional[NettingChannelState]: """ Returns the first channel that can be used to start the transfer. The routing service can race with local changes, so the recommended routes must be validated. """ for route in available_routes: channel_identifier = route.channel_identifier channel_state = channelidentifiers_to_channels.get(channel_identifier) if not channel_state: continue if channel.get_status(channel_state) != CHANNEL_STATE_OPENED: continue pending_transfers = channel.get_number_of_pending_transfers( channel_state.our_state) if pending_transfers >= MAXIMUM_PENDING_TRANSFERS: continue distributable = channel.get_distributable( channel_state.our_state, channel_state.partner_state, ) if transfer_amount > distributable: continue if channel.is_valid_amount(channel_state.our_state, transfer_amount): return channel_state return None
def next_channel_from_routes( available_routes: typing.List[RouteState], channelidentifiers_to_channels: ChannelMap, transfer_amount: typing.TokenAmount, ) -> typing.Optional[NettingChannelState]: """ Returns the first channel that can be used to start the transfer. The routing service can race with local changes, so the recommended routes must be validated. """ for route in available_routes: channel_identifier = route.channel_identifier channel_state = channelidentifiers_to_channels.get(channel_identifier) if not channel_state: continue if channel.get_status(channel_state) != CHANNEL_STATE_OPENED: continue distributable = channel.get_distributable( channel_state.our_state, channel_state.partner_state, ) if transfer_amount > distributable: continue if channel.is_valid_amount(channel_state.our_state, transfer_amount): return channel_state return None
def events_for_refund_transfer( refund_channel, refund_transfer, pseudo_random_generator, timeout_blocks, block_number, ): """ Refund the transfer. Args: refund_route (RouteState): The original route that sent the mediated transfer to this node. refund_transfer (LockedTransferSignedState): The original mediated transfer from the refund_route. timeout_blocks (int): The number of blocks available from the /latest transfer/ received by this node, this transfer might be the original mediated transfer (if no route was available) or a refund transfer from a down stream node. block_number (int): The current block number. Returns: An empty list if there are not enough blocks to safely create a refund, or a list with a refund event.""" # A refund transfer works like a special SendLockedTransfer, so it must # follow the same rules and decrement reveal_timeout from the # payee_transfer. new_lock_timeout = timeout_blocks - refund_channel.reveal_timeout distributable = channel.get_distributable( refund_channel.our_state, refund_channel.partner_state, ) is_valid = (new_lock_timeout > 0 and refund_transfer.lock.amount <= distributable and channel.is_valid_amount(refund_channel.our_state, refund_transfer.lock.amount)) if is_valid: new_lock_expiration = new_lock_timeout + block_number message_identifier = message_identifier_from_prng( pseudo_random_generator) refund_transfer = channel.send_refundtransfer( refund_channel, refund_transfer.initiator, refund_transfer.target, refund_transfer.lock.amount, message_identifier, refund_transfer.payment_identifier, new_lock_expiration, refund_transfer.lock.secrethash, ) return [refund_transfer] # Can not create a refund lock with a safe expiration, so don't do anything # and wait for the received lock to expire. return list()
def events_for_refund_transfer( refund_channel, refund_transfer, pseudo_random_generator, timeout_blocks, block_number, ): """ Refund the transfer. Args: refund_route (RouteState): The original route that sent the mediated transfer to this node. refund_transfer (LockedTransferSignedState): The original mediated transfer from the refund_route. timeout_blocks (int): The number of blocks available from the /latest transfer/ received by this node, this transfer might be the original mediated transfer (if no route was available) or a refund transfer from a down stream node. block_number (int): The current block number. Returns: An empty list if there are not enough blocks to safely create a refund, or a list with a refund event.""" # A refund transfer works like a special SendLockedTransfer, so it must # follow the same rules and decrement reveal_timeout from the # payee_transfer. new_lock_timeout = timeout_blocks - refund_channel.reveal_timeout distributable = channel.get_distributable( refund_channel.our_state, refund_channel.partner_state, ) is_valid = ( new_lock_timeout > 0 and refund_transfer.lock.amount <= distributable and channel.is_valid_amount(refund_channel.our_state, refund_transfer.lock.amount) ) if is_valid: new_lock_expiration = new_lock_timeout + block_number message_identifier = message_identifier_from_prng(pseudo_random_generator) refund_transfer = channel.send_refundtransfer( refund_channel, refund_transfer.initiator, refund_transfer.target, refund_transfer.lock.amount, message_identifier, refund_transfer.payment_identifier, new_lock_expiration, refund_transfer.lock.secrethash, ) return [refund_transfer] # Can not create a refund lock with a safe expiration, so don't do anything # and wait for the received lock to expire. return list()
def next_channel_from_routes( available_routes: List['RouteState'], channelidentifiers_to_channels: Dict, transfer_amount: int, timeout_blocks: int, ) -> NettingChannelState: """ Returns the first route that may be used to mediated the transfer. The routing service can race with local changes, so the recommended routes must be validated. Args: available_routes: Current available routes that may be used, it's assumed that the available_routes list is ordered from best to worst. channelidentifiers_to_channels: Mapping from channel identifier to NettingChannelState. transfer_amount: The amount of tokens that will be transferred through the given route. timeout_blocks: Base number of available blocks used to compute the lock timeout. Returns: The next route. """ for route in available_routes: channel_identifier = route.channel_identifier channel_state = channelidentifiers_to_channels.get(channel_identifier) if not channel_state: continue if channel.get_status(channel_state) != CHANNEL_STATE_OPENED: continue pending_transfers = channel.get_number_of_pending_transfers( channel_state.our_state) if pending_transfers >= MAXIMUM_PENDING_TRANSFERS: continue distributable = channel.get_distributable( channel_state.our_state, channel_state.partner_state, ) if transfer_amount > distributable: continue lock_timeout = timeout_blocks - channel_state.reveal_timeout if lock_timeout <= 0: continue if channel.is_valid_amount(channel_state.our_state, transfer_amount): return channel_state return None
def is_channel_usable(candidate_channel_state, transfer_amount, lock_timeout): pending_transfers = channel.get_number_of_pending_transfers( candidate_channel_state.our_state) distributable = channel.get_distributable( candidate_channel_state.our_state, candidate_channel_state.partner_state, ) return (lock_timeout > 0 and channel.get_status(candidate_channel_state) == CHANNEL_STATE_OPENED and candidate_channel_state.settle_timeout >= lock_timeout and candidate_channel_state.reveal_timeout < lock_timeout and pending_transfers < MAXIMUM_PENDING_TRANSFERS and transfer_amount <= distributable and channel.is_valid_amount( candidate_channel_state.our_state, transfer_amount))
def next_channel_from_routes( available_routes: List['RouteState'], channelidentifiers_to_channels: Dict, transfer_amount: int, timeout_blocks: int, ) -> NettingChannelState: """ Returns the first route that may be used to mediated the transfer. The routing service can race with local changes, so the recommended routes must be validated. Args: available_routes: Current available routes that may be used, it's assumed that the available_routes list is ordered from best to worst. channelidentifiers_to_channels: Mapping from channel identifier to NettingChannelState. transfer_amount: The amount of tokens that will be transferred through the given route. timeout_blocks: Base number of available blocks used to compute the lock timeout. Returns: The next route. """ for route in available_routes: channel_identifier = route.channel_identifier channel_state = channelidentifiers_to_channels.get(channel_identifier) if not channel_state: continue if channel.get_status(channel_state) != CHANNEL_STATE_OPENED: continue distributable = channel.get_distributable( channel_state.our_state, channel_state.partner_state, ) if transfer_amount > distributable: continue lock_timeout = timeout_blocks - channel_state.reveal_timeout if lock_timeout <= 0: continue if channel.is_valid_amount(channel_state.our_state, transfer_amount): return channel_state return None