def wait_for_newchannel( raiden: RaidenService, payment_network_id: typing.PaymentNetworkID, token_address: typing.TokenAddress, partner_address: typing.Address, retry_timeout: float, ) -> None: """Wait until the channel with partner_address is registered. Note: This does not time out, use gevent.Timeout. """ channel_state = views.get_channelstate_for( views.state_from_raiden(raiden), payment_network_id, token_address, partner_address, ) while channel_state is None: gevent.sleep(retry_timeout) channel_state = views.get_channelstate_for( views.state_from_raiden(raiden), payment_network_id, token_address, partner_address, )
def get_channel_list( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress = None, partner_address: typing.Address = None, ) -> typing.List[NettingChannelState]: """Returns a list of channels associated with the optionally given `token_address` and/or `partner_address`. Args: token_address: an optionally provided token address partner_address: an optionally provided partner address Return: A list containing all channels the node participates. Optionally filtered by a token address and/or partner address. Raises: KeyError: An error occurred when the token address is unknown to the node. """ if registry_address and not is_binary_address(registry_address): raise InvalidAddress('Expected binary address format for registry in get_channel_list') if token_address and not is_binary_address(token_address): raise InvalidAddress('Expected binary address format for token in get_channel_list') if partner_address: if not is_binary_address(partner_address): raise InvalidAddress( 'Expected binary address format for partner in get_channel_list', ) if not token_address: raise UnknownTokenAddress('Provided a partner address but no token address') if token_address and partner_address: channel_state = views.get_channelstate_for( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, partner_address=partner_address, ) if channel_state: result = [channel_state] else: result = [] elif token_address: result = views.list_channelstate_for_tokennetwork( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) else: result = views.list_all_channelstate( chain_state=views.state_from_raiden(self.raiden), ) return result
def find_new_partners(self, number: int): """Search the token network for potential channel partners. Args: number: number of partners to return """ open_channels = views.get_channelstate_open( chain_state=views.state_from_raiden(self.raiden), payment_network_id=self.registry_address, token_address=self.token_address, ) known = set(channel_state.partner_state.address for channel_state in open_channels) known.add(self.BOOTSTRAP_ADDR) known.add(self.raiden.address) participants_addresses = views.get_participants_addresses( views.state_from_raiden(self.raiden), self.registry_address, self.token_address, ) available = participants_addresses - known new_partners = list(available)[:number] log.debug('found {} partners'.format(len(available))) return new_partners
def run_smoketests(raiden_service: RaidenService, test_config: Dict, debug: bool = False): """ Test that the assembled raiden_service correctly reflects the configuration from the smoketest_genesis. """ try: chain = raiden_service.chain assert ( raiden_service.default_registry.address == to_canonical_address(test_config['contracts']['registry_address']) ) assert ( raiden_service.default_secret_registry.address == to_canonical_address(test_config['contracts']['secret_registry_address']) ) token_network_added_events = raiden_service.default_registry.filter_token_added_events() token_addresses = [event['args']['token_address'] for event in token_network_added_events] assert token_addresses == [test_config['contracts']['token_address']] if test_config.get('transport') == 'udp': assert len(chain.address_to_discovery.keys()) == 1, repr(chain.address_to_discovery) assert ( list(chain.address_to_discovery.keys())[0] == to_canonical_address(test_config['contracts']['discovery_address']) ) discovery = list(chain.address_to_discovery.values())[0] assert discovery.endpoint_by_address(raiden_service.address) != TEST_ENDPOINT token_networks = views.get_token_network_addresses_for( views.state_from_raiden(raiden_service), raiden_service.default_registry.address, ) assert len(token_networks) == 1 channel_state = views.get_channelstate_for( views.state_from_raiden(raiden_service), raiden_service.default_registry.address, token_networks[0], unhexlify(TEST_PARTNER_ADDRESS), ) distributable = channel.get_distributable( channel_state.our_state, channel_state.partner_state, ) assert distributable == TEST_DEPOSIT_AMOUNT assert distributable == channel_state.our_state.contract_balance assert channel.get_status(channel_state) == CHANNEL_STATE_OPENED # Run API test run_restapi_smoketests() except Exception: error = traceback.format_exc() if debug: import pdb pdb.post_mortem() return error
def channel_batch_close( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, partner_addresses: typing.List[typing.Address], retry_timeout: typing.NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ): """Close a channel opened with `partner_address` for the given `token_address`. Race condition, this can fail if channel was closed externally. """ if not is_binary_address(token_address): raise InvalidAddress('Expected binary address format for token in channel close') if not all(map(is_binary_address, partner_addresses)): raise InvalidAddress('Expected binary address format for partner in channel close') valid_tokens = views.get_token_network_addresses_for( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, ) if token_address not in valid_tokens: raise UnknownTokenAddress('Token address is not known.') chain_state = views.state_from_raiden(self.raiden) channels_to_close = views.filter_channels_by_partneraddress( chain_state=chain_state, payment_network_id=registry_address, token_address=token_address, partner_addresses=partner_addresses, ) token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) for channel_state in channels_to_close: channel_close = ActionChannelClose( token_network_identifier=token_network_identifier, channel_identifier=channel_state.identifier, ) self.raiden.handle_state_change(channel_close) channel_ids = [channel_state.identifier for channel_state in channels_to_close] waiting.wait_for_close( raiden=self.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=channel_ids, retry_timeout=retry_timeout, )
def leave(self, registry_address, only_receiving=True): """ Leave the token network. This implies closing all channels and waiting for all channels to be settled. Note: By default we're just discarding all channels for which we haven't received anything. This potentially leaves deposits locked in channels after `closing`. This is "safe" from an accounting point of view (deposits can not be lost), but may still be undesirable from a liquidity point of view (deposits will only be freed after manually closing or after the partner closed the channel). If only_receiving is False then we close and settle all channels irrespective of them having received transfers or not. """ with self.lock: self.initial_channel_target = 0 if only_receiving: channels_to_close = views.get_channelstate_for_receiving( views.state_from_raiden(self.raiden), registry_address, self.token_address, ) else: channels_to_close = views.get_channelstate_open( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=self.token_address, ) partner_addresses = [ channel_state.partner_state.address for channel_state in channels_to_close ] self.api.channel_batch_close( registry_address, self.token_address, partner_addresses, ) channel_ids = [ channel_state.identifier for channel_state in channels_to_close ] waiting.wait_for_settle( self.raiden, registry_address, self.token_address, channel_ids, self.raiden.alarm.sleep_time, ) return channels_to_close
def get_channel_list(self, registry_address, token_address=None, partner_address=None): """Returns a list of channels associated with the optionally given `token_address` and/or `partner_address`. Args: token_address (bin): an optionally provided token address partner_address (bin): an optionally provided partner address Return: A list containing all channels the node participates. Optionally filtered by a token address and/or partner address. Raises: KeyError: An error occurred when the token address is unknown to the node. """ if token_address and not is_binary_address(token_address): raise InvalidAddress('Expected binary address format for token in get_channel_list') if partner_address and not is_binary_address(partner_address): raise InvalidAddress('Expected binary address format for partner in get_channel_list') result = list() if token_address and partner_address: channel_state = views.get_channelstate_for( views.state_from_raiden(self.raiden), registry_address, token_address, partner_address, ) if channel_state: result = [channel_state] else: result = [] elif token_address: result = views.list_channelstate_for_tokennetwork( views.state_from_raiden(self.raiden), registry_address, token_address, ) elif partner_address: result = views.list_channelstate_for_tokennetwork( views.state_from_raiden(self.raiden), registry_address, partner_address, ) else: result = views.list_all_channelstate( views.state_from_raiden(self.raiden), ) return result
def wait_for_block( raiden: RaidenService, block_number: typing.BlockNumber, retry_timeout: float, ) -> None: current_block_number = views.block_number( views.state_from_raiden(raiden), ) while current_block_number < block_number: gevent.sleep(retry_timeout) current_block_number = views.block_number( views.state_from_raiden(raiden), )
def transfer_async( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, amount: typing.TokenAmount, target: typing.Address, identifier: typing.PaymentID = None, ): if not isinstance(amount, int): raise InvalidAmount('Amount not a number') if amount <= 0: raise InvalidAmount('Amount negative') if not is_binary_address(token_address): raise InvalidAddress('token address is not valid.') if not is_binary_address(target): raise InvalidAddress('target address is not valid.') valid_tokens = views.get_token_network_addresses_for( views.state_from_raiden(self.raiden), registry_address, ) if token_address not in valid_tokens: raise UnknownTokenAddress('Token address is not known.') log.debug( 'Initiating transfer', initiator=pex(self.raiden.address), target=pex(target), token=pex(token_address), amount=amount, identifier=identifier, ) payment_network_identifier = self.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_raiden(self.raiden), payment_network_id=payment_network_identifier, token_address=token_address, ) async_result = self.raiden.mediated_transfer_async( token_network_identifier=token_network_identifier, amount=amount, target=target, identifier=identifier, ) return async_result
def handle_message_refundtransfer(raiden: RaidenService, message: RefundTransfer): token_network_address = message.token_network_address from_transfer = lockedtransfersigned_from_message(message) chain_state = views.state_from_raiden(raiden) routes = get_best_routes( chain_state, token_network_address, raiden.address, from_transfer.target, from_transfer.lock.amount, message.sender, ) role = views.get_transfer_role( chain_state, from_transfer.lock.secrethash, ) if role == 'initiator': secret = random_secret() state_change = ReceiveTransferRefundCancelRoute( message.sender, routes, from_transfer, secret, ) else: state_change = ReceiveTransferRefund( message.sender, from_transfer, routes, ) raiden.handle_state_change(state_change)
def get_tokens_list(self, registry_address): """Returns a list of tokens the node knows about""" tokens_list = views.get_token_network_addresses_for( views.state_from_raiden(self.raiden), registry_address, ) return tokens_list
def token_network_connect( self, registry_address, token_address, funds, initial_channel_target=3, joinable_funds_target=.4, ): """Automatically maintain channels open for the given token network. Args: token_address (bin): the ERC20 token network to connect to. funds (int): the amount of funds that can be used by the ConnectionMananger. initial_channel_target (int): number of channels to open proactively. joinable_funds_target (float): fraction of the funds that will be used to join channels opened by other participants. """ if not is_binary_address(token_address): raise InvalidAddress('token_address must be a valid address in binary') token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) connection_manager = self.raiden.connection_manager_for_token_network( token_network_identifier, ) connection_manager.connect( funds, initial_channel_target=initial_channel_target, joinable_funds_target=joinable_funds_target, )
def handle_channel_closed(raiden, event: Event): token_network_identifier = event.originating_contract data = event.event_data channel_identifier = data['channel_identifier'] transaction_hash = data['transactionHash'] assert transaction_hash, 'A mined transaction must have the hash field' channel_state = views.get_channelstate_by_token_network_identifier( views.state_from_raiden(raiden), token_network_identifier, channel_identifier, ) if channel_state: # The from address is included in the ChannelClosed event as the # closing_participant field channel_closed = ContractReceiveChannelClosed( transaction_hash=transaction_hash, transaction_from=data['closing_participant'], token_network_identifier=token_network_identifier, channel_identifier=channel_identifier, block_number=data['block_number'], ) raiden.handle_state_change(channel_closed) else: # This is a channel close event of a channel we're not a participant of channel_closed = ContractReceiveRouteClosed( transaction_hash=transaction_hash, token_network_identifier=token_network_identifier, channel_identifier=channel_identifier, block_number=data['block_number'], ) raiden.handle_state_change(channel_closed)
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 initiator_init( raiden, transfer_identifier, transfer_amount, transfer_secret, token_network_identifier, target_address, ): transfer_state = TransferDescriptionWithSecretState( transfer_identifier, transfer_amount, token_network_identifier, raiden.address, target_address, transfer_secret, ) previous_address = None routes = routing.get_best_routes( views.state_from_raiden(raiden), token_network_identifier, raiden.address, target_address, transfer_amount, previous_address, ) init_initiator_statechange = ActionInitInitiator( transfer_state, routes, ) return init_initiator_statechange
def initiator_init( raiden: 'RaidenService', transfer_identifier: PaymentID, transfer_amount: PaymentAmount, transfer_secret: Secret, token_network_identifier: TokenNetworkID, target_address: TargetAddress, ): msg = 'Should never end up initiating transfer with Secret 0x0' assert transfer_secret != constants.EMPTY_HASH, msg transfer_state = TransferDescriptionWithSecretState( raiden.default_registry.address, transfer_identifier, transfer_amount, token_network_identifier, InitiatorAddress(raiden.address), target_address, transfer_secret, ) previous_address = None routes = routing.get_best_routes( chain_state=views.state_from_raiden(raiden), token_network_id=token_network_identifier, from_address=InitiatorAddress(raiden.address), to_address=target_address, amount=transfer_amount, previous_address=previous_address, config=raiden.config, ) init_initiator_statechange = ActionInitInitiator( transfer_state, routes, ) return init_initiator_statechange
def token_network_leave( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, ) -> typing.List[NettingChannelState]: """ Close all channels and wait for settlement. """ if not is_binary_address(registry_address): raise InvalidAddress('registry_address must be a valid address in binary') if not is_binary_address(token_address): raise InvalidAddress('token_address must be a valid address in binary') if token_address not in self.get_tokens_list(registry_address): raise UnknownTokenAddress('token_address unknown') token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) connection_manager = self.raiden.connection_manager_for_token_network( token_network_identifier, ) return connection_manager.leave(registry_address)
def wait_for_settle( raiden: RaidenService, payment_network_id: typing.PaymentNetworkID, token_address: typing.TokenAddress, channel_ids: typing.List[typing.ChannelID], retry_timeout: float, ) -> None: """Wait until all channels are settled. Note: This does not time out, use gevent.Timeout. """ if not isinstance(channel_ids, list): raise ValueError('channel_ids must be a list') channel_ids = list(channel_ids) while channel_ids: last_id = channel_ids[-1] channel_state = views.get_channelstate_by_id( views.state_from_raiden(raiden), payment_network_id, token_address, last_id, ) channel_is_settled = ( channel_state is None or channel.get_status(channel_state) == CHANNEL_STATE_SETTLED ) if channel_is_settled: channel_ids.pop() else: gevent.sleep(retry_timeout)
def install_all_blockchain_filters( self, token_network_registry_proxy: TokenNetworkRegistry, secret_registry_proxy: SecretRegistry, from_block: BlockNumber, ): with self.event_poll_lock: node_state = views.state_from_raiden(self) token_networks = views.get_token_network_identifiers( node_state, token_network_registry_proxy.address, ) self.blockchain_events.add_token_network_registry_listener( token_network_registry_proxy=token_network_registry_proxy, contract_manager=self.contract_manager, from_block=from_block, ) self.blockchain_events.add_secret_registry_listener( secret_registry_proxy=secret_registry_proxy, contract_manager=self.contract_manager, from_block=from_block, ) for token_network in token_networks: token_network_proxy = self.chain.token_network( TokenNetworkAddress(token_network), ) self.blockchain_events.add_token_network_listener( token_network_proxy=token_network_proxy, contract_manager=self.contract_manager, from_block=from_block, )
def wait_for_close( raiden: RaidenService, payment_network_id: typing.PaymentNetworkID, token_address: typing.TokenAddress, channel_ids: typing.List[typing.ChannelID], retry_timeout: float, ) -> None: """Wait until all channels are closed. Note: This does not time out, use gevent.Timeout. """ channel_ids = list(channel_ids) while channel_ids: last_id = channel_ids[-1] channel_state = views.get_channelstate_by_id( views.state_from_raiden(raiden), payment_network_id, token_address, last_id, ) channel_is_settled = ( channel_state is None or channel.get_status(channel_state) in CHANNEL_AFTER_CLOSE_STATES ) if channel_is_settled: channel_ids.pop() else: gevent.sleep(retry_timeout)
def wait_for_settle_all_channels( raiden: RaidenService, retry_timeout: float, ) -> None: """Wait until all channels are settled. Note: This does not time out, use gevent.Timeout. """ chain_state = views.state_from_raiden(raiden) id_paymentnetworkstate = chain_state.identifiers_to_paymentnetworks.items() for payment_network_id, payment_network_state in id_paymentnetworkstate: id_tokennetworkstate = payment_network_state.tokenidentifiers_to_tokennetworks.items() for token_network_id, token_network_state in id_tokennetworkstate: channel_ids = token_network_state.channelidentifiers_to_channels.keys() wait_for_settle( raiden, payment_network_id, token_network_id, channel_ids, retry_timeout, )
def get_tokens_list(self, registry_address: typing.PaymentNetworkID): """Returns a list of tokens the node knows about""" tokens_list = views.get_token_network_addresses_for( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, ) return tokens_list
def __repr__(self) -> str: open_channels = views.get_channelstate_open( chain_state=views.state_from_raiden(self.raiden), payment_network_id=self.registry_address, token_address=self.token_address, ) return f'{self.__class__.__name__}(target={self.initial_channel_target} ' +\ f'channels={len(open_channels)}:{open_channels!r})'
def wait_for_payment_network( raiden: RaidenService, payment_network_id: typing.PaymentNetworkID, token_address: typing.TokenAddress, retry_timeout: float, ) -> None: token_network = views.get_token_network_by_token_address( views.state_from_raiden(raiden), payment_network_id, token_address, ) while token_network is None: gevent.sleep(retry_timeout) token_network = views.get_token_network_by_token_address( views.state_from_raiden(raiden), payment_network_id, token_address, )
def wait_for_payment_balance( raiden: RaidenService, payment_network_id: typing.PaymentNetworkID, token_address: typing.TokenAddress, partner_address: typing.Address, target_address: typing.Address, target_balance: typing.TokenAmount, retry_timeout: float, ) -> None: """Wait until a given channels balance exceeds the target balance. Note: This does not time out, use gevent.Timeout. """ def get_balance(end_state): if end_state.balance_proof: return end_state.balance_proof.transferred_amount else: return 0 if target_address == raiden.address: balance = lambda channel_state: get_balance(channel_state.partner_state) elif target_address == partner_address: balance = lambda channel_state: get_balance(channel_state.our_state) else: raise ValueError('target_address must be one of the channel participants') channel_state = views.get_channelstate_for( views.state_from_raiden(raiden), payment_network_id, token_address, partner_address, ) while balance(channel_state) < target_balance: log.critical('wait', b=balance(channel_state), t=target_balance) gevent.sleep(retry_timeout) channel_state = views.get_channelstate_for( views.state_from_raiden(raiden), payment_network_id, token_address, partner_address, )
def wait_for_healthy( raiden: RaidenService, node_address: typing.Address, retry_timeout: float, ) -> None: """Wait until `node_address` becomes healthy. Note: This does not time out, use gevent.Timeout. """ network_statuses = views.get_networkstatuses( views.state_from_raiden(raiden), ) while network_statuses.get(node_address) != NODE_NETWORK_REACHABLE: gevent.sleep(retry_timeout) network_statuses = views.get_networkstatuses( views.state_from_raiden(raiden), )
def log_open_channels(raiden, registry_address, token_address, funds): chain_state = views.state_from_raiden(raiden) open_channels = views.get_channelstate_open( chain_state=chain_state, payment_network_id=registry_address, token_address=token_address, ) if open_channels: sum_deposits = views.get_our_capacity_for_token_network( views.state_from_raiden(raiden), registry_address, token_address, ) log.debug( 'connect() called on an already joined token network', registry_address=pex(registry_address), token_address=pex(token_address), open_channels=len(open_channels), sum_deposits=sum_deposits, funds=funds, )
def handle_channel_new_balance(raiden, event: Event): data = event.event_data channel_identifier = data['channel_identifier'] token_network_identifier = event.originating_contract participant_address = data['participant'] total_deposit = data['args']['total_deposit'] deposit_block_number = data['block_number'] transaction_hash = data['transactionHash'] assert transaction_hash, 'A mined transaction must have the hash field' previous_channel_state = views.get_channelstate_by_token_network_identifier( views.state_from_raiden(raiden), token_network_identifier, channel_identifier, ) # Channels will only be registered if this node is a participant is_participant = previous_channel_state is not None if is_participant: previous_balance = previous_channel_state.our_state.contract_balance balance_was_zero = previous_balance == 0 deposit_transaction = TransactionChannelNewBalance( participant_address, total_deposit, deposit_block_number, ) newbalance_statechange = ContractReceiveChannelNewBalance( transaction_hash=transaction_hash, token_network_identifier=token_network_identifier, channel_identifier=channel_identifier, deposit_transaction=deposit_transaction, block_number=data['block_number'], ) raiden.handle_state_change(newbalance_statechange) if balance_was_zero and participant_address != raiden.address: connection_manager = raiden.connection_manager_for_token_network( token_network_identifier, ) join_channel = gevent.spawn( connection_manager.join_channel, participant_address, total_deposit, ) raiden.add_pending_greenlet(join_channel)
def token_network_connect( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, funds: typing.TokenAmount, initial_channel_target: int = 3, joinable_funds_target: float = 0.4, ) -> None: """ Automatically maintain channels open for the given token network. Args: token_address: the ERC20 token network to connect to. funds: the amount of funds that can be used by the ConnectionMananger. initial_channel_target: number of channels to open proactively. joinable_funds_target: fraction of the funds that will be used to join channels opened by other participants. """ if not is_binary_address(registry_address): raise InvalidAddress('registry_address must be a valid address in binary') if not is_binary_address(token_address): raise InvalidAddress('token_address must be a valid address in binary') token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) connection_manager = self.raiden.connection_manager_for_token_network( token_network_identifier, ) has_enough_reserve, estimated_required_reserve = has_enough_gas_reserve( raiden=self.raiden, channels_to_open=initial_channel_target, ) if not has_enough_reserve: raise InsufficientGasReserve(( 'The account balance is below the estimated amount necessary to ' 'finish the lifecycles of all active channels. A balance of at ' f'least {estimated_required_reserve} wei is required.' )) connection_manager.connect( funds=funds, initial_channel_target=initial_channel_target, joinable_funds_target=joinable_funds_target, )
def wait_for_participant_newbalance( raiden: RaidenService, payment_network_id: typing.PaymentNetworkID, token_address: typing.TokenAddress, partner_address: typing.Address, target_address: typing.Address, target_balance: typing.TokenAmount, retry_timeout: float, ) -> None: """Wait until a given channels balance exceeds the target balance. Note: This does not time out, use gevent.Timeout. """ if target_address == raiden.address: balance = lambda channel_state: channel_state.our_state.contract_balance elif target_address == partner_address: balance = lambda channel_state: channel_state.partner_state.contract_balance else: raise ValueError('target_address must be one of the channel participants') channel_state = views.get_channelstate_for( views.state_from_raiden(raiden), payment_network_id, token_address, partner_address, ) while balance(channel_state) < target_balance: gevent.sleep(retry_timeout) channel_state = views.get_channelstate_for( views.state_from_raiden(raiden), payment_network_id, token_address, partner_address, )
def _queueids_to_queues(self) -> QueueIdsToQueues: chain_state = views.state_from_raiden(self._raiden_service) return views.get_all_messagequeues(chain_state)
def run_test_refund_transfer( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout ): """A failed transfer must send a refund back. TODO: - Unlock the token on refund #1091 - Clear the merkletree and update the locked amount #193 - Remove the refund message type #490""" # Topology: # # 0 -> 1 -> 2 # app0, app1, app2 = raiden_chain token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address ) # make a transfer to test the path app0 -> app1 -> app2 identifier_path = 1 amount_path = 1 transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=amount_path, identifier=identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 transfer( initiator_app=app1, target_app=app2, token_address=token_address, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(1) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # app0 -> app1 -> app2 is the only available path, but the channel app1 -> # app2 doesn't have capacity, so a refund will be sent on app1 -> app0 identifier_refund = 3 amount_refund = 50 payment_status = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, payment_hash_invoice=EMPTY_PAYMENT_HASH_INVOICE ) msg = "there is no path with capacity, the transfer must fail" assert payment_status.payment_done.wait() is False, msg gevent.sleep(0.2) # A lock structure with the correct amount send_locked = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": amount_refund}}} ) assert send_locked secrethash = send_locked.transfer.lock.secrethash send_refund = raiden_events_search_for_item(app1.raiden, SendRefundTransfer, {}) assert send_refund lock = send_locked.transfer.lock refund_lock = send_refund.transfer.lock assert lock.amount == refund_lock.amount assert lock.secrethash assert lock.expiration assert lock.secrethash == refund_lock.secrethash # Both channels have the amount locked because of the refund message with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit - amount_path, [lock], app1, deposit + amount_path, [refund_lock], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # Additional checks for LockExpired causing nonce mismatch after refund transfer: # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046 # At this point make sure that the initiator has not deleted the payment task assert secrethash in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task # Wait for lock lock expiration but make sure app0 never processes LockExpired with dont_handle_lock_expired_mock(app0): wait_for_block( raiden=app0.raiden, block_number=channel.get_sender_expiration_threshold(lock) + 1, retry_timeout=retry_timeout, ) # make sure that app0 still has the payment task for the secrethash # https://github.com/raiden-network/raiden/issues/3183 assert secrethash in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task # make sure that app1 sent a lock expired message for the secrethash send_lock_expired = raiden_events_search_for_item( app1.raiden, SendLockExpired, {"secrethash": secrethash} ) assert send_lock_expired # make sure that app0 never got it state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(0, "latest") assert not search_for_item(state_changes, ReceiveLockExpired, {"secrethash": secrethash}) # Out of the handicapped app0 transport. # Now wait till app0 receives and processes LockExpired receive_lock_expired = wait_for_state_change( app0.raiden, ReceiveLockExpired, {"secrethash": secrethash}, retry_timeout ) # And also till app1 received the processed wait_for_state_change( app1.raiden, ReceiveProcessed, {"message_identifier": receive_lock_expired.message_identifier}, retry_timeout, ) # make sure app1 queue has cleared the SendLockExpired chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) result = [ (queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue ] assert not result # and now wait for 1 more block so that the payment task can be deleted wait_for_block( raiden=app0.raiden, block_number=app0.raiden.get_block_number() + 1, retry_timeout=retry_timeout, ) # and since the lock expired message has been sent and processed then the # payment task should have been deleted from both nodes # https://github.com/raiden-network/raiden/issues/3183 assert secrethash not in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task assert secrethash not in state_from_raiden(app1.raiden).payment_mapping.secrethashes_to_task
def run_test_different_view_of_last_bp_during_unlock( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout, blockchain_type, ): """Test for https://github.com/raiden-network/raiden/issues/3196#issuecomment-449163888""" # Topology: # # 0 -> 1 -> 2 # app0, app1, app2 = raiden_chain token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address ) token_proxy = app0.raiden.chain.token(token_address) initial_balance0 = token_proxy.balance_of(app0.raiden.address) initial_balance1 = token_proxy.balance_of(app1.raiden.address) # make a transfer to test the path app0 -> app1 -> app2 identifier_path = 1 amount_path = 1 transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=amount_path, identifier=identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 transfer( initiator_app=app1, target_app=app2, token_address=token_address, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # app0 -> app1 -> app2 is the only available path, but the channel app1 -> # app2 doesn't have capacity, so a refund will be sent on app1 -> app0 identifier_refund = 3 amount_refund = 50 payment_status = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, payment_hash_invoice=EMPTY_PAYMENT_HASH_INVOICE ) msg = "there is no path with capacity, the transfer must fail" assert payment_status.payment_done.wait() is False, msg gevent.sleep(0.2) # A lock structure with the correct amount send_locked = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": amount_refund}}} ) assert send_locked secrethash = send_locked.transfer.lock.secrethash send_refund = raiden_events_search_for_item(app1.raiden, SendRefundTransfer, {}) assert send_refund lock = send_locked.transfer.lock refund_lock = send_refund.transfer.lock assert lock.amount == refund_lock.amount assert lock.secrethash assert lock.expiration assert lock.secrethash == refund_lock.secrethash # Both channels have the amount locked because of the refund message with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit - amount_path, [lock], app1, deposit + amount_path, [refund_lock], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # Additional checks for LockExpired causing nonce mismatch after refund transfer: # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046 # At this point make sure that the initiator has not deleted the payment task assert secrethash in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task with dont_handle_node_change_network_state(): # now app1 goes offline app1.raiden.stop() app1.raiden.get() assert not app1.raiden # Wait for lock expiration so that app0 sends a LockExpired wait_for_block( raiden=app0.raiden, block_number=channel.get_sender_expiration_threshold(lock) + 1, retry_timeout=retry_timeout, ) # make sure that app0 sent a lock expired message for the secrethash wait_for_raiden_event( app0.raiden, SendLockExpired, {"secrethash": secrethash}, retry_timeout ) # now app0 closes the channel RaidenAPI(app0.raiden).channel_close( registry_address=payment_network_identifier, token_address=token_address, partner_address=app1.raiden.address, ) count = 0 original_update = app1.raiden.raiden_event_handler.handle_contract_send_channelupdate def patched_update(raiden, event): nonlocal count count += 1 original_update(raiden, event) app1.raiden.raiden_event_handler.handle_contract_send_channelupdate = patched_update # and now app1 comes back online app1.raiden.start() # test for https://github.com/raiden-network/raiden/issues/3216 assert count == 1, "Update transfer should have only been called once during restart" channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier # and we wait for settlement wait_for_settle( raiden=app0.raiden, payment_network_id=payment_network_identifier, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) timeout = 30 if blockchain_type == "parity" else 10 with gevent.Timeout(timeout): unlock_app0 = wait_for_state_change( app0.raiden, ContractReceiveChannelBatchUnlock, {"participant": app0.raiden.address}, retry_timeout, ) assert unlock_app0.returned_tokens == 50 with gevent.Timeout(timeout): unlock_app1 = wait_for_state_change( app1.raiden, ContractReceiveChannelBatchUnlock, {"participant": app1.raiden.address}, retry_timeout, ) assert unlock_app1.returned_tokens == 50 final_balance0 = token_proxy.balance_of(app0.raiden.address) final_balance1 = token_proxy.balance_of(app1.raiden.address) assert final_balance0 - deposit - initial_balance0 == -1 assert final_balance1 - deposit - initial_balance1 == 1
def run_smoketest(print_step: Callable, setup: RaidenTestSetup) -> None: print_step("Starting Raiden") app = None try: app = run_app(**setup.args) raiden_api = app.raiden.raiden_api assert raiden_api is not None # for mypy block = BlockNumber(app.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS) # Proxies now use the confirmed block hash to query the chain for # prerequisite checks. Wait a bit here to make sure that the confirmed # block hash contains the deployed token network or else things break wait_for_block(raiden=app.raiden, block_number=block, retry_timeout=1.0) raiden_api.channel_open( registry_address=TokenNetworkRegistryAddress( setup.contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]), token_address=TokenAddress( to_canonical_address(setup.token.address)), partner_address=ConnectionManager.BOOTSTRAP_ADDR, ) raiden_api.set_total_channel_deposit( registry_address=TokenNetworkRegistryAddress( setup.contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]), token_address=TokenAddress( to_canonical_address(setup.token.address)), partner_address=ConnectionManager.BOOTSTRAP_ADDR, total_deposit=TEST_DEPOSIT_AMOUNT, ) token_addresses = [to_checksum_address(setup.token.address) ] # type: ignore print_step("Running smoketest") raiden_service = app.raiden token_network_added_events = raiden_service.default_registry.filter_token_added_events( ) events_token_addresses = [ event["args"]["token_address"] for event in token_network_added_events ] assert events_token_addresses == token_addresses token_networks = views.get_token_identifiers( views.state_from_raiden(raiden_service), raiden_service.default_registry.address) assert len(token_networks) == 1 channel_state = views.get_channelstate_for( chain_state=views.state_from_raiden(raiden_service), token_network_registry_address=raiden_service.default_registry. address, token_address=token_networks[0], partner_address=ConnectionManager.BOOTSTRAP_ADDR, ) assert channel_state distributable = channel.get_distributable(channel_state.our_state, channel_state.partner_state) assert distributable == TEST_DEPOSIT_AMOUNT assert Balance( distributable) == channel_state.our_state.contract_balance assert channel.get_status(channel_state) == ChannelState.STATE_OPENED port_number = raiden_service.config.rest_api.port response = requests.get( f"http://localhost:{port_number}/api/v1/channels") assert response.status_code == HTTPStatus.OK response_json = json.loads(response.content) assert response_json[0]["partner_address"] == to_checksum_address( ConnectionManager.BOOTSTRAP_ADDR) assert response_json[0]["state"] == "opened" assert int(response_json[0]["balance"]) > 0 finally: if app is not None: app.stop() app.raiden.greenlet.get()
def channel_open( self, registry_address: TokenNetworkRegistryAddress, token_address: TokenAddress, partner_address: Address, settle_timeout: BlockTimeout = None, reveal_timeout: BlockTimeout = None, retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ) -> ChannelID: """ Open a channel with the peer at `partner_address` with the given `token_address`. """ if settle_timeout is None: settle_timeout = self.raiden.config.settle_timeout if reveal_timeout is None: reveal_timeout = self.raiden.config.reveal_timeout if reveal_timeout <= 0: raise InvalidRevealTimeout( "reveal_timeout should be larger than zero") if settle_timeout < reveal_timeout * 2: raise InvalidSettleTimeout( "`settle_timeout` can not be smaller than double the " "`reveal_timeout`.\n " "\n " "The setting `reveal_timeout` determines the maximum number of " "blocks it should take a transaction to be mined when the " "blockchain is under congestion. This setting determines the " "when a node must go on-chain to register a secret, and it is " "therefore the lower bound of the lock expiration. The " "`settle_timeout` determines when a channel can be settled " "on-chain, for this operation to be safe all locks must have " "been resolved, for this reason the `settle_timeout` has to be " "larger than `reveal_timeout`.") if not is_binary_address(registry_address): raise InvalidBinaryAddress( "Expected binary address format for registry in channel open") if not is_binary_address(token_address): raise InvalidBinaryAddress( "Expected binary address format for token in channel open") if not is_binary_address(partner_address): raise InvalidBinaryAddress( "Expected binary address format for partner in channel open") confirmed_block_identifier = views.get_confirmed_blockhash(self.raiden) registry = self.raiden.proxy_manager.token_network_registry( registry_address, block_identifier=confirmed_block_identifier) settlement_timeout_min = registry.settlement_timeout_min( block_identifier=confirmed_block_identifier) settlement_timeout_max = registry.settlement_timeout_max( block_identifier=confirmed_block_identifier) if settle_timeout < settlement_timeout_min: raise InvalidSettleTimeout( f"Settlement timeout should be at least {settlement_timeout_min}" ) if settle_timeout > settlement_timeout_max: raise InvalidSettleTimeout( f"Settlement timeout exceeds max of {settlement_timeout_max}") token_network_address = registry.get_token_network( token_address=token_address, block_identifier=confirmed_block_identifier) if token_network_address is None: raise TokenNotRegistered( "Token network for token %s does not exist" % to_checksum_address(token_address)) token_network = self.raiden.proxy_manager.token_network( address=token_network_address, block_identifier=confirmed_block_identifier) safety_deprecation_switch = token_network.safety_deprecation_switch( block_identifier=confirmed_block_identifier) if safety_deprecation_switch: msg = ( "This token_network has been deprecated. New channels cannot be " "open for this network, usage of the newly deployed token " "network contract is highly encouraged.") raise TokenNetworkDeprecated(msg) duplicated_channel = self.is_already_existing_channel( token_network_address=token_network_address, partner_address=partner_address, block_identifier=confirmed_block_identifier, ) if duplicated_channel: raise DuplicatedChannelError( f"A channel with {to_checksum_address(partner_address)} for token " f"{to_checksum_address(token_address)} already exists. " f"(At blockhash: {confirmed_block_identifier.hex()})") has_enough_reserve, estimated_required_reserve = has_enough_gas_reserve( self.raiden, channels_to_open=1) if not has_enough_reserve: raise InsufficientGasReserve( "The account balance is below the estimated amount necessary to " "finish the lifecycles of all active channels. A balance of at " f"least {estimated_required_reserve} wei is required.") try: token_network.new_netting_channel( partner=partner_address, settle_timeout=settle_timeout, given_block_identifier=confirmed_block_identifier, ) except DuplicatedChannelError: log.info("partner opened channel first") except RaidenRecoverableError: # The channel may have been created in the pending block. duplicated_channel = self.is_already_existing_channel( token_network_address=token_network_address, partner_address=partner_address) if duplicated_channel: log.info("Channel has already been opened") else: raise waiting.wait_for_newchannel( raiden=self.raiden, token_network_registry_address=registry_address, token_address=token_address, partner_address=partner_address, retry_timeout=retry_timeout, ) chain_state = views.state_from_raiden(self.raiden) channel_state = views.get_channelstate_for( chain_state=chain_state, token_network_registry_address=registry_address, token_address=token_address, partner_address=partner_address, ) assert channel_state, f"channel {channel_state} is gone" self.raiden.set_channel_reveal_timeout( canonical_identifier=channel_state.canonical_identifier, reveal_timeout=reveal_timeout) return channel_state.identifier
def start(self): """ Start the node synchronously. Raises directly if anything went wrong on startup """ if not self.stop_event.ready(): raise RuntimeError(f'{self!r} already started') self.stop_event.clear() if self.database_dir is not None: self.db_lock.acquire(timeout=0) assert self.db_lock.is_locked # start the registration early to speed up the start if self.config['transport_type'] == 'udp': endpoint_registration_greenlet = gevent.spawn( self.discovery.register, self.address, self.config['transport']['udp']['external_ip'], self.config['transport']['udp']['external_port'], ) storage = sqlite.SQLiteStorage(self.database_path, serialize.JSONSerializer()) self.wal = wal.restore_to_state_change( transition_function=node.state_transition, storage=storage, state_change_identifier='latest', ) if self.wal.state_manager.current_state is None: log.debug( 'No recoverable state available, created inital state', node=pex(self.address), ) # On first run Raiden needs to fetch all events for the payment # network, to reconstruct all token network graphs and find opened # channels last_log_block_number = self.query_start_block state_change = ActionInitChain( random.Random(), last_log_block_number, self.chain.node_address, self.chain.network_id, ) self.handle_state_change(state_change) payment_network = PaymentNetworkState( self.default_registry.address, [], # empty list of token network states as it's the node's startup ) state_change = ContractReceiveNewPaymentNetwork( constants.EMPTY_HASH, payment_network, last_log_block_number, ) self.handle_state_change(state_change) else: # The `Block` state change is dispatched only after all the events # for that given block have been processed, filters can be safely # installed starting from this position without losing events. last_log_block_number = views.block_number(self.wal.state_manager.current_state) log.debug( 'Restored state from WAL', last_restored_block=last_log_block_number, node=pex(self.address), ) known_networks = views.get_payment_network_identifiers(views.state_from_raiden(self)) if known_networks and self.default_registry.address not in known_networks: configured_registry = pex(self.default_registry.address) known_registries = lpex(known_networks) raise RuntimeError( f'Token network address mismatch.\n' f'Raiden is configured to use the smart contract ' f'{configured_registry}, which conflicts with the current known ' f'smart contracts {known_registries}', ) # Restore the current snapshot group state_change_qty = self.wal.storage.count_state_changes() self.snapshot_group = state_change_qty // SNAPSHOT_STATE_CHANGES_COUNT # Install the filters using the correct from_block value, otherwise # blockchain logs can be lost. self.install_all_blockchain_filters( self.default_registry, self.default_secret_registry, last_log_block_number, ) # Complete the first_run of the alarm task and synchronize with the # blockchain since the last run. # # Notes about setup order: # - The filters must be polled after the node state has been primed, # otherwise the state changes won't have effect. # - The alarm must complete its first run before the transport is started, # to reject messages for closed/settled channels. self.alarm.register_callback(self._callback_new_block) self.alarm.first_run(last_log_block_number) chain_state = views.state_from_raiden(self) self._initialize_transactions_queues(chain_state) self._initialize_whitelists(chain_state) # send messages in queue before starting transport, # this is necessary to avoid a race where, if the transport is started # before the messages are queued, actions triggered by it can cause new # messages to be enqueued before these older ones self._initialize_messages_queues(chain_state) # The transport must not ever be started before the alarm task's # `first_run()` has been, because it's this method which synchronizes the # node with the blockchain, including the channel's state (if the channel # is closed on-chain new messages must be rejected, which will not be the # case if the node is not synchronized) self.transport.start(self, self.message_handler) # First run has been called above! self.alarm.start() # exceptions on these subtasks should crash the app and bubble up self.alarm.link_exception(self.on_error) self.transport.link_exception(self.on_error) # Health check needs the transport layer self.start_neighbours_healthcheck(chain_state) if self.config['transport_type'] == 'udp': endpoint_registration_greenlet.get() # re-raise if exception occurred log.debug('Raiden Service started', node=pex(self.address)) super().start()
def handle_contract_send_channelunlock( raiden: 'RaidenService', channel_unlock_event: ContractSendChannelBatchUnlock, ): token_network_identifier = channel_unlock_event.token_network_identifier channel_identifier = channel_unlock_event.channel_identifier canonical_identifier = CanonicalIdentifier( chain_identifier=raiden.chain.network_id, token_network_address=token_network_identifier, channel_identifier=channel_identifier, ) participant = channel_unlock_event.participant token_address = channel_unlock_event.token_address payment_channel: PaymentChannel = raiden.chain.payment_channel( canonical_identifier=canonical_identifier, ) channel_state = get_channelstate_by_token_network_and_partner( chain_state=state_from_raiden(raiden), token_network_id=token_network_identifier, partner_address=participant, ) if not channel_state: # channel was cleaned up already due to an unlock raise RaidenUnrecoverableError( f'Failed to find channel state with partner ' f'{participant}, token_network:pex(token_network_identifier)', ) our_address = channel_state.our_state.address our_locksroot = channel_state.our_state.onchain_locksroot partner_address = channel_state.partner_state.address partner_locksroot = channel_state.partner_state.onchain_locksroot # we want to unlock because there are on-chain unlocked locks search_events = our_locksroot != EMPTY_HASH # we want to unlock, because there are unlocked/unclaimed locks search_state_changes = partner_locksroot != EMPTY_HASH if not search_events and not search_state_changes: # In the case that someone else sent the unlock we do nothing # Check https://github.com/raiden-network/raiden/issues/3152 # for more details log.warning( 'Onchain unlock already mined', token_address=token_address, channel_identifier=canonical_identifier.channel_identifier, participant=participant, ) return if search_state_changes: state_change_record = get_state_change_with_balance_proof_by_locksroot( storage=raiden.wal.storage, canonical_identifier=canonical_identifier, locksroot=partner_locksroot, sender=partner_address, ) state_change_identifier = state_change_record.state_change_identifier if not state_change_identifier: raise RaidenUnrecoverableError( f'Failed to find state that matches the current channel locksroots. ' f'chain_id:{raiden.chain.network_id} ' f'token:{to_checksum_address(token_address)} ' f'token_network:{to_checksum_address(token_network_identifier)} ' f'channel:{channel_identifier} ' f'participant:{to_checksum_address(participant)} ' f'our_locksroot:{to_hex(our_locksroot)} ' f'partner_locksroot:{to_hex(partner_locksroot)} ', ) restored_channel_state = channel_state_until_state_change( raiden=raiden, payment_network_identifier=raiden.default_registry.address, token_address=token_address, channel_identifier=channel_identifier, state_change_identifier=state_change_identifier, ) gain = get_batch_unlock_gain(restored_channel_state, ) skip_unlock = (restored_channel_state.partner_state.address == participant and gain.from_partner_locks == 0) if not skip_unlock: unlock( raiden=raiden, payment_channel=payment_channel, end_state=restored_channel_state.partner_state, participant=our_address, partner=partner_address, ) if search_events: event_record = get_event_with_balance_proof_by_locksroot( storage=raiden.wal.storage, canonical_identifier=canonical_identifier, locksroot=our_locksroot, recipient=partner_address, ) state_change_identifier = event_record.state_change_identifier if not state_change_identifier: raise RaidenUnrecoverableError( f'Failed to find event that match current channel locksroots. ' f'chain_id:{raiden.chain.network_id} ' f'token:{to_checksum_address(token_address)} ' f'token_network:{to_checksum_address(token_network_identifier)} ' f'channel:{channel_identifier} ' f'participant:{to_checksum_address(participant)} ' f'our_locksroot:{to_hex(our_locksroot)} ' f'partner_locksroot:{to_hex(partner_locksroot)} ', ) restored_channel_state = channel_state_until_state_change( raiden=raiden, payment_network_identifier=raiden.default_registry.address, token_address=token_address, channel_identifier=canonical_identifier.channel_identifier, state_change_identifier=state_change_identifier, ) gain = get_batch_unlock_gain(restored_channel_state, ) skip_unlock = (restored_channel_state.our_state.address == participant and gain.from_our_locks == 0) if not skip_unlock: unlock( raiden=raiden, payment_channel=payment_channel, end_state=restored_channel_state.our_state, participant=partner_address, partner=our_address, )
def start_async(self) -> RaidenGreenletEvent: """ Start the node asynchronously. """ self.start_event.clear() self.stop_event.clear() if self.database_dir is not None: self.db_lock.acquire(timeout=0) assert self.db_lock.is_locked # start the registration early to speed up the start if self.config['transport_type'] == 'udp': endpoint_registration_greenlet = gevent.spawn( self.discovery.register, self.address, self.config['transport']['udp']['external_ip'], self.config['transport']['udp']['external_port'], ) # The database may be :memory: storage = sqlite.SQLiteStorage(self.database_path, serialize.PickleSerializer()) self.wal = wal.restore_from_latest_snapshot( node.state_transition, storage, ) if self.wal.state_manager.current_state is None: log.debug('No recoverable state available, created inital state') block_number = self.chain.block_number() state_change = ActionInitChain( random.Random(), block_number, self.chain.node_address, self.chain.network_id, ) self.wal.log_and_dispatch(state_change, block_number) payment_network = PaymentNetworkState( self.default_registry.address, [], # empty list of token network states as it's the node's startup ) state_change = ContractReceiveNewPaymentNetwork( constants.NULL_ADDRESS, payment_network, ) self.handle_state_change(state_change) # On first run Raiden needs to fetch all events for the payment # network, to reconstruct all token network graphs and find opened # channels last_log_block_number = 0 else: # The `Block` state change is dispatched only after all the events # for that given block have been processed, filters can be safely # installed starting from this position without losing events. last_log_block_number = views.block_number(self.wal.state_manager.current_state) log.debug('Restored state from WAL', last_restored_block=last_log_block_number) # Restore the current snapshot group self.snapshot_group = last_log_block_number // SNAPSHOT_BLOCK_COUNT # Install the filters using the correct from_block value, otherwise # blockchain logs can be lost. self.install_all_blockchain_filters( self.default_registry, self.default_secret_registry, last_log_block_number, ) # Complete the first_run of the alarm task and synchronize with the # blockchain since the last run. # # Notes about setup order: # - The filters must be polled after the node state has been primed, # otherwise the state changes won't have effect. # - The alarm must complete its first run before the transport is started, # to avoid rejecting messages for unknown channels. self.alarm.register_callback(self._callback_new_block) self.alarm.first_run() chain_state = views.state_from_raiden(self) # Dispatch pending transactions pending_transactions = views.get_pending_transactions( chain_state, ) log.debug( 'Processing pending transactions', num_pending_transactions=len(pending_transactions), ) with self.dispatch_events_lock: for transaction in pending_transactions: on_raiden_event(self, transaction) self.alarm.start() queueids_to_queues = views.get_all_messagequeues(chain_state) self.transport.start(self, queueids_to_queues) # Health check needs the transport layer self.start_neighbours_healthcheck() if self.config['transport_type'] == 'udp': def set_start_on_registration(_): self.start_event.set() endpoint_registration_greenlet.link_safe(set_start_on_registration) else: self.start_event.set() return self.start_event
def open( self, registry_address: typing.PaymentNetworkID, partner_address: typing.Address, token_address: typing.TokenAddress, settle_timeout: typing.BlockTimeout = None, total_deposit: typing.TokenAmount = None, ): log.debug( 'Opening channel', node=pex(self.raiden_api.address), registry_address=to_checksum_address(registry_address), partner_address=to_checksum_address(partner_address), token_address=to_checksum_address(token_address), settle_timeout=settle_timeout, ) try: token = self.raiden_api.raiden.chain.token(token_address) except AddressWithoutCode as e: return api_error( errors=str(e), status_code=HTTPStatus.CONFLICT, ) balance = token.balance_of(self.raiden_api.raiden.address) if total_deposit is not None and total_deposit > balance: error_msg = 'Not enough balance to deposit. {} Available={} Needed={}'.format( pex(token_address), balance, total_deposit, ) return api_error( errors=error_msg, status_code=HTTPStatus.PAYMENT_REQUIRED, ) try: self.raiden_api.channel_open( registry_address, token_address, partner_address, settle_timeout, ) except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress, AddressWithoutCode, DuplicatedChannelError, TokenNotRegistered) as e: return api_error( errors=str(e), status_code=HTTPStatus.CONFLICT, ) except (InsufficientFunds, InsufficientGasReserve) as e: return api_error( errors=str(e), status_code=HTTPStatus.PAYMENT_REQUIRED, ) if total_deposit: # make initial deposit log.debug( 'Depositing to new channel', node=pex(self.raiden_api.address), registry_address=to_checksum_address(registry_address), token_address=to_checksum_address(token_address), partner_address=to_checksum_address(partner_address), total_deposit=total_deposit, ) try: self.raiden_api.set_total_channel_deposit( registry_address=registry_address, token_address=token_address, partner_address=partner_address, total_deposit=total_deposit, ) except InsufficientFunds as e: return api_error( errors=str(e), status_code=HTTPStatus.PAYMENT_REQUIRED, ) except (DepositOverLimit, DepositMismatch) as e: return api_error( errors=str(e), status_code=HTTPStatus.CONFLICT, ) channel_state = views.get_channelstate_for( views.state_from_raiden(self.raiden_api.raiden), registry_address, token_address, partner_address, ) result = self.channel_schema.dump(channel_state) return api_response( result=result.data, status_code=HTTPStatus.CREATED, )
def open( self, registry_address: typing.PaymentNetworkID, partner_address: typing.Address, token_address: typing.TokenAddress, settle_timeout: typing.BlockTimeout = None, reveal_timeout: typing.BlockTimeout = None, total_deposit: typing.TokenAmount = None, ): log.debug( 'Opening channel', registry_address=to_checksum_address(registry_address), partner_address=to_checksum_address(partner_address), token_address=to_checksum_address(token_address), settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, ) try: self.raiden_api.channel_open( registry_address, token_address, partner_address, settle_timeout, reveal_timeout, ) except EthNodeCommunicationError: return api_response( result='', status_code=HTTPStatus.ACCEPTED, ) except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress, AddressWithoutCode, DuplicatedChannelError, TokenNotRegistered) as e: return api_error( errors=str(e), status_code=HTTPStatus.CONFLICT, ) except (InsufficientFunds, InsufficientGasReserve) as e: return api_error( errors=str(e), status_code=HTTPStatus.PAYMENT_REQUIRED, ) if total_deposit: # make initial deposit log.debug( 'Depositing to new channel', registry_address=to_checksum_address(registry_address), token_address=to_checksum_address(token_address), partner_address=to_checksum_address(partner_address), total_deposit=total_deposit, ) try: self.raiden_api.set_total_channel_deposit( registry_address=registry_address, token_address=token_address, partner_address=partner_address, total_deposit=total_deposit, ) except EthNodeCommunicationError: return api_response( result='', status_code=HTTPStatus.ACCEPTED, ) except InsufficientFunds as e: return api_error( errors=str(e), status_code=HTTPStatus.PAYMENT_REQUIRED, ) except (DepositOverLimit, DepositMismatch) as e: return api_error( errors=str(e), status_code=HTTPStatus.CONFLICT, ) channel_state = views.get_channelstate_for( views.state_from_raiden(self.raiden_api.raiden), registry_address, token_address, partner_address, ) result = self.channel_schema.dump(channel_state) return api_response( result=result.data, status_code=HTTPStatus.CREATED, )
def transfer_async( self, registry_address: TokenNetworkRegistryAddress, token_address: TokenAddress, amount: PaymentAmount, target: TargetAddress, identifier: PaymentID = None, secret: Secret = None, secrethash: SecretHash = None, lock_timeout: BlockTimeout = None, ) -> "PaymentStatus": current_state = views.state_from_raiden(self.raiden) token_network_registry_address = self.raiden.default_registry.address if not isinstance(amount, int): # pragma: no unittest raise InvalidAmount("Amount not a number") if Address(target) == self.address: raise SamePeerAddress("Address must be different than ours") if amount <= 0: raise InvalidAmount("Amount negative") if amount > UINT256_MAX: raise InvalidAmount("Amount too large") if not is_binary_address(token_address): raise InvalidBinaryAddress("token address is not valid.") if token_address not in views.get_token_identifiers( current_state, registry_address): raise UnknownTokenAddress("Token address is not known.") if not is_binary_address(target): raise InvalidBinaryAddress("target address is not valid.") valid_tokens = views.get_token_identifiers( views.state_from_raiden(self.raiden), registry_address) if token_address not in valid_tokens: raise UnknownTokenAddress("Token address is not known.") if secret is not None and not isinstance(secret, T_Secret): raise InvalidSecret("secret is not valid.") if secrethash is not None and not isinstance(secrethash, T_SecretHash): raise InvalidSecretHash("secrethash is not valid.") if identifier is None: identifier = create_default_identifier() if identifier <= 0: raise InvalidPaymentIdentifier( "Payment identifier cannot be 0 or negative") if identifier > UINT64_MAX: raise InvalidPaymentIdentifier("Payment identifier is too large") log.debug( "Initiating transfer", initiator=to_checksum_address(self.raiden.address), target=to_checksum_address(target), token=to_checksum_address(token_address), amount=amount, identifier=identifier, ) token_network_address = views.get_token_network_address_by_token_address( chain_state=current_state, token_network_registry_address=token_network_registry_address, token_address=token_address, ) if token_network_address is None: raise UnknownTokenAddress( f"Token {to_checksum_address(token_address)} is not registered " f"with the network {to_checksum_address(registry_address)}.") payment_status = self.raiden.mediated_transfer_async( token_network_address=token_network_address, amount=amount, target=target, identifier=identifier, secret=secret, secrethash=secrethash, lock_timeout=lock_timeout, ) return payment_status
def get_channel_list( self, registry_address: TokenNetworkRegistryAddress, token_address: TokenAddress = None, partner_address: Address = None, ) -> List[NettingChannelState]: """Returns a list of channels associated with the optionally given `token_address` and/or `partner_address`. Args: token_address: an optionally provided token address partner_address: an optionally provided partner address Return: A list containing all channels the node participates. Optionally filtered by a token address and/or partner address. Raises: KeyError: An error occurred when the token address is unknown to the node. """ if registry_address and not is_binary_address(registry_address): raise InvalidBinaryAddress( "Expected binary address format for registry in get_channel_list" ) if token_address and not is_binary_address(token_address): raise InvalidBinaryAddress( "Expected binary address format for token in get_channel_list") if partner_address: if not is_binary_address(partner_address): raise InvalidBinaryAddress( "Expected binary address format for partner in get_channel_list" ) if not token_address: raise UnknownTokenAddress( "Provided a partner address but no token address") if token_address and partner_address: channel_state = views.get_channelstate_for( chain_state=views.state_from_raiden(self.raiden), token_network_registry_address=registry_address, token_address=token_address, partner_address=partner_address, ) if channel_state: result = [channel_state] else: result = [] elif token_address: result = views.list_channelstate_for_tokennetwork( chain_state=views.state_from_raiden(self.raiden), token_network_registry_address=registry_address, token_address=token_address, ) else: result = views.list_all_channelstate( chain_state=views.state_from_raiden(self.raiden)) return result
def open( self, registry_address, partner_address, token_address, settle_timeout=None, reveal_timeout=None, balance=None, ): try: self.raiden_api.channel_open( registry_address, token_address, partner_address, settle_timeout, reveal_timeout, ) except EthNodeCommunicationError: return api_response( result='', status_code=HTTPStatus.ACCEPTED, ) except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress, AddressWithoutCode, DuplicatedChannelError, TokenNotRegistered) as e: return api_error( errors=str(e), status_code=HTTPStatus.CONFLICT, ) except InsufficientFunds as e: return api_error( errors=str(e), status_code=HTTPStatus.PAYMENT_REQUIRED, ) if balance: # make initial deposit try: self.raiden_api.set_total_channel_deposit( registry_address, token_address, partner_address, balance, ) except EthNodeCommunicationError: return api_response( result='', status_code=HTTPStatus.ACCEPTED, ) except InsufficientFunds as e: return api_error( errors=str(e), status_code=HTTPStatus.PAYMENT_REQUIRED, ) except DepositOverLimit as e: return api_error( errors=str(e), status_code=HTTPStatus.CONFLICT, ) except DepositMismatch as e: return api_error( errors=str(e), status_code=HTTPStatus.CONFLICT, ) channel_state = views.get_channelstate_for( views.state_from_raiden(self.raiden_api.raiden), registry_address, token_address, partner_address, ) result = self.channel_schema.dump(channel_state) return api_response( result=result.data, status_code=HTTPStatus.CREATED, )
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_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address) assert token_network_address token_network = views.get_token_network_by_address( views.state_from_app(app0), token_network_address) assert token_network channel_identifier = get_channelstate(app0, app1, token_network_address).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 assert channel_state.close_transaction 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_address( views.state_from_app(app0), token_network_address) assert token_network assert (channel_identifier not in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address]) state_changes = app0.raiden.wal.storage.get_statechanges_by_range( RANGE_ALL_STATE_CHANGES) assert search_for_item( state_changes, ContractReceiveChannelClosed, { "token_network_address": token_network_address, "channel_identifier": channel_identifier, "transaction_from": app1.raiden.address, "block_number": channel_state.close_transaction.finished_block_number, }, ) assert search_for_item( state_changes, ContractReceiveChannelSettled, { "token_network_address": token_network_address, "channel_identifier": channel_identifier }, )
def test_mediated_transfer_with_node_consuming_more_than_allocated_fee( raiden_network, number_of_nodes, deposit, token_addresses, network_wait): """ Tests a mediator node consuming more fees than allocated. Which means that the initiator will not reveal the secret to the target. """ app0, app1, app2 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) token_network_registry_address = app0.raiden.default_registry.address token_network_address = views.get_token_network_address_by_token_address( chain_state, token_network_registry_address, token_address) assert token_network_address amount = PaymentAmount(100) fee = FeeAmount(5) fee_margin = calculate_fee_margin(amount, fee) app1_app2_channel_state = views.get_channelstate_by_token_network_and_partner( chain_state=views.state_from_raiden(app1.raiden), token_network_address=token_network_address, partner_address=app2.raiden.address, ) assert app1_app2_channel_state # Let app1 consume all of the allocated mediation fee app1_app2_channel_state.fee_schedule = FeeScheduleState( flat=FeeAmount(fee * 2)) secret = factories.make_secret(0) secrethash = sha256_secrethash(secret) wait_message_handler = WaitForMessage() app0.raiden.message_handler = wait_message_handler secret_request_received = wait_message_handler.wait_for_message( SecretRequest, {"secrethash": secrethash}) def get_best_routes_with_fees(*args, **kwargs): error_msg, routes, uuid = get_best_routes(*args, **kwargs) for r in routes: r.estimated_fee = fee return error_msg, routes, uuid with patch("raiden.routing.get_best_routes", get_best_routes_with_fees): app0.raiden.start_mediated_transfer_with_secret( token_network_address=token_network_address, amount=amount, target=app2.raiden.address, identifier=1, secret=secret, ) app0_app1_channel_state = views.get_channelstate_by_token_network_and_partner( chain_state=views.state_from_raiden(app0.raiden), token_network_address=token_network_address, partner_address=app1.raiden.address, ) assert app0_app1_channel_state msg = "App0 should have the transfer in secrethashes_to_lockedlocks" assert secrethash in app0_app1_channel_state.our_state.secrethashes_to_lockedlocks, msg msg = "App0 should have locked the amount + fee" lock_amount = app0_app1_channel_state.our_state.secrethashes_to_lockedlocks[ secrethash].amount assert lock_amount == amount + fee + fee_margin, msg secret_request_received.wait() app0_chain_state = views.state_from_app(app0) initiator_task = cast( InitiatorTask, app0_chain_state.payment_mapping.secrethashes_to_task[secrethash]) msg = "App0 should have never revealed the secret" transfer_state = initiator_task.manager_state.initiator_transfers[ secrethash].transfer_state assert transfer_state != "transfer_secret_revealed", msg
def reveal_secret_with_resolver( raiden: "RaidenService", chain_state: ChainState, secret_request_event: SendSecretRequest) -> bool: resolver_endpoint = raiden.config.resolver_endpoint if not resolver_endpoint: return False log.debug("Using resolver to fetch secret", resolver_endpoint=resolver_endpoint) assert isinstance(raiden.wal, WriteAheadLog), "RaidenService has not been started" current_state = raiden.wal.state_manager.current_state if current_state is None: return False task = current_state.payment_mapping.secrethashes_to_task[ secret_request_event.secrethash] token = task.target_state.transfer.token request = { "token": to_hex(token), "secrethash": to_hex(secret_request_event.secrethash), "amount": secret_request_event.amount, "payment_identifier": secret_request_event.payment_identifier, "payment_sender": to_hex(secret_request_event.recipient), "expiration": secret_request_event.expiration, "payment_recipient": to_hex(raiden.address), "chain_id": chain_state.chain_id, } # loop until we get a valid response from the resolver or until timeout while True: current_state = views.state_from_raiden(raiden) if secret_request_event.expiration < current_state.block_number: log.debug("Stopped using resolver, transfer expired", resolver_endpoint=resolver_endpoint) # The locked transfer is expired now, so it makes no sense to continue processing it. # When returning `False`, the event handler would contiue processing the events, which # is not what is wanted here, so we return `True` to cancel return True response = None try: # before calling resolver, update block height request["chain_height"] = chain_state.block_number response = requests.post(resolver_endpoint, json=request) except requests.exceptions.RequestException: pass # no response means the resolver could not be reached and we should try again if response is not None: if response.status_code == HTTPStatus.OK: # request succeeded so we can break the loop and use the secret break elif response.status_code == HTTPStatus.SERVICE_UNAVAILABLE: # treat SERVICE UNAVAILABLE as if the resolver could not be reached and try again pass else: # on any other status code, treat the request as having failed and return False return False gevent.sleep(5) log.debug("Got secret from resolver, dispatching secret reveal", resolver_endpoint=resolver_endpoint) state_change = ReceiveSecretReveal( sender=secret_request_event.recipient, secret=Secret(to_bytes(hexstr=json.loads(response.content)["secret"])), ) raiden.handle_and_track_state_changes([state_change]) return True
def test_send_queued_messages_after_restart( # pylint: disable=unused-argument raiden_network: List[App], restart_node: RestartNode, deposit: TokenAmount, token_addresses: List[TokenAddress], network_wait: float, ): """Test re-sending of undelivered messages on node restart""" app0, app1 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) token_network_registry_address = app0.raiden.default_registry.address token_network_address = views.get_token_network_address_by_token_address( chain_state, token_network_registry_address, token_address) assert token_network_address number_of_transfers = 7 amount_per_transfer = PaymentAmount(1) total_transferred_amount = TokenAmount(amount_per_transfer * number_of_transfers) # Make sure none of the transfers will be sent before the restart transfers = [] for secret_seed in range(number_of_transfers): secret = make_secret(secret_seed) secrethash = sha256_secrethash(secret) transfers.append((create_default_identifier(), amount_per_transfer, secret, secrethash)) assert isinstance(app0.raiden.raiden_event_handler, HoldRaidenEventHandler) # for mypy app0.raiden.raiden_event_handler.hold( SendLockedTransfer, {"transfer": { "lock": { "secrethash": secrethash } }}) for identifier, amount, secret, _ in transfers: app0.raiden.mediated_transfer_async( token_network_address=token_network_address, amount=amount, target=TargetAddress(app1.raiden.address), identifier=identifier, secret=secret, ) app0.stop() # Restart the app. The pending transfers must be processed. new_transport = MatrixTransport( config=app0.raiden.config.transport, environment=app0.raiden.config.environment_type) raiden_event_handler = RaidenEventHandler() message_handler = MessageHandler() app0_restart = App( config=app0.config, rpc_client=app0.raiden.rpc_client, proxy_manager=app0.raiden.proxy_manager, query_start_block=BlockNumber(0), default_registry=app0.raiden.default_registry, default_secret_registry=app0.raiden.default_secret_registry, default_service_registry=app0.raiden.default_service_registry, default_user_deposit=app0.raiden.default_user_deposit, default_one_to_n_address=app0.raiden.default_one_to_n_address, default_msc_address=app0.raiden.default_msc_address, transport=new_transport, raiden_event_handler=raiden_event_handler, message_handler=message_handler, routing_mode=RoutingMode.PRIVATE, ) del app0 restart_node(app0_restart) # XXX: There is no synchronization among the app and the test, so it is # possible between `start` and the check below that some of the transfers # have completed, making it flaky. # # Make sure the transfers are in the queue and fail otherwise. chain_state = views.state_from_raiden(app0_restart.raiden) for _, _, _, secrethash in transfers: msg = "The secrethashes of the pending transfers must be in the queue after a restart." assert secrethash in chain_state.payment_mapping.secrethashes_to_task, msg timeout = block_offset_timeout( app1.raiden, "Timeout waiting for balance update of app0") with watch_for_unlock_failures(*raiden_network), timeout: waiting.wait_for_payment_balance( raiden=app0_restart.raiden, token_network_registry_address=token_network_registry_address, token_address=token_address, partner_address=app1.raiden.address, target_address=app1.raiden.address, target_balance=total_transferred_amount, retry_timeout=network_wait, ) timeout.exception_to_throw = ValueError( "Timeout waiting for balance update of app1") waiting.wait_for_payment_balance( raiden=app1.raiden, token_network_registry_address=token_network_registry_address, token_address=token_address, partner_address=app0_restart.raiden.address, target_address=app1.raiden.address, target_balance=total_transferred_amount, retry_timeout=network_wait, ) assert_synced_channel_state( token_network_address, app0_restart, Balance(deposit - total_transferred_amount), [], app1, Balance(deposit + total_transferred_amount), [], ) new_transport.stop()
def get_tokens_list(self, registry_address: TokenNetworkRegistryAddress) -> List[TokenAddress]: """Returns a list of tokens the node knows about""" return views.get_token_identifiers( chain_state=views.state_from_raiden(self.raiden), token_network_registry_address=registry_address, )
def get_node_network_state(self, node_address: Address) -> NetworkState: """ Returns the currently network status of `node_address`. """ return views.get_node_network_status( chain_state=views.state_from_raiden(self.raiden), node_address=node_address)
def set_total_channel_withdraw( self, registry_address: TokenNetworkRegistryAddress, token_address: TokenAddress, partner_address: Address, total_withdraw: WithdrawAmount, retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ) -> None: """ Set the `total_withdraw` in the channel with the peer at `partner_address` and the given `token_address`. Raises: InvalidBinaryAddress: If either token_address or partner_address is not 20 bytes long. RaidenUnrecoverableError: May happen for multiple reasons: - During preconditions checks, if the channel was not open at the time of the approve_and_set_total_deposit call. - If the transaction fails during gas estimation or if a previous withdraw transaction with the same value was already mined. DepositMismatch: The total withdraw amount did not increase. """ chain_state = views.state_from_raiden(self.raiden) token_addresses = views.get_token_identifiers(chain_state, registry_address) channel_state = views.get_channelstate_for( chain_state=chain_state, token_network_registry_address=registry_address, token_address=token_address, partner_address=partner_address, ) if not is_binary_address(token_address): raise InvalidBinaryAddress( "Expected binary address format for token in channel deposit") if not is_binary_address(partner_address): raise InvalidBinaryAddress( "Expected binary address format for partner in channel deposit" ) if token_address not in token_addresses: raise UnknownTokenAddress("Unknown token address") if channel_state is None: raise NonexistingChannel( "No channel with partner_address for the given token") if total_withdraw <= channel_state.our_total_withdraw: raise WithdrawMismatch( f"Total withdraw {total_withdraw} did not increase") current_balance = channel.get_balance( sender=channel_state.our_state, receiver=channel_state.partner_state) amount_to_withdraw = total_withdraw - channel_state.our_total_withdraw if amount_to_withdraw > current_balance: raise InsufficientFunds( "The withdraw of {} is bigger than the current balance of {}". format(amount_to_withdraw, current_balance)) self.raiden.withdraw( canonical_identifier=channel_state.canonical_identifier, total_withdraw=total_withdraw) waiting.wait_for_withdraw_complete( raiden=self.raiden, canonical_identifier=channel_state.canonical_identifier, total_withdraw=total_withdraw, retry_timeout=retry_timeout, )
def test_participant_selection(raiden_network, token_addresses, skip_if_tester): registry_address = raiden_network[0].raiden.default_registry.address # pylint: disable=too-many-locals token_address = token_addresses[0] # connect the first node (will register the token if necessary) RaidenAPI(raiden_network[0].raiden).token_network_connect( registry_address, token_address, 100, ) # connect the other nodes connect_greenlets = [ gevent.spawn( RaidenAPI(app.raiden).token_network_connect, registry_address, token_address, 100, ) for app in raiden_network[1:] ] gevent.wait(connect_greenlets) token_network_registry_address = views.get_token_network_identifier_by_token_address( views.state_from_raiden(raiden_network[0].raiden), payment_network_id=registry_address, token_address=token_address, ) connection_managers = [ app.raiden.connection_manager_for_token_network( token_network_registry_address, ) for app in raiden_network ] assert wait_for_saturated( connection_managers, registry_address, token_address, ) is True assert saturated_count( connection_managers, registry_address, token_address, ) == len(connection_managers) # ensure unpartitioned network for app in raiden_network: node_state = views.state_from_raiden(app.raiden) network_state = views.get_token_network_by_token_address( node_state, registry_address, token_address, ) assert network_state is not None for target in raiden_network: if target.raiden.address == app.raiden.address: continue routes = routing.get_best_routes( node_state, network_state.address, app.raiden.address, target.raiden.address, 1, None, ) assert routes is not None # create a transfer to the leaving node, so we have a channel to settle sender = raiden_network[-1].raiden receiver = raiden_network[0].raiden registry_address = sender.default_registry.address # assert there is a direct channel receiver -> sender (vv) receiver_channel = RaidenAPI(receiver).get_channel_list( registry_address=registry_address, token_address=token_address, partner_address=sender.address, ) assert len(receiver_channel) == 1 receiver_channel = receiver_channel[0] # assert there is a direct channel sender -> receiver sender_channel = RaidenAPI(sender).get_channel_list( registry_address=registry_address, token_address=token_address, partner_address=receiver.address, ) assert len(sender_channel) == 1 sender_channel = sender_channel[0] exception = ValueError('partner not reachable') with gevent.Timeout(30, exception=exception): waiting.wait_for_healthy(sender, receiver.address, 1) amount = 1 RaidenAPI(sender).transfer_and_wait( registry_address, token_address, amount, receiver.address, transfer_timeout=10, ) exception = ValueError('timeout while waiting for incoming transaction') with gevent.Timeout(30, exception=exception): wait_for_transaction( receiver, registry_address, token_address, sender.address, ) # test `leave()` method connection_manager = connection_managers[0] timeout = ( sender_channel.settle_timeout * connection_manager.raiden.chain.estimate_blocktime() * 10 ) assert timeout > 0 exception = ValueError('timeout while waiting for leave') with gevent.Timeout(timeout, exception=exception): RaidenAPI(raiden_network[0].raiden).token_network_leave( registry_address, token_address, ) before_block = connection_manager.raiden.chain.block_number() wait_blocks = sender_channel.settle_timeout + 10 # wait until both chains are synced? wait_until_block( connection_manager.raiden.chain, before_block + wait_blocks, ) wait_until_block( receiver.chain, before_block + wait_blocks, ) receiver_channel = RaidenAPI(receiver).get_channel_list( registry_address=registry_address, token_address=token_address, partner_address=sender.address, ) assert receiver_channel[0].settle_transaction is not None
def connect( self, funds: typing.TokenAmount, initial_channel_target: int = 3, joinable_funds_target: float = 0.4, ): """Connect to the network. Subsequent calls to `connect` are allowed, but will only affect the spendable funds and the connection strategy parameters for the future. `connect` will not close any channels. Note: the ConnectionManager does not discriminate manually opened channels from automatically opened ones. If the user manually opened channels, those deposit amounts will affect the funding per channel and the number of new channels opened. Args: funds: Target amount of tokens spendable to join the network. initial_channel_target: Target number of channels to open. joinable_funds_target: Amount of funds not initially assigned. """ token = self.raiden.chain.token(self.token_address) token_balance = token.balance_of(self.raiden.address) if token_balance < funds: raise InvalidAmount( f'Insufficient balance for token {pex(self.token_address)}', ) if funds <= 0: raise InvalidAmount( 'The funds to use in the connection need to be a positive integer', ) if joinable_funds_target < 0 or joinable_funds_target > 1: raise InvalidAmount( f'joinable_funds_target should be between 0 and 1. Given: {joinable_funds_target}', ) with self.lock: self.funds = funds self.initial_channel_target = initial_channel_target self.joinable_funds_target = joinable_funds_target log_open_channels(self.raiden, self.registry_address, self.token_address, funds) qty_network_channels = views.count_token_network_channels( views.state_from_raiden(self.raiden), self.registry_address, self.token_address, ) if not qty_network_channels: log.info( 'Bootstrapping token network.', node=pex(self.raiden.address), network_id=pex(self.registry_address), token_id=pex(self.token_address), ) self.api.channel_open( self.registry_address, self.token_address, self.BOOTSTRAP_ADDR, ) else: self._open_channels()
def join_channel(self, partner_address, partner_deposit): """Will be called, when we were selected as channel partner by another node. It will fund the channel with up to the partners deposit, but not more than remaining funds or the initial funding per channel. If the connection manager has no funds, this is a noop. """ # Consider this race condition: # # - Partner opens the channel and starts the deposit. # - This nodes learns about the new channel, starts ConnectionManager's # retry_connect, which will start a deposit for this half of the # channel. # - This node learns about the partner's deposit before its own. # join_channel is called which will try to deposit again. # # To fix this race, first the node must wait for the pending operations # to finish, because in them could be a deposit, and then deposit must # be called only if the channel is still not funded. token_network_proxy = self.raiden.chain.token_network( self.token_network_identifier) # Wait for any pending operation in the channel to complete, before # deciding on the deposit with self.lock, token_network_proxy.channel_operations_lock[ partner_address]: channel_state = views.get_channelstate_for( views.state_from_raiden(self.raiden), self.token_network_identifier, self.token_address, partner_address, ) if not channel_state: return joining_funds = min( partner_deposit, self._funds_remaining, self._initial_funding_per_partner, ) if joining_funds <= 0 or self._leaving_state: return if joining_funds <= channel_state.our_state.contract_balance: return try: self.api.set_total_channel_deposit( self.registry_address, self.token_address, partner_address, joining_funds, ) except RaidenRecoverableError: log.info( 'Channel not in opened state', node=pex(self.raiden.address), ) except InvalidDBData: raise except RaidenUnrecoverableError as e: should_crash = ( self.raiden.config['environment_type'] != Environment.PRODUCTION or self.raiden.config['unrecoverable_error_should_crash']) if should_crash: raise log.critical( str(e), node=pex(self.raiden.address), ) else: log.info( 'Joined a channel', node=pex(self.raiden.address), partner=pex(partner_address), funds=joining_funds, )
def _open_channels(self) -> bool: """ Open channels until there are `self.initial_channel_target` channels open. Do nothing if there are enough channels open already. Note: - This method must be called with the lock held. Return: - False if no channels could be opened """ open_channels = views.get_channelstate_open( chain_state=views.state_from_raiden(self.raiden), payment_network_id=self.registry_address, token_address=self.token_address, ) open_channels = [ channel_state for channel_state in open_channels if channel_state.partner_state.address != self.BOOTSTRAP_ADDR ] funded_channels = [ channel_state for channel_state in open_channels if channel_state.our_state.contract_balance >= self._initial_funding_per_partner ] nonfunded_channels = [ channel_state for channel_state in open_channels if channel_state not in funded_channels ] possible_new_partners = self._find_new_partners() if possible_new_partners == 0: return False # if we already met our target, break if len(funded_channels) >= self.initial_channel_target: return False # if we didn't, but there's no nonfunded channels and no available partners # it means the network is smaller than our target, so we should also break if not nonfunded_channels and possible_new_partners == 0: return False n_to_join = self.initial_channel_target - len(funded_channels) nonfunded_partners = [ channel_state.partner_state.address for channel_state in nonfunded_channels ] # first, fund nonfunded channels, then open and fund with possible_new_partners, # until initial_channel_target of funded channels is met join_partners = (nonfunded_partners + possible_new_partners)[:n_to_join] log.debug( 'Spawning greenlets to join partners', node=pex(self.raiden.address), num_greenlets=len(join_partners), ) greenlets = [ gevent.spawn(self._join_partner, partner) for partner in join_partners ] gevent.joinall(greenlets, raise_error=True) return True
def get_node_network_state(self, node_address: typing.Address): """ Returns the currently network status of `node_address`. """ return views.get_node_network_status( views.state_from_raiden(self.raiden), node_address, )
def run_smoketests(raiden_service: RaidenService, test_config: Dict, debug: bool = False): """ Test that the assembled raiden_service correctly reflects the configuration from the smoketest_genesis. """ try: chain = raiden_service.chain assert ( raiden_service.default_registry.address == to_canonical_address( test_config['contracts']['registry_address'])) assert (raiden_service.default_secret_registry.address == to_canonical_address( test_config['contracts']['secret_registry_address'])) token_network_added_events = raiden_service.default_registry.filter_token_added_events( ) token_addresses = [ event['args']['token_address'] for event in token_network_added_events ] assert token_addresses == [test_config['contracts']['token_address']] if test_config.get('transport') == 'udp': assert len(chain.address_to_discovery.keys()) == 1, repr( chain.address_to_discovery) assert (list( chain.address_to_discovery.keys())[0] == to_canonical_address( test_config['contracts']['discovery_address'])) discovery = list(chain.address_to_discovery.values())[0] assert discovery.endpoint_by_address( raiden_service.address) != TEST_ENDPOINT token_networks = views.get_token_network_addresses_for( views.state_from_raiden(raiden_service), raiden_service.default_registry.address, ) assert len(token_networks) == 1 channel_state = views.get_channelstate_for( views.state_from_raiden(raiden_service), raiden_service.default_registry.address, token_networks[0], unhexlify(TEST_PARTNER_ADDRESS), ) distributable = channel.get_distributable( channel_state.our_state, channel_state.partner_state, ) assert distributable == TEST_DEPOSIT_AMOUNT assert distributable == channel_state.our_state.contract_balance assert channel.get_status(channel_state) == CHANNEL_STATE_OPENED # Run API test run_restapi_smoketests() except Exception: error = traceback.format_exc() if debug: import pdb pdb.post_mortem() # pylint: disable=no-member return error
def channel_batch_close( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, partner_addresses: typing.List[typing.Address], retry_timeout: typing.NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ): """Close a channel opened with `partner_address` for the given `token_address`. Race condition, this can fail if channel was closed externally. """ if not is_binary_address(token_address): raise InvalidAddress('Expected binary address format for token in channel close') if not all(map(is_binary_address, partner_addresses)): raise InvalidAddress('Expected binary address format for partner in channel close') valid_tokens = views.get_token_network_addresses_for( views.state_from_raiden(self.raiden), registry_address, ) if token_address not in valid_tokens: raise UnknownTokenAddress('Token address is not known.') chain_state = views.state_from_raiden(self.raiden) channels_to_close = views.filter_channels_by_partneraddress( chain_state, registry_address, token_address, partner_addresses, ) token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_raiden(self.raiden), registry_address, token_address, ) # If concurrent operations are happening on one of the channels, fail entire # request. with ExitStack() as stack: # Put all the locks in this outer context so that the netting channel functions # don't release the locks when their context goes out of scope for channel_state in channels_to_close: channel = self.raiden.chain.payment_channel( token_network_identifier, channel_state.identifier, ) stack.enter_context(channel.lock_or_raise()) for channel_state in channels_to_close: channel_close = ActionChannelClose( token_network_identifier, channel_state.identifier, ) self.raiden.handle_state_change(channel_close) channel_ids = [channel_state.identifier for channel_state in channels_to_close] waiting.wait_for_close( self.raiden, registry_address, token_address, channel_ids, retry_timeout, )
def start(self): """ Start the node. """ if self.stop_event and self.stop_event.is_set(): self.stop_event.clear() if self.database_dir is not None: self.db_lock.acquire(timeout=0) assert self.db_lock.is_locked # The database may be :memory: storage = sqlite.SQLiteStorage(self.database_path, serialize.PickleSerializer()) self.wal, unapplied_events = wal.restore_from_latest_snapshot( node.state_transition, storage, ) last_log_block_number = None # First run, initialize the basic state if self.wal.state_manager.current_state is None: block_number = self.chain.block_number() state_change = ActionInitNode( random.Random(), block_number, ) self.wal.log_and_dispatch(state_change, block_number) else: # Get the last known block number after reapplying all the state changes from the log last_log_block_number = views.block_number( self.wal.state_manager.current_state) # The alarm task must be started after the snapshot is loaded or the # state is primed, the callbacks assume the node is initialized. self.alarm.start() self.alarm.register_callback(self.poll_blockchain_events) self.alarm.register_callback(self.set_block_number) self._block_number = self.chain.block_number() # Registry registration must start *after* the alarm task. This # avoids corner cases where the registry is queried in block A, a new # block B is mined, and the alarm starts polling at block C. # If last_log_block_number is None, the wal.state_manager.current_state was # None in the log, meaning we don't have any events we care about, so just # read the latest state from the network self.register_payment_network(self.default_registry.address, last_log_block_number) # Start the protocol after the registry is queried to avoid warning # about unknown channels. queueids_to_queues = views.get_all_messagequeues( views.state_from_raiden(self)) # TODO: remove the cyclic dependency between the protocol and this instance self.protocol.start(self, queueids_to_queues) # Health check needs the protocol layer self.start_neighbours_healthcheck() for event in unapplied_events: on_raiden_event(self, event) self.start_event.set()
def set_total_channel_deposit( self, registry_address: TokenNetworkRegistryAddress, token_address: TokenAddress, partner_address: Address, total_deposit: TokenAmount, retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ) -> None: """ Set the `total_deposit` in the channel with the peer at `partner_address` and the given `token_address` in order to be able to do transfers. Raises: InvalidBinaryAddress: If either token_address or partner_address is not 20 bytes long. RaidenRecoverableError: May happen for multiple reasons: - If the token approval fails, e.g. the token may validate if account has enough balance for the allowance. - The deposit failed, e.g. the allowance did not set the token aside for use and the user spent it before deposit was called. - The channel was closed/settled between the allowance call and the deposit call. AddressWithoutCode: The channel was settled during the deposit execution. DepositOverLimit: The total deposit amount is higher than the limit. UnexpectedChannelState: The channel is no longer in an open state. """ chain_state = views.state_from_raiden(self.raiden) token_addresses = views.get_token_identifiers(chain_state, registry_address) channel_state = views.get_channelstate_for( chain_state=chain_state, token_network_registry_address=registry_address, token_address=token_address, partner_address=partner_address, ) if not is_binary_address(token_address): raise InvalidBinaryAddress( "Expected binary address format for token in channel deposit") if not is_binary_address(partner_address): raise InvalidBinaryAddress( "Expected binary address format for partner in channel deposit" ) if token_address not in token_addresses: raise UnknownTokenAddress("Unknown token address") if channel_state is None: raise NonexistingChannel( "No channel with partner_address for the given token") confirmed_block_identifier = chain_state.block_hash token = self.raiden.proxy_manager.token( token_address, block_identifier=confirmed_block_identifier) token_network_registry = self.raiden.proxy_manager.token_network_registry( registry_address, block_identifier=confirmed_block_identifier) token_network_address = token_network_registry.get_token_network( token_address=token_address, block_identifier=confirmed_block_identifier) if token_network_address is None: raise UnknownTokenAddress( f"Token {to_checksum_address(token_address)} is not registered " f"with the network {to_checksum_address(registry_address)}.") token_network_proxy = self.raiden.proxy_manager.token_network( address=token_network_address, block_identifier=confirmed_block_identifier) channel_proxy = self.raiden.proxy_manager.payment_channel( channel_state=channel_state, block_identifier=confirmed_block_identifier) blockhash = chain_state.block_hash token_network_proxy = channel_proxy.token_network safety_deprecation_switch = token_network_proxy.safety_deprecation_switch( block_identifier=blockhash) balance = token.balance_of(self.raiden.address, block_identifier=blockhash) network_balance = token.balance_of( address=Address(token_network_address), block_identifier=blockhash) token_network_deposit_limit = token_network_proxy.token_network_deposit_limit( block_identifier=blockhash) addendum = total_deposit - channel_state.our_state.contract_balance channel_participant_deposit_limit = token_network_proxy.channel_participant_deposit_limit( block_identifier=blockhash) total_channel_deposit = total_deposit + channel_state.partner_state.contract_balance is_channel_open = channel.get_status( channel_state) == ChannelState.STATE_OPENED if not is_channel_open: raise UnexpectedChannelState("Channel is not in an open state.") if safety_deprecation_switch: msg = ("This token_network has been deprecated. " "All channels in this network should be closed and " "the usage of the newly deployed token network contract " "is highly encouraged.") raise TokenNetworkDeprecated(msg) if total_deposit <= channel_state.our_state.contract_balance: raise DepositMismatch("Total deposit did not increase.") # If this check succeeds it does not imply the `deposit` will # succeed, since the `deposit` transaction may race with another # transaction. if not (balance >= addendum): msg = "Not enough balance to deposit. {} Available={} Needed={}".format( to_checksum_address(token_address), balance, addendum) raise InsufficientFunds(msg) if network_balance + addendum > token_network_deposit_limit: msg = f"Deposit of {addendum} would have exceeded the token network deposit limit." raise DepositOverLimit(msg) if total_deposit > channel_participant_deposit_limit: msg = (f"Deposit of {total_deposit} is larger than the " f"channel participant deposit limit") raise DepositOverLimit(msg) if total_channel_deposit >= UINT256_MAX: raise DepositOverLimit("Deposit overflow") try: channel_proxy.approve_and_set_total_deposit( total_deposit=total_deposit, block_identifier=blockhash) except RaidenRecoverableError as e: log.info(f"Deposit failed. {str(e)}") target_address = self.raiden.address waiting.wait_for_participant_deposit( raiden=self.raiden, token_network_registry_address=registry_address, token_address=token_address, partner_address=partner_address, target_address=target_address, target_balance=total_deposit, retry_timeout=retry_timeout, )
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_address = views.get_token_network_address_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address) assert token_network_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_address( views.state_from_app(alice_app), token_network_address) assert token_network channel_state = get_channelstate(alice_app, bob_app, token_network_address) 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 = sha256_secrethash(transfer_1_secret) transfer_2_secret = factories.make_secret(1) transfer_2_secrethash = sha256_secrethash(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_address=token_network_address, amount=alice_to_bob_amount, target=target, identifier=identifier, secret=transfer_1_secret, ) transfer1_received.wait() alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address) lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash) assert lock # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state(token_network_address, 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_address) assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address) 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_address) 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_address) 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_address=token_network_address, amount=alice_to_bob_amount, target=target, identifier=identifier, 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_address) assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks