def run_test_payment_timing_out_if_partner_does_not_respond( # pylint: disable=unused-argument raiden_network, token_addresses, reveal_timeout, skip_if_not_matrix, retry_timeout, ): app0, app1 = raiden_network token_address = token_addresses[0] def fake_receive(room, event): # pylint: disable=unused-argument return True with patch.object(app1.raiden.transport, '_handle_message', side_effect=fake_receive): greenlet = gevent.spawn( RaidenAPI(app0.raiden).transfer, app0.raiden.default_registry.address, token_address, 1, target=app1.raiden.address, ) waiting.wait_for_block( app0.raiden, app1.raiden.get_block_number() + 2 * reveal_timeout + 1, retry_timeout, ) greenlet.join(timeout=5) assert not greenlet.value
def test_register_token_insufficient_eth(raiden_network, retry_timeout, unregistered_token): app1 = raiden_network[0] registry_address = app1.raiden.default_registry.address token_address = unregistered_token # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app1.raiden, block_number=app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1, retry_timeout=retry_timeout, ) api1 = RaidenAPI(app1.raiden) assert token_address not in api1.get_tokens_list(registry_address) # app1.raiden loses all its ETH because it has been naughty burn_eth(app1.raiden.rpc_client) with pytest.raises(InsufficientEth): api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=TokenAmount(UINT256_MAX), token_network_deposit_limit=TokenAmount(UINT256_MAX), )
def test_payment_timing_out_if_partner_does_not_respond( raiden_network, token_addresses, reveal_timeout, skip_if_not_matrix, retry_timeout, ): """ Test to make sure that when our target does not respond payment times out If the target does not respond and the lock times out then the payment will timeout. Note that at the moment we don't retry other routes even if they exist when the lock expires for this transfer. Issue: https://github.com/raiden-network/raiden/issues/3094""" app0, app1 = raiden_network token_address = token_addresses[0] def fake_receive(room, event): return True with patch.object(app1.raiden.transport, '_handle_message', side_effect=fake_receive): greenlet = gevent.spawn( RaidenAPI(app0.raiden).transfer, app0.raiden.default_registry.address, token_address, 1, target=app1.raiden.address, ) waiting.wait_for_block( app0.raiden, app1.raiden.get_block_number() + 2 * reveal_timeout + 1, retry_timeout, ) greenlet.join(timeout=5) assert not greenlet.value
def test_register_token_without_balance( api_server_test_instance, token_amount, raiden_network: List[RaidenService], contract_manager, retry_timeout, ): app0 = raiden_network[0] contract_proxy, _ = app0.rpc_client.deploy_single_contract( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, contract=contract_manager.get_contract(CONTRACT_HUMAN_STANDARD_TOKEN), constructor_parameters=(token_amount, 2, "raiden", "Rd2"), ) new_token_address = Address(to_canonical_address(contract_proxy.address)) # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. wait_for_block( raiden=app0, block_number=BlockNumber(app0.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1), retry_timeout=retry_timeout, ) # Burn all the eth and then make sure we get the appropriate API error burn_eth(app0.rpc_client) poor_request = grequests.put( api_url_for( api_server_test_instance, "registertokenresource", token_address=to_checksum_address(new_token_address), )) poor_response = poor_request.send().response assert_response_with_error(poor_response, HTTPStatus.PAYMENT_REQUIRED)
def run_test_token_registered_race(raiden_chain, token_amount, retry_timeout, contract_manager): app0, app1 = raiden_chain api0 = RaidenAPI(app0.raiden) api1 = RaidenAPI(app1.raiden) # Recreate the race condition by making sure the non-registering app won't # register at all by watching for the TokenAdded blockchain event. event_listeners = app1.raiden.blockchain_events.event_listeners app1.raiden.blockchain_events.event_listeners = list() token_address = deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.chain.client, contract_manager=contract_manager, constructor_arguments=( token_amount, 2, 'raiden', 'Rd', ), ) gevent.sleep(1) registry_address = app0.raiden.default_registry.address assert token_address not in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) api0.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=UINT256_MAX, token_network_deposit_limit=UINT256_MAX, ) exception = RuntimeError('Did not see the token registration within 30 seconds') with gevent.Timeout(seconds=30, exception=exception): wait_for_state_change( app0.raiden, ContractReceiveNewTokenNetwork, { 'token_network': { 'token_address': token_address, }, }, retry_timeout, ) assert token_address in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) # The next time when the event is polled, the token is registered app1.raiden.blockchain_events.event_listeners = event_listeners waiting.wait_for_block( app1.raiden, app1.raiden.get_block_number() + 1, retry_timeout, ) assert token_address in api1.get_tokens_list(registry_address)
def test_payment_timing_out_if_partner_does_not_respond( # pylint: disable=unused-argument raiden_network, token_addresses, reveal_timeout, retry_timeout): """ Test to make sure that when our target does not respond payment times out If the target does not respond and the lock times out then the payment will timeout. Note that at the moment we don't retry other routes even if they exist when the lock expires for this transfer. Issue: https://github.com/raiden-network/raiden/issues/3094""" app0, app1 = raiden_network token_address = token_addresses[0] app1.raiden.raiden_event_handler.hold(SendSecretRequest, {}) greenlet = gevent.spawn( RaidenAPI(app0.raiden).transfer, app0.raiden.default_registry.address, token_address, 1, target=app1.raiden.address, ) waiting.wait_for_block( app0.raiden, app1.raiden.get_block_number() + 2 * reveal_timeout + 1, retry_timeout) greenlet.join(timeout=5) assert not greenlet.value
def run_test_locked_transfer_secret_registered_onchain(raiden_network, token_addresses, secret_registry_address, retry_timeout): app0 = raiden_network[0] token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address) amount = 1 target = factories.UNIT_TRANSFER_INITIATOR identifier = 1 transfer_secret = sha3(target + b"1") secret_registry_proxy = app0.raiden.chain.secret_registry( secret_registry_address) secret_registry_proxy.register_secret(secret=transfer_secret) # Wait until our node has processed the block that the secret registration was mined at block_number = app0.raiden.get_block_number() wait_for_block( raiden=app0.raiden, block_number=block_number + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, retry_timeout=retry_timeout, ) # Test that sending a transfer with a secret already registered on-chain fails with pytest.raises(RaidenUnrecoverableError): app0.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=amount, fee=0, target=target, identifier=identifier, payment_hash_invoice=EMPTY_PAYMENT_HASH_INVOICE, secret=transfer_secret, ) # Test that receiving a transfer with a secret already registered on chain fails expiration = 9999 locked_transfer = factories.create( factories.LockedTransferProperties( amount=amount, target=app0.raiden.address, expiration=expiration, secret=transfer_secret, )) message_handler = MessageHandler() message_handler.handle_message_lockedtransfer(app0.raiden, locked_transfer) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( 0, "latest") transfer_statechange_dispatched = search_for_item( state_changes, ActionInitMediator, {}) or search_for_item( state_changes, ActionInitTarget, {}) assert not transfer_statechange_dispatched
def test_locked_transfer_secret_registered_onchain( raiden_network, token_addresses, secret_registry_address, retry_timeout ): app0 = raiden_network[0] 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 ) amount = TokenAmount(1) target = factories.UNIT_TRANSFER_INITIATOR identifier = PaymentID(1) transfer_secret = make_secret() secret_registry_proxy = app0.raiden.proxy_manager.secret_registry( secret_registry_address, block_identifier=chain_state.block_hash ) secret_registry_proxy.register_secret(secret=transfer_secret) # Wait until our node has processed the block that the secret registration was mined at block_number = app0.raiden.get_block_number() wait_for_block( raiden=app0.raiden, block_number=block_number + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, retry_timeout=retry_timeout, ) # Test that sending a transfer with a secret already registered on-chain fails with pytest.raises(RaidenUnrecoverableError): app0.raiden.start_mediated_transfer_with_secret( token_network_address=token_network_address, amount=amount, target=target, identifier=identifier, secret=transfer_secret, ) # Test that receiving a transfer with a secret already registered on chain fails expiration = BlockExpiration(9999) locked_transfer = factories.create( factories.LockedTransferProperties( amount=amount, target=app0.raiden.address, expiration=expiration, secret=transfer_secret, ) ) message_handler = MessageHandler() message_handler.handle_message_lockedtransfer(app0.raiden, locked_transfer) state_changes = app0.raiden.wal.storage.get_statechanges_by_range(RANGE_ALL_STATE_CHANGES) transfer_statechange_dispatched = search_for_item( state_changes, ActionInitMediator, {} ) or search_for_item(state_changes, ActionInitTarget, {}) assert not transfer_statechange_dispatched
def token_network_register( self, registry_address: PaymentNetworkID, token_address: TokenAddress, channel_participant_deposit_limit: TokenAmount, token_network_deposit_limit: TokenAmount, retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ) -> TokenNetworkAddress: """Register the `token_address` in the blockchain. If the address is already registered but the event has not been processed this function will block until the next block to make sure the event is processed. Raises: InvalidAddress: If the registry_address or token_address is not a valid address. AlreadyRegisteredTokenAddress: If the token is already registered. TransactionThrew: If the register transaction failed, this may happen because the account has not enough balance to pay for the gas or this register call raced with another transaction and lost. """ 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 in self.get_tokens_list(registry_address): raise AlreadyRegisteredTokenAddress("Token already registered") contracts_version = self.raiden.contract_manager.contracts_version registry = self.raiden.chain.token_network_registry(registry_address) try: if contracts_version == DEVELOPMENT_CONTRACT_VERSION: return registry.add_token_with_limits( token_address=token_address, channel_participant_deposit_limit=channel_participant_deposit_limit, token_network_deposit_limit=token_network_deposit_limit, ) else: return registry.add_token_without_limits(token_address=token_address) except RaidenRecoverableError as e: if "Token already registered" in str(e): raise AlreadyRegisteredTokenAddress("Token already registered") # else raise finally: # Assume the transaction failed because the token is already # registered with the smart contract and this node has not yet # polled for the event (otherwise the check above would have # failed). # # To provide a consistent view to the user, wait one block, this # will guarantee that the events have been processed. next_block = self.raiden.get_block_number() + 1 waiting.wait_for_block(self.raiden, next_block, retry_timeout)
def _timeout_task( # pragma: no unittest throw: Callable, exception_to_throw: Exception, raiden: RaidenService, block_number: BlockNumber, retry_timeout: float, ) -> None: wait_for_block(raiden, block_number, retry_timeout) throw(exception_to_throw)
def _timeout_task( throw: Callable, exception_to_throw: Exception, raiden: RaidenService, block_number: BlockNumber, retry_timeout: float, ): wait_for_block(raiden, block_number, retry_timeout) throw(exception_to_throw)
def test_get_token_network_for_token( api_server_test_instance, token_amount, token_addresses, raiden_network: List[RaidenService], contract_manager, retry_timeout, unregistered_token, ): app0 = raiden_network[0] new_token_address = unregistered_token # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. wait_for_block( raiden=app0, block_number=BlockNumber(app0.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1), retry_timeout=retry_timeout, ) # unregistered token returns 404 token_request = grequests.get( api_url_for( api_server_test_instance, "registertokenresource", token_address=to_checksum_address(new_token_address), )) token_response = token_request.send().response assert_proper_response(token_response, status_code=HTTPStatus.NOT_FOUND) # register token register_request = grequests.put( api_url_for( api_server_test_instance, "registertokenresource", token_address=to_checksum_address(new_token_address), )) register_response = register_request.send().response assert_proper_response(register_response, status_code=HTTPStatus.CREATED) token_network_address = get_json_response( register_response)["token_network_address"] wait_for_token_network(app0, app0.default_registry.address, new_token_address, 0.1) # now it should return the token address token_request = grequests.get( api_url_for( api_server_test_instance, "registertokenresource", token_address=to_checksum_address(new_token_address), )) token_response = token_request.send().response assert_proper_response(token_response, status_code=HTTPStatus.OK) assert token_network_address == get_json_response(token_response)
def test_token_registered_race(raiden_chain, token_amount, retry_timeout, contract_manager): """If a token is registered it must appear on the token list. If two nodes register the same token one of the transactions will fail. The node that receives an error for "already registered token" must see the token in the token list. Issue: #784 """ app0, app1 = raiden_chain api0 = RaidenAPI(app0.raiden) api1 = RaidenAPI(app1.raiden) # Recreate the race condition by making sure the non-registering app won't # register at all by watching for the TokenAdded blockchain event. event_listeners = app1.raiden.blockchain_events.event_listeners app1.raiden.blockchain_events.event_listeners = list() token_address = deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.chain.client, contract_manager=contract_manager, num_confirmations=None, constructor_arguments=( token_amount, 2, 'raiden', 'Rd', ), ) gevent.sleep(1) registry_address = app0.raiden.default_registry.address assert token_address not in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) api0.token_network_register(registry_address, token_address) gevent.sleep(1) assert token_address in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) # The next time when the event is polled, the token is registered app1.raiden.blockchain_events.event_listeners = event_listeners waiting.wait_for_block( app1.raiden, app1.raiden.get_block_number() + 1, retry_timeout, ) assert token_address in api1.get_tokens_list(registry_address)
def token_network_register( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, retry_timeout: typing.NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ) -> typing.TokenNetworkAddress: """Register the `token_address` in the blockchain. If the address is already registered but the event has not been processed this function will block until the next block to make sure the event is processed. Raises: InvalidAddress: If the registry_address or token_address is not a valid address. AlreadyRegisteredTokenAddress: If the token is already registered. TransactionThrew: If the register transaction failed, this may happen because the account has not enough balance to pay for the gas or this register call raced with another transaction and lost. """ 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 in self.get_tokens_list(registry_address): raise AlreadyRegisteredTokenAddress('Token already registered') try: registry = self.raiden.chain.token_network_registry( registry_address) return registry.add_token( token_address=token_address, given_block_identifier=views.state_from_raiden( self.raiden).block_hash, ) except RaidenRecoverableError as e: if 'Token already registered' in str(e): raise AlreadyRegisteredTokenAddress('Token already registered') # else raise finally: # Assume the transaction failed because the token is already # registered with the smart contract and this node has not yet # polled for the event (otherwise the check above would have # failed). # # To provide a consistent view to the user, wait one block, this # will guarantee that the events have been processed. next_block = self.raiden.get_block_number() + 1 waiting.wait_for_block(self.raiden, next_block, retry_timeout)
def token_network_register( self, registry_address, token_address, poll_timeout=DEFAULT_POLL_TIMEOUT, retry_timeout=DEFAULT_RETRY_TIMEOUT, ) -> typing.TokenNetworkAddress: """Register the `token_address` in the blockchain. If the address is already registered but the event has not been processed this function will block until the next block to make sure the event is processed. Raises: InvalidAddress: If the registry_address or token_address is not a valid address. AlreadyRegisteredTokenAddress: If the token is already registered. TransactionThrew: If the register transaction failed, this may happen because the account has not enough balance to pay for the gas or this register call raced with another transaction and lost. """ 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 in self.get_tokens_list(registry_address): raise AlreadyRegisteredTokenAddress('Token already registered') try: registry = self.raiden.chain.token_network_registry( registry_address) msg = 'After {} seconds the channel was not properly created.'.format( poll_timeout, ) with gevent.Timeout(poll_timeout, EthNodeCommunicationError(msg)): return registry.add_token(token_address) finally: # Assume the transaction failed because the token is already # registered with the smart contract and this node has not yet # polled for the event (otherwise the check above would have # failed). # # To provide a consistent view to the user, wait one block, this # will guarantee that the events have been processed. next_block = self.raiden.get_block_number() + 1 waiting.wait_for_block(self.raiden, next_block, retry_timeout)
def test_register_token(raiden_network, token_amount, contract_manager, retry_timeout): app1 = raiden_network[0] registry_address = app1.raiden.default_registry.address token_address = deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.rpc_client, contract_manager=contract_manager, constructor_arguments=(token_amount, 2, "raiden", "Rd"), ) # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app1.raiden, block_number=app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1, retry_timeout=retry_timeout, ) api1 = RaidenAPI(app1.raiden) assert token_address not in api1.get_tokens_list(registry_address) api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=UINT256_MAX, token_network_deposit_limit=UINT256_MAX, ) exception = RuntimeError("Did not see the token registration within 30 seconds") with gevent.Timeout(seconds=30, exception=exception): wait_for_state_change( app1.raiden, ContractReceiveNewTokenNetwork, {"token_network": {"token_address": token_address}}, retry_timeout, ) assert token_address in api1.get_tokens_list(registry_address) # Exception if we try to reregister with pytest.raises(AlreadyRegisteredTokenAddress): api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=UINT256_MAX, token_network_deposit_limit=UINT256_MAX, )
def token_network_register( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, retry_timeout: typing.NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ) -> typing.TokenNetworkAddress: """Register the `token_address` in the blockchain. If the address is already registered but the event has not been processed this function will block until the next block to make sure the event is processed. Raises: InvalidAddress: If the registry_address or token_address is not a valid address. AlreadyRegisteredTokenAddress: If the token is already registered. TransactionThrew: If the register transaction failed, this may happen because the account has not enough balance to pay for the gas or this register call raced with another transaction and lost. """ 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 in self.get_tokens_list(registry_address): raise AlreadyRegisteredTokenAddress('Token already registered') try: registry = self.raiden.chain.token_network_registry(registry_address) return registry.add_token(token_address) except RaidenRecoverableError as e: if 'Token already registered' in str(e): raise AlreadyRegisteredTokenAddress('Token already registered') # else raise finally: # Assume the transaction failed because the token is already # registered with the smart contract and this node has not yet # polled for the event (otherwise the check above would have # failed). # # To provide a consistent view to the user, wait one block, this # will guarantee that the events have been processed. next_block = self.raiden.get_block_number() + 1 waiting.wait_for_block(self.raiden, next_block, retry_timeout)
def token_network_register( self, registry_address, token_address, poll_timeout=DEFAULT_POLL_TIMEOUT, retry_timeout=DEFAULT_RETRY_TIMEOUT, ) -> typing.TokenNetworkAddress: """Register the `token_address` in the blockchain. If the address is already registered but the event has not been processed this function will block until the next block to make sure the event is processed. Raises: InvalidAddress: If the registry_address or token_address is not a valid address. AlreadyRegisteredTokenAddress: If the token is already registered. TransactionThrew: If the register transaction failed, this may happen because the account has not enough balance to pay for the gas or this register call raced with another transaction and lost. """ 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 in self.get_tokens_list(registry_address): raise AlreadyRegisteredTokenAddress('Token already registered') try: registry = self.raiden.chain.token_network_registry(registry_address) msg = 'After {} seconds the channel was not properly created.'.format( poll_timeout, ) with gevent.Timeout(poll_timeout, EthNodeCommunicationError(msg)): return registry.add_token(token_address) finally: # Assume the transaction failed because the token is already # registered with the smart contract and this node has not yet # polled for the event (otherwise the check above would have # failed). # # To provide a consistent view to the user, wait one block, this # will guarantee that the events have been processed. next_block = self.raiden.get_block_number() + 1 waiting.wait_for_block(self.raiden, next_block, retry_timeout)
def test_register_token(raiden_network: List[RaidenService], retry_timeout, unregistered_token): app1 = raiden_network[0] registry_address = app1.default_registry.address token_address = unregistered_token # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app1, block_number=BlockNumber(app1.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1), retry_timeout=retry_timeout, ) api1 = RaidenAPI(app1) assert token_address not in api1.get_tokens_list(registry_address) api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=TokenAmount(UINT256_MAX), token_network_deposit_limit=TokenAmount(UINT256_MAX), ) exception = RuntimeError( "Did not see the token registration within 30 seconds") with gevent.Timeout(seconds=30, exception=exception): wait_for_state_change( app1, ContractReceiveNewTokenNetwork, {"token_network": { "token_address": token_address }}, retry_timeout, ) assert token_address in api1.get_tokens_list(registry_address) # Exception if we try to reregister with pytest.raises(AlreadyRegisteredTokenAddress): api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=TokenAmount(UINT256_MAX), token_network_deposit_limit=TokenAmount(UINT256_MAX), )
def test_token_registered_race(raiden_chain, token_amount, events_poll_timeout): """If a token is registered it must appear on the token list. If two nodes register the same token one of the transactions will fail. The node that receives an error for "already registered token" must see the token in the token list. Issue: #784 """ app0, app1 = raiden_chain api0 = RaidenAPI(app0.raiden) api1 = RaidenAPI(app1.raiden) # Recreate the race condition by making sure the non-registering app won't # register at all by watching for the TokenAdded blockchain event. event_listeners = app1.raiden.blockchain_events.event_listeners app1.raiden.blockchain_events.event_listeners = list() token_address = app1.raiden.chain.deploy_contract( contract_name='HumanStandardToken', contract_path=get_contract_path('HumanStandardToken.sol'), constructor_parameters=(token_amount, 'raiden', 2, 'Rd'), ) gevent.sleep(1) registry_address = app0.raiden.default_registry.address assert token_address not in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) api0.token_network_register(registry_address, token_address) gevent.sleep(1) assert token_address in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) # The next time when the event is polled, the token is registered app1.raiden.blockchain_events.event_listeners = event_listeners waiting.wait_for_block( app1.raiden, app1.raiden.get_block_number() + 1, events_poll_timeout, ) assert token_address in api1.get_tokens_list(registry_address)
def test_register_token_insufficient_eth( raiden_network, token_amount, contract_manager, retry_timeout ): app1 = raiden_network[0] registry_address = app1.raiden.default_registry.address token_address = deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.rpc_client, contract_manager=contract_manager, constructor_arguments=(token_amount, 2, "raiden", "Rd"), ) # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app1.raiden, block_number=app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1, retry_timeout=retry_timeout, ) api1 = RaidenAPI(app1.raiden) assert token_address not in api1.get_tokens_list(registry_address) # app1.raiden loses all its ETH because it has been naughty burn_eth(app1.raiden.rpc_client) # At this point we should get an UnrecoverableError due to InsufficientFunds with pytest.raises(InsufficientFunds): api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=UINT256_MAX, token_network_deposit_limit=UINT256_MAX, )
def test_transfer_after_connect_works(raiden_network, token_addresses): """ Test that payments work after joining a channel. This makes sure that the connection manager does not leave any partners in a half-healthchecked state that causes problems during payments. Test for https://github.com/raiden-network/raiden/issues/5918 """ registry_address = raiden_network[0].raiden.default_registry.address token_address = token_addresses[0] app0, app1, app2 = raiden_network api0 = RaidenAPI(app0.raiden) api1 = RaidenAPI(app1.raiden) # Open channel between node0 and node2 to not run into the bootstrapping # case when joining the token network api0.channel_open(registry_address, token_address, app2.raiden.address) # Make sure that app1 processed the block where channel open # happened. Otherwise the test becomes flaky because it does not see # potential participants in the network current_block = app0.raiden.get_block_number() wait_for_block(app1.raiden, current_block, 1) api1.token_network_connect( registry_address=registry_address, token_address=token_address, funds=TokenAmount(100), initial_channel_target=2, ) payment_result = api1.transfer_and_wait( registry_address=registry_address, token_address=token_address, amount=PaymentAmount(1), target=app0.raiden.address, ).payment_done.get() assert isinstance(payment_result, EventPaymentSentSuccess)
def test_refund_transfer( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout, # UDP does not seem to retry messages until processed # https://github.com/raiden-network/raiden/issues/3185 skip_if_not_matrix, ): """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 mediated_transfer( app0, app2, token_network_identifier, amount_path, identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) 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 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, ) assert async_result.wait( ) is False, 'there is no path with capacity, the transfer must fail' 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 assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) 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 test_lock_expiry(raiden_network, token_addresses, secret_registry_address, deposit): """Test lock expiry and removal.""" alice_app, bob_app = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) channel_identifier = channel_state.identifier assert channel_identifier in token_network.partneraddresses_to_channels[ bob_app.raiden.address] alice_to_bob_amount = 10 identifier = 1 transfer_1_secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) transfer_1_secrethash = sha3(transfer_1_secret) alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # Verify lock is registered in both channel states alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task # Wait for the expiration to trigger with some additional buffer # time for processing (+2) blocks. waiting.wait_for_block( alice_app.raiden, lock.expiration + (DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK + 2), DEFAULT_RETRY_TIMEOUT, ) alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks # Verify Bob received the message and processed the LockExpired message bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task # Make another transfer alice_to_bob_amount = 10 identifier = 2 transfer_2_secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) transfer_2_secrethash = sha3(transfer_2_secret) # Make sure the other transfer still exists alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks
def test_deposit_amount_must_be_smaller_than_the_token_network_limit( raiden_network: List[App], contract_manager: ContractManager, retry_timeout: float) -> None: """The Python API must properly check the requested deposit will not exceed the token network deposit limit. This is a regression test for #3135. As of version `v0.18.1` (commit 786347b23), the proxy was not properly checking that the requested deposit amount was smaller than the smart contract deposit limit. This led to two errors: - The error message was vague and incorrect: "Deposit amount decreased" - The exception used was not handled and crashed the node. This test checks the limit is properly check from the REST API. """ app1 = raiden_network[0] registry_address = app1.raiden.default_registry.address token_supply = 1_000_000 token_address = TokenAddress( deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.rpc_client, contract_manager=contract_manager, constructor_arguments=(token_supply, 2, "raiden", "Rd"), )) # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app1.raiden, block_number=BlockNumber(app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1), retry_timeout=retry_timeout, ) api1 = RaidenAPI(app1.raiden) msg = "Token is not registered yet, it must not be in the token list." assert token_address not in api1.get_tokens_list(registry_address), msg token_network_deposit_limit = TokenAmount(100) api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=token_network_deposit_limit, token_network_deposit_limit=token_network_deposit_limit, ) exception = RuntimeError( "Did not see the token registration within 30 seconds") with gevent.Timeout(seconds=30, exception=exception): wait_for_state_change( app1.raiden, ContractReceiveNewTokenNetwork, {"token_network": { "token_address": token_address }}, retry_timeout, ) msg = "Token has been registered, yet must be available in the token list." assert token_address in api1.get_tokens_list(registry_address), msg partner_address = make_address() api1.channel_open( registry_address=app1.raiden.default_registry.address, token_address=token_address, partner_address=partner_address, ) with pytest.raises(DepositOverLimit): api1.set_total_channel_deposit( registry_address=app1.raiden.default_registry.address, token_address=token_address, partner_address=partner_address, total_deposit=TokenAmount(token_network_deposit_limit + 1), ) pytest.fail( "The deposit must fail if the requested deposit exceeds the token " "network deposit limit.")
def test_participant_deposit_amount_must_be_smaller_than_the_limit( raiden_network: List[App], contract_manager: ContractManager, retry_timeout: float) -> None: """The Python API must properly check the requested participant deposit will not exceed the smart contract limit. This is companion test for `test_deposit_amount_must_be_smaller_than_the_token_network_limit`. The participant deposit limit was introduced for the bug bounty with the PR https://github.com/raiden-network/raiden-contracts/pull/276/ , the limit is available since version 0.4.0 of the smart contract. """ app1 = raiden_network[0] registry_address = app1.raiden.default_registry.address token_supply = 1_000_000 token_address = TokenAddress( deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.rpc_client, contract_manager=contract_manager, constructor_arguments=(token_supply, 2, "raiden", "Rd"), )) api1 = RaidenAPI(app1.raiden) msg = "Token is not registered yet, it must not be in the token list." assert token_address not in api1.get_tokens_list(registry_address), msg # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app1.raiden, block_number=BlockNumber(app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1), retry_timeout=retry_timeout, ) token_network_participant_deposit_limit = TokenAmount(100) api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit= token_network_participant_deposit_limit, token_network_deposit_limit=TokenAmount(UINT256_MAX), ) exception = RuntimeError( "Did not see the token registration within 30 seconds") with gevent.Timeout(seconds=30, exception=exception): wait_for_state_change( app1.raiden, ContractReceiveNewTokenNetwork, {"token_network": { "token_address": token_address }}, retry_timeout, ) msg = "Token has been registered, yet must be available in the token list." assert token_address in api1.get_tokens_list(registry_address), msg partner_address = make_address() api1.channel_open( registry_address=app1.raiden.default_registry.address, token_address=token_address, partner_address=partner_address, ) with pytest.raises(DepositOverLimit): api1.set_total_channel_deposit( registry_address=app1.raiden.default_registry.address, token_address=token_address, partner_address=partner_address, total_deposit=TokenAmount(token_network_participant_deposit_limit + 1), ) pytest.fail( "The deposit must fail if the requested deposit exceeds the participant deposit limit." )
def test_token_registered_race(raiden_chain, token_amount, retry_timeout, contract_manager): """If a token is registered it must appear on the token list. If two nodes register the same token one of the transactions will fail. The node that receives an error for "already registered token" must see the token in the token list. Issue: #784 """ app0, app1 = raiden_chain api0 = RaidenAPI(app0.raiden) api1 = RaidenAPI(app1.raiden) # Recreate the race condition by making sure the non-registering app won't # register at all by watching for the TokenAdded blockchain event. event_listeners = app1.raiden.blockchain_events.event_listeners app1.raiden.blockchain_events.event_listeners = list() token_address = deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.chain.client, contract_manager=contract_manager, constructor_arguments=( token_amount, 2, 'raiden', 'Rd', ), ) gevent.sleep(1) registry_address = app0.raiden.default_registry.address assert token_address not in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) api0.token_network_register(registry_address, token_address) exception = RuntimeError('Did not see the token registration within 30 seconds') with gevent.Timeout(seconds=30, exception=exception): wait_for_state_change( app0.raiden, ContractReceiveNewTokenNetwork, { 'token_network': { 'token_address': token_address, }, }, retry_timeout, ) assert token_address in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) # The next time when the event is polled, the token is registered app1.raiden.blockchain_events.event_listeners = event_listeners waiting.wait_for_block( app1.raiden, app1.raiden.get_block_number() + 1, retry_timeout, ) assert token_address in api1.get_tokens_list(registry_address)
def test_different_view_of_last_bp_during_unlock( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout, # UDP does not seem to retry messages until processed # https://github.com/raiden-network/raiden/issues/3185 skip_if_not_matrix, ): """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 mediated_transfer( app0, app2, token_network_identifier, amount_path, identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) 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 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, ) assert async_result.wait() is False, 'there is no path with capacity, the transfer must fail' gevent.sleep(0.2) # A lock structure with the correct amount send_locked = raiden_events_must_contain_entry( app0.raiden, SendLockedTransfer, {'transfer': {'lock': {'amount': amount_refund}}}, ) assert send_locked secrethash = send_locked.transfer.lock.secrethash send_refund = raiden_events_must_contain_entry(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 assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) 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, ) with gevent.Timeout(10): unlock_app0 = wait_for_state_change( app0.raiden, ContractReceiveChannelBatchUnlock, {'participant': app0.raiden.address}, retry_timeout, ) assert unlock_app0.returned_tokens == 50 with gevent.Timeout(10): 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 test_refund_transfer( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout, # UDP does not seem to retry messages until processed # https://github.com/raiden-network/raiden/issues/3185 skip_if_not_matrix, ): """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 mediated_transfer( app0, app2, token_network_identifier, amount_path, identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) 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 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, ) assert async_result.wait() is False, 'there is no path with capacity, the transfer must fail' gevent.sleep(0.2) # A lock structure with the correct amount send_locked = raiden_events_must_contain_entry( app0.raiden, SendLockedTransfer, {'transfer': {'lock': {'amount': amount_refund}}}, ) assert send_locked secrethash = send_locked.transfer.lock.secrethash send_refund = raiden_events_must_contain_entry(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 assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) 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_must_contain_entry( 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 must_contain_entry( 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 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] token_network_registry_address = app0.raiden.default_registry.address token_network_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), token_network_registry_address, token_address) token_proxy = app0.raiden.proxy_manager.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_address, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_address, 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 amount_refund_with_fees = amount_refund + calculate_fee_for_amount(50) payment_status = app0.raiden.mediated_transfer_async( token_network_address, amount_refund, app2.raiden.address, identifier_refund) msg = "there is no path with capacity, the transfer must fail" assert isinstance(payment_status.payment_done.wait(), EventPaymentSentFailed), msg # A lock structure with the correct amount send_locked = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {"transfer": { "lock": { "amount": amount_refund_with_fees } }}, ) 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_address, app0, deposit - amount_path, [lock], app1, deposit + amount_path, [refund_lock], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_address, 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.expiration) + 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=token_network_registry_address, token_address=token_address, partner_address=app1.raiden.address, ) count = 0 on_raiden_event_original = app1.raiden.raiden_event_handler.on_raiden_event def patched_on_raiden_event(raiden, chain_state, event): if type(event) == ContractSendChannelUpdateTransfer: nonlocal count count += 1 on_raiden_event_original(raiden, chain_state, event) app1.raiden.raiden_event_handler.on_raiden_event = patched_on_raiden_event # 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_address).identifier # and we wait for settlement wait_for_settle( raiden=app0.raiden, token_network_registry_address=token_network_registry_address, 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, {"receiver": app0.raiden.address}, retry_timeout, ) assert unlock_app0.returned_tokens == amount_refund_with_fees with gevent.Timeout(timeout): unlock_app1 = wait_for_state_change( app1.raiden, ContractReceiveChannelBatchUnlock, {"receiver": app1.raiden.address}, retry_timeout, ) assert unlock_app1.returned_tokens == amount_refund_with_fees 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, append_report: Callable, args: Dict[str, Any], contract_addresses: List[Address], token: ContractProxy, debug: bool, ethereum_nodes: List[HTTPExecutor], ): print_step('Starting Raiden') config = deepcopy(App.DEFAULT_CONFIG) extra_config = args.pop('extra_config', None) if extra_config: merge_dict(config, extra_config) args['config'] = config # Should use basic routing in the smoke test for now # TODO: If we ever utilize a PFS in the smoke test we # need to use the deployed service registry, register the # PFS service there and then change this argument. args['routing_mode'] = RoutingMode.BASIC raiden_stdout = StringIO() maybe_redirect_stdout = contextlib.redirect_stdout(raiden_stdout) if debug: maybe_redirect_stdout = contextlib.nullcontext() with maybe_redirect_stdout: success = False app = None try: app = run_app(**args) raiden_api = RaidenAPI(app.raiden) rest_api = RestAPI(raiden_api) (api_host, api_port) = split_endpoint(args['api_address']) api_server = APIServer(rest_api, config={ 'host': api_host, 'port': api_port }) api_server.start() block = 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=contract_addresses[ CONTRACT_TOKEN_NETWORK_REGISTRY], token_address=to_canonical_address(token.contract.address), partner_address=to_canonical_address(TEST_PARTNER_ADDRESS), ) raiden_api.set_total_channel_deposit( contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY], to_canonical_address(token.contract.address), to_canonical_address(TEST_PARTNER_ADDRESS), TEST_DEPOSIT_AMOUNT, ) token_addresses = [to_checksum_address(token.contract.address)] print_step('Running smoketest') error = smoketest_perform_tests( app.raiden, args['transport'], token_addresses, contract_addresses[CONTRACT_ENDPOINT_REGISTRY], ) if error is not None: append_report('Smoketest assertion error', error) else: success = True except: # noqa pylint: disable=bare-except if debug: import pdb # The pylint comment is required when pdbpp is installed pdb.post_mortem() # pylint: disable=no-member else: error = traceback.format_exc() append_report('Smoketest execution error', error) finally: if app is not None: app.stop() app.raiden.get() node_executor = ethereum_nodes[0] node = node_executor.process node.send_signal(signal.SIGINT) try: node.wait(10) except TimeoutExpired: print_step('Ethereum node shutdown unclean, check log!', error=True) node.kill() if isinstance(node_executor.stdio, tuple): logfile = node_executor.stdio[1] logfile.flush() logfile.seek(0) append_report('Ethereum Node log output', logfile.read()) append_report('Raiden Node stdout', raiden_stdout.getvalue()) if success: print_step(f'Smoketest successful') else: print_step(f'Smoketest had errors', error=True) return success
def _run_smoketest(): print_step('Starting Raiden') config = deepcopy(App.DEFAULT_CONFIG) if args.get('extra_config', dict()): merge_dict(config, args['extra_config']) del args['extra_config'] args['config'] = config raiden_stdout = StringIO() with contextlib.redirect_stdout(raiden_stdout): app = run_app(**args) try: raiden_api = RaidenAPI(app.raiden) rest_api = RestAPI(raiden_api) (api_host, api_port) = split_endpoint(args['api_address']) api_server = APIServer(rest_api, config={ 'host': api_host, 'port': api_port }) api_server.start() block = 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=contract_addresses[ CONTRACT_TOKEN_NETWORK_REGISTRY], token_address=to_canonical_address(token.contract.address), partner_address=to_canonical_address(TEST_PARTNER_ADDRESS), ) raiden_api.set_total_channel_deposit( contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY], to_canonical_address(token.contract.address), to_canonical_address(TEST_PARTNER_ADDRESS), TEST_DEPOSIT_AMOUNT, ) token_addresses = [to_checksum_address(token.contract.address)] success = False print_step('Running smoketest') error = run_smoketests( app.raiden, args['transport'], token_addresses, contract_addresses[CONTRACT_ENDPOINT_REGISTRY], debug=debug, orig_stdout=stdout, ) if error is not None: append_report('Smoketest assertion error', error) else: success = True finally: app.stop() app.raiden.get() node = ethereum[0] node.send_signal(2) err, out = node.communicate() append_report('Ethereum stdout', out) append_report('Ethereum stderr', err) append_report('Raiden Node stdout', raiden_stdout.getvalue()) if success: print_step(f'Smoketest successful') else: print_step(f'Smoketest had errors', error=True) return success
def test_different_view_of_last_bp_during_unlock( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout, # UDP does not seem to retry messages until processed # https://github.com/raiden-network/raiden/issues/3185 skip_if_not_matrix, ): """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 mediated_transfer( app0, app2, token_network_identifier, amount_path, identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) 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 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, ) assert async_result.wait( ) is False, 'there is no path with capacity, the transfer must fail' 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 assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) 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, ) with gevent.Timeout(10): unlock_app0 = wait_for_state_change( app0.raiden, ContractReceiveChannelBatchUnlock, {'participant': app0.raiden.address}, retry_timeout, ) assert unlock_app0.returned_tokens == 50 with gevent.Timeout(10): 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 test_token_registered_race(raiden_chain, retry_timeout, unregistered_token): """If a token is registered it must appear on the token list. If two nodes register the same token one of the transactions will fail. The node that receives an error for "already registered token" must see the token in the token list. Issue: #784 """ app0, app1 = raiden_chain token_address = unregistered_token api0 = RaidenAPI(app0.raiden) api1 = RaidenAPI(app1.raiden) # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app0.raiden, block_number=app0.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1, retry_timeout=retry_timeout, ) waiting.wait_for_block( raiden=app1.raiden, block_number=app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1, retry_timeout=retry_timeout, ) registry_address = app0.raiden.default_registry.address assert token_address not in api0.get_tokens_list(registry_address) assert token_address not in api1.get_tokens_list(registry_address) greenlets: set = { gevent.spawn( api0.token_network_register, registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=TokenAmount(UINT256_MAX), token_network_deposit_limit=TokenAmount(UINT256_MAX), ), gevent.spawn( api0.token_network_register, registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=TokenAmount(UINT256_MAX), token_network_deposit_limit=TokenAmount(UINT256_MAX), ), } # One of the nodes will lose the race with pytest.raises(RaidenRecoverableError): gevent.joinall(greenlets, raise_error=True) exception = RuntimeError( "Did not see the token registration within 30 seconds") with gevent.Timeout(seconds=30, exception=exception): wait_for_state_change( app0.raiden, ContractReceiveNewTokenNetwork, {"token_network": { "token_address": token_address }}, retry_timeout, ) wait_for_state_change( app1.raiden, ContractReceiveNewTokenNetwork, {"token_network": { "token_address": token_address }}, retry_timeout, ) assert token_address in api0.get_tokens_list(registry_address) assert token_address in api1.get_tokens_list(registry_address) for api in (api0, api1): with pytest.raises(AlreadyRegisteredTokenAddress): api.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=TokenAmount(UINT256_MAX), token_network_deposit_limit=TokenAmount(UINT256_MAX), )
def test_channel_withdraw_expired( raiden_network, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout ): """ Tests withdraw expiration. """ 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 # Prevent withdraw confirmation from being sent send_withdraw_confirmation_event = alice_app.raiden.raiden_event_handler.hold( SendWithdrawConfirmation, {} ) alice_to_bob_amount = 10 total_withdraw = deposit + alice_to_bob_amount wait_for_withdraw_expired_message = alice_app.raiden.message_handler.wait_for_message( WithdrawExpired, {"total_withdraw": total_withdraw} ) identifier = 1 target = bob_app.raiden.address secret = sha3(target) payment_status = alice_app.raiden.start_mediated_transfer_with_secret( token_network_address=token_network_address, amount=alice_to_bob_amount, target=target, identifier=identifier, secret=secret, ) wait_for_unlock = bob_app.raiden.message_handler.wait_for_message( Unlock, {"payment_identifier": identifier} ) timeout = network_wait * number_of_nodes with Timeout(seconds=timeout): wait_for_unlock.get() msg = ( f"transfer from {to_checksum_address(alice_app.raiden.address)} " f"to {to_checksum_address(bob_app.raiden.address)} failed." ) assert payment_status.payment_done.get(), msg bob_alice_channel_state = get_channelstate(bob_app, alice_app, token_network_address) bob_app.raiden.withdraw( canonical_identifier=bob_alice_channel_state.canonical_identifier, total_withdraw=total_withdraw, ) with Timeout(seconds=timeout): send_withdraw_confirmation_event.wait() # Make sure proper withdraw state is set in both channel states bob_alice_channel_state = get_channelstate(bob_app, alice_app, token_network_address) assert bob_alice_channel_state.our_total_withdraw == total_withdraw assert bob_alice_channel_state.our_state.withdraws_pending.get(total_withdraw) is not None alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address) assert alice_bob_channel_state.partner_total_withdraw == total_withdraw assert alice_bob_channel_state.partner_state.withdraws_pending.get(total_withdraw) is not None withdraw_expiration = bob_alice_channel_state.our_state.withdraws_pending[ total_withdraw ].expiration expiration_threshold = channel.get_sender_expiration_threshold(withdraw_expiration) waiting.wait_for_block( raiden=bob_app.raiden, block_number=BlockNumber(expiration_threshold + 1), retry_timeout=retry_timeout, ) bob_alice_channel_state = get_channelstate(bob_app, alice_app, token_network_address) assert bob_alice_channel_state.our_total_withdraw == 0 assert bob_alice_channel_state.our_state.withdraws_pending.get(total_withdraw) is None with Timeout(seconds=timeout): wait_for_withdraw_expired_message.wait() alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address) assert alice_bob_channel_state.partner_total_withdraw == 0 assert alice_bob_channel_state.partner_state.withdraws_pending.get(total_withdraw) is None