def run_test_receive_lockedtransfer_invalidnonce(raiden_network, number_of_nodes, deposit, token_addresses, reveal_timeout, network_wait): app0, app1, app2 = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address) channel0 = get_channelstate(app0, app1, token_network_identifier) amount = 10 transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=amount, identifier=1, timeout=network_wait * number_of_nodes, ) amount = 10 payment_identifier = 1 repeated_nonce = 1 expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=random.randint(0, UINT64_MAX), payment_identifier=payment_identifier, payment_hash_invoice=EMPTY_PAYMENT_HASH_INVOICE, nonce=repeated_nonce, token_network_address=token_network_identifier, token=token_address, channel_identifier=channel0.identifier, transferred_amount=amount, locked_amount=amount, recipient=app1.raiden.address, locksroot=UNIT_SECRETHASH, lock=Lock(amount=amount, expiration=expiration, secrethash=UNIT_SECRETHASH), target=app2.raiden.address, initiator=app0.raiden.address, fee=0, ) sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], )
def run_test_create_monitoring_request(raiden_network, token_addresses): app0, app1 = raiden_network 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=chain_state, payment_network_id=payment_network_id, token_address=token_address, ) payment_identifier = create_default_identifier() transfer( initiator_app=app1, target_app=app0, token_address=token_address, amount=1, identifier=payment_identifier, ) chain_state = views.state_from_raiden(app0.raiden) channel_state = views.get_channelstate_by_token_network_and_partner( chain_state, token_network_identifier, app1.raiden.address, ) balance_proof = channel_state.partner_state.balance_proof api = RaidenAPI(app0.raiden) request = api.create_monitoring_request( balance_proof=balance_proof, reward_amount=1, ) assert request as_dict = request.to_dict() from_dict = RequestMonitoring.from_dict(as_dict) assert from_dict.to_dict() == as_dict
def run_regression_payment_complete_after_refund_to_the_initiator( raiden_network, token_addresses, settle_timeout, deposit): app0, app1, app2, app3, app4 = raiden_network token = token_addresses[0] registry_address = app0.raiden.default_registry.address # Topology: # # 0 -> 1 -> 2 # v ^ # 3 ------> 4 app_channels = [(app0, app1), (app1, app2), (app0, app3), (app3, app4), (app4, app2)] open_and_wait_for_channels(app_channels, registry_address, token, deposit, settle_timeout) # Use all deposit from app1->app2 to force a refund transfer(initiator_app=app1, target_app=app2, token_address=token, amount=deposit, identifier=1) # Send a refund that will refund the initiator transfer(initiator_app=app0, target_app=app2, token_address=token, amount=deposit, identifier=1) assert raiden_state_changes_search_for_item( raiden=app0, item_type=ReceiveTransferRefundCancelRoute, attributes={})
def test_api_channel_events(raiden_chain, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] amount = PaymentAmount(30) transfer( initiator_app=app0, target_app=app1, token_address=token_address, amount=amount, identifier=PaymentID(1), ) app0_events = RaidenAPI(app0.raiden).get_blockchain_events_channel( token_address, app1.raiden.address) assert must_have_event(app0_events, {"event": ChannelEvent.DEPOSIT}) app0_events = app0.raiden.wal.storage.get_events() assert any( isinstance(event, EventPaymentSentSuccess) for event in app0_events) app1_events = app1.raiden.wal.storage.get_events() assert any( isinstance(event, EventPaymentReceivedSuccess) for event in app1_events) app1_events = RaidenAPI(app1.raiden).get_blockchain_events_channel( token_address, app0.raiden.address) assert must_have_event(app1_events, {"event": ChannelEvent.DEPOSIT})
def test_regression_unfiltered_routes(raiden_network, token_addresses, settle_timeout, deposit): """ The transfer should proceed without triggering an assert. Transfers failed in networks where two or more paths to the destination are possible but they share same node as a first hop. """ app0, app1, app2, app3, app4 = raiden_network token = token_addresses[0] registry_address = app0.raiden.default_registry.address # Topology: # # 0 -> 1 -> 2 -> 4 # | ^ # +--> 3 ---+ app_channels = [(app0, app1), (app1, app2), (app1, app3), (app3, app4), (app2, app4)] open_and_wait_for_channels(app_channels, registry_address, token, deposit, settle_timeout) transfer( initiator_app=app0, target_app=app4, token_address=token, amount=PaymentAmount(1), identifier=PaymentID(1), )
def test_create_monitoring_request(raiden_network, token_addresses): 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=chain_state, token_network_registry_address=token_network_registry_address, token_address=token_address, ) assert token_network_address payment_identifier = create_default_identifier() transfer( initiator_app=app1, target_app=app0, token_address=token_address, amount=PaymentAmount(1), identifier=payment_identifier, ) chain_state = views.state_from_raiden(app0.raiden) channel_state = views.get_channelstate_by_token_network_and_partner( chain_state, token_network_address, app1.raiden.address) assert channel_state balance_proof = cast(BalanceProofSignedState, channel_state.partner_state.balance_proof) api = RaidenAPI(app0.raiden) request = api.create_monitoring_request(balance_proof=balance_proof, reward_amount=TokenAmount(1)) assert request as_dict = DictSerializer.serialize(request) from_dict = DictSerializer.deserialize(as_dict) assert DictSerializer.serialize(from_dict) == as_dict
def run_test_regression_transport_global_queues_are_initialized_on_restart_for_services( raiden_network, number_of_nodes, token_addresses, network_wait, user_deposit_address): app0, app1 = raiden_network app0.config["services"]["monitoring_enabled"] = True # Send a transfer to make sure the state has a balance proof # to publish to the global matrix rooms token_address = token_addresses[0] amount = 10 transfer( initiator_app=app1, target_app=app0, token_address=token_address, amount=amount, identifier=1, timeout=network_wait * number_of_nodes, ) app0.stop() transport = MatrixTransport(app0.config["transport"]["matrix"]) transport.send_async = Mock() transport._send_raw = Mock() old_start_transport = transport.start # Check that the queue is populated before the transport sends it and empties the queue def start_transport(*args, **kwargs): # Before restart the transport's global message queue should be initialized # There should be 2 messages in the global queue. # 1 for the PFS and the other for MS assert len(transport._global_send_queue) == 2 # No other messages were sent at this point transport.send_async.assert_not_called() transport._send_raw.assert_not_called() old_start_transport(*args, **kwargs) transport.start = start_transport raiden_event_handler = RaidenEventHandler() message_handler = MessageHandler() app0_restart = App( config=app0.config, chain=app0.raiden.chain, query_start_block=0, default_registry=app0.raiden.default_registry, default_one_to_n_address=app0.raiden.default_one_to_n_address, default_secret_registry=app0.raiden.default_secret_registry, default_service_registry=app0.raiden.default_service_registry, transport=transport, raiden_event_handler=raiden_event_handler, message_handler=message_handler, discovery=app0.raiden.discovery, user_deposit=app0.raiden.chain.user_deposit(user_deposit_address), ) app0_restart.start()
def run_test_mediated_transfer_with_entire_deposit( raiden_network, number_of_nodes, token_addresses, deposit, network_wait, ): app0, app1, app2 = raiden_network 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, ) transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=deposit, identifier=1, timeout=network_wait * number_of_nodes, ) transfer( initiator_app=app2, target_app=app0, token_address=token_address, amount=deposit * 2, identifier=2, timeout=network_wait * number_of_nodes, ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit * 2, [], app1, 0, [], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit * 2, [], app2, 0, [], )
def run_test_node_can_settle_if_partner_does_not_call_update_transfer( raiden_network, number_of_nodes, token_addresses, network_wait, ): app0, app1 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address registry_address = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=chain_state, payment_network_id=payment_network_id, token_address=token_address, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier transfer( initiator_app=app0, target_app=app1, token_address=token_address, amount=1, identifier=1, timeout=network_wait * number_of_nodes, ) # stop app1 - the test uses token_network_contract now app1.stop() RaidenAPI(app0.raiden).channel_close( registry_address=registry_address, token_address=token_address, partner_address=app1.raiden.address, ) # app1 won't update the channel waiting.wait_for_settle( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert search_for_item( state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, }, )
def test_cancel_transfer(raiden_chain, token, deposit): app0, app1, app2, app3 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking messages = setup_messages_cb() mlogger = MessageLogger() assert_synched_channels(channel(app0, app1, token), deposit, [], channel(app1, app0, token), deposit, []) assert_synched_channels(channel(app1, app2, token), deposit, [], channel(app2, app1, token), deposit, []) assert_synched_channels(channel(app2, app3, token), deposit, [], channel(app3, app2, token), deposit, []) assert_synched_channels(channel(app0, app1, token), deposit, [], channel(app1, app0, token), deposit, []) # drain the channel app1 -> app2 amount12 = 50 direct_transfer(app1, app2, token, amount12, identifier=1) # drain the channel app2 -> app3 amount23 = 80 direct_transfer(app2, app3, token, amount23, identifier=2) assert_synched_channels(channel(app1, app2, token), deposit - amount12, [], channel(app2, app1, token), deposit + amount12, []) assert_synched_channels(channel(app2, app3, token), deposit - amount23, [], channel(app3, app2, token), deposit + amount23, []) # app1 -> app3 is the only available path but app2 -> app3 doesnt have # resources and needs to send a RefundTransfer down the path transfer(app0, app3, token, amount=50, identifier=1) assert_synched_channels(channel(app0, app1, token), deposit, [], channel(app1, app0, token), deposit, []) assert_synched_channels(channel(app1, app2, token), deposit - amount12, [], channel(app2, app1, token), deposit + amount12, []) assert_synched_channels(channel(app2, app3, token), deposit - amount23, [], channel(app3, app2, token), deposit + amount23, []) assert len(unique(messages)) == 12 # DT + DT + SMT + MT + RT + RT + ACKs app1_messages = mlogger.get_node_messages(pex(app1.raiden.address), only='sent') assert isinstance(app1_messages[-1], RefundTransfer) app2_messages = mlogger.get_node_messages(pex(app2.raiden.address), only='sent') assert isinstance(app2_messages[-1], RefundTransfer)
def test_cancel_transfer(): deposit = 100 asset = sha3('test_cancel_transfer')[:20] # pylint: disable=unbalanced-tuple-unpacking app0, app1, app2 = create_sequential_network(num_nodes=3, deposit=deposit, asset=asset) messages = setup_messages_cb() mlogger = MessageLogger() assert_synched_channels( channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, [] ) assert_synched_channels( channel(app1, app2, asset), deposit, [], channel(app2, app1, asset), deposit, [] ) # drain the channel app1 -> app2 amount = 80 direct_transfer(app1, app2, asset, amount) assert_synched_channels( channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, [] ) assert_synched_channels( channel(app1, app2, asset), deposit - amount, [], channel(app2, app1, asset), deposit + amount, [] ) # app1 -> app2 is the only available path and doens't have resource, app1 # needs to send CancelTransfer to app0 transfer(app0, app2, asset, 50) assert_synched_channels( channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, [] ) assert_synched_channels( channel(app1, app2, asset), deposit - amount, [], channel(app2, app1, asset), deposit + amount, [] ) assert len(messages) == 6 # DirectTransfer + MediatedTransfer + CancelTransfer + a Ack for each app1_messages = mlogger.get_node_messages(pex(app1.raiden.address), only='sent') assert isinstance(app1_messages[-1], CancelTransfer)
def test_handle_insufficient_eth(raiden_network, token_addresses, caplog): app0, app1 = raiden_network token = token_addresses[0] registry_address = app0.raiden.default_registry.address channel_state = views.get_channelstate_for( chain_state=views.state_from_raiden(app0.raiden), token_network_registry_address=registry_address, token_address=token, partner_address=app1.raiden.address, ) assert isinstance(channel_state, NettingChannelState) channel_identifier = channel_state.identifier transfer( initiator_app=app0, target_app=app1, amount=PaymentAmount(1), token_address=token, identifier=PaymentID(1), timeout=60, ) app1.raiden.stop() burn_eth(app1.raiden.rpc_client) app1.raiden.start() settle_block_timeout = BlockTimeout( exception_to_throw=RuntimeError("Settle did not happen."), raiden=app0.raiden, block_number=app0.raiden.get_block_number() + channel_state.settle_timeout * 2, retry_timeout=DEFAULT_RETRY_TIMEOUT, ) with settle_block_timeout: RaidenAPI(app0.raiden).channel_close( registry_address=registry_address, token_address=token, partner_address=app1.raiden.address, ) waiting.wait_for_settle( raiden=app0.raiden, token_network_registry_address=registry_address, token_address=token, channel_ids=[channel_identifier], retry_timeout=DEFAULT_RETRY_TIMEOUT, ) assert any( "subtask died" in message and "insufficient ETH" in message for message in caplog.messages )
def test_regression_payment_complete_after_refund_to_the_initiator( raiden_network: List[RaidenService], token_addresses, settle_timeout, deposit): """Regression test for issue #3915""" app0, app1, app2, app3, app4 = raiden_network token = token_addresses[0] registry_address = app0.default_registry.address # Topology: # # 0 -> 1 -> 2 # | ^ # v | # 3 ------> 4 app_channels = [(app0, app1), (app1, app2), (app0, app3), (app3, app4), (app4, app2)] open_and_wait_for_channels(app_channels, registry_address, token, deposit, settle_timeout) # Use all deposit from app1->app2 to force a refund transfer( initiator_app=app1, target_app=app2, token_address=token, amount=deposit, identifier=PaymentID(1), routes=[[app1.address, app2.address]], ) # Send a transfer that will result in a refund app1->app0 transfer( initiator_app=app0, target_app=app2, token_address=token, amount=PaymentAmount(50), identifier=PaymentID(2), timeout=20, expect_unlock_failures=True, routes=[ [app0.address, app1.address, app2.address], [app0.address, app3.address, app4.address, app2.address], ], ) assert raiden_state_changes_search_for_item( raiden=app0, item_type=ReceiveTransferCancelRoute, attributes={}) assert raiden_events_search_for_item(raiden=app0, item_type=EventRouteFailed, attributes={})
def test_receive_lockedtransfer_invalidnonce(raiden_network, number_of_nodes, deposit, token_addresses, reveal_timeout, network_wait): app0, app1, app2 = raiden_network 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 channel0 = get_channelstate(app0, app1, token_network_address) amount = 10 payment_identifier = PaymentID(1) secrethash = transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=PaymentAmount(10), identifier=payment_identifier, timeout=network_wait * number_of_nodes, ) repeated_nonce = Nonce(1) expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=repeated_nonce, token_network_address=token_network_address, token=token_address, channel_identifier=channel0.identifier, transferred_amount=TokenAmount(amount), locked_amount=TokenAmount(amount), recipient=app1.raiden.address, locksroot=make_locksroot(), lock=Lock(amount=PaymentWithFeeAmount(amount), expiration=expiration, secrethash=UNIT_SECRETHASH), target=app2.raiden.address, initiator=app0.raiden.address, signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[ RouteMetadata(route=[app1.raiden.address, app2.raiden.address]) ]), ) sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1) with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash): wait_assert( assert_synced_channel_state, token_network_address, app0, deposit - amount, [], app1, deposit + amount, [], )
def test_handle_insufficient_eth( raiden_network: List[RaidenService], restart_node, token_addresses, caplog ): app0, app1 = raiden_network token = token_addresses[0] registry_address = app0.default_registry.address channel_state = views.get_channelstate_for( chain_state=views.state_from_raiden(app0), token_network_registry_address=registry_address, token_address=token, partner_address=app1.address, ) assert isinstance(channel_state, NettingChannelState) channel_identifier = channel_state.identifier with block_offset_timeout(app0): transfer( initiator_app=app0, target_app=app1, token_address=token, amount=PaymentAmount(1), identifier=PaymentID(1), ) app1.stop() burn_eth(app1.rpc_client) restart_node(app1) block_offset = BlockOffset(channel_state.settle_timeout * 2) with block_offset_timeout(app0, "Settle did not happen", block_offset): RaidenAPI(app0).channel_close( registry_address=registry_address, token_address=token, partner_address=app1.address, ) waiting.wait_for_settle( raiden=app0, token_network_registry_address=registry_address, token_address=token, channel_ids=[channel_identifier], retry_timeout=DEFAULT_RETRY_TIMEOUT, ) assert any( "subtask died" in message and "insufficient ETH" in message for message in caplog.messages )
def run_test_mediated_transfer_events( raiden_network, number_of_nodes, token_addresses, network_wait, ): app0, app1, app2 = raiden_network token_address = token_addresses[0] amount = 10 transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=amount, identifier=1, timeout=network_wait * number_of_nodes, ) def test_initiator_events(): initiator_events = app0.raiden.wal.storage.get_events() return ( search_for_item(initiator_events, SendSecretReveal, {}) and search_for_item(initiator_events, EventUnlockSuccess, {}) ) assert wait_until(test_initiator_events, network_wait) def test_mediator_events(): mediator_events = app1.raiden.wal.storage.get_events() return ( search_for_item(mediator_events, EventUnlockSuccess, {}) and search_for_item(mediator_events, EventUnlockClaimSuccess, {}) ) assert wait_until(test_mediator_events, network_wait) def test_target_events(): target_events = app2.raiden.wal.storage.get_events() return ( search_for_item(target_events, SendSecretRequest, {}) and search_for_item(target_events, SendSecretReveal, {}) and search_for_item(target_events, EventUnlockClaimSuccess, {}) ) assert wait_until(test_target_events, network_wait)
def test_mediated_transfer_events(raiden_network, number_of_nodes, token_addresses, network_wait): app0, app1, app2 = raiden_network token_address = token_addresses[0] amount = 10 transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=PaymentAmount(amount), identifier=PaymentID(1), timeout=network_wait * number_of_nodes, routes=[[app0.address, app1.address, app2.address]], ) def test_initiator_events(): assert not has_unlock_failure(app0) initiator_events = app0.wal.storage.get_events() secret_reveal = search_for_item(initiator_events, SendSecretReveal, {}) unlock_success = search_for_item(initiator_events, EventUnlockSuccess, {}) return secret_reveal and unlock_success assert wait_until(test_initiator_events, network_wait) def test_mediator_events(): assert not has_unlock_failure(app1) mediator_events = app1.wal.storage.get_events() unlock_success = search_for_item(mediator_events, EventUnlockSuccess, {}) unlock_claim_success = search_for_item(mediator_events, EventUnlockClaimSuccess, {}) return unlock_success and unlock_claim_success assert wait_until(test_mediator_events, network_wait) def test_target_events(): assert not has_unlock_failure(app2) target_events = app2.wal.storage.get_events() return (search_for_item(target_events, SendSecretRequest, {}) and search_for_item(target_events, SendSecretReveal, {}) and search_for_item(target_events, EventUnlockClaimSuccess, {})) assert wait_until(test_target_events, network_wait)
def run_test_regression_unfiltered_routes(raiden_network, token_addresses, settle_timeout, deposit): app0, app1, app2, app3, app4 = raiden_network token = token_addresses[0] registry_address = app0.raiden.default_registry.address # Topology: # # 0 -> 1 -> 2 -> 4 # | ^ # +--> 3 ---+ app_channels = [(app0, app1), (app1, app2), (app1, app3), (app3, app4), (app2, app4)] open_and_wait_for_channels(app_channels, registry_address, token, deposit, settle_timeout) transfer(initiator_app=app0, target_app=app4, token_address=token, amount=1, identifier=1)
def test_settled_lock(): """ After a lock has it's secret revealed and a transfer happened, the lock cannot be used to net any value with the contract. """ deposit = 100 asset = sha3('test_settled_lock')[:20] amount = 30 # pylint: disable=unbalanced-tuple-unpacking apps = create_sequential_network(num_nodes=4, deposit=deposit, asset=asset) # mediated transfer with the secret revealed transfer(apps[0], apps[3], asset, amount) # create the latest transfer direct_transfer(apps[0], apps[1], asset, amount) secret = '' # need to get the secret attack_channel = channel(apps[2], apps[1], asset) secret_transfer = get_received_transfer(attack_channel, 0) last_transfer = get_received_transfer(attack_channel, 1) nettingcontract_address = attack_channel.nettingcontract_address # create a fake proof merkle_proof = attack_channel.our_state.locked.get_proof(secret_transfer) # call close giving the secret for a transfer that has being revealed apps[1].raiden.chain.close( asset, nettingcontract_address, apps[1].raiden.address, [last_transfer], [(merkle_proof, secret_transfer.lock, secret)], ) # forward the block number to allow settle for _ in range(NettingChannelContract.settle_timeout): apps[2].raiden.chain.next_block() apps[1].raiden.chain.settle(asset, nettingcontract_address)
def test_cancel_transfer(raiden_chain, asset, deposit): app0, app1, app2 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking messages = setup_messages_cb() mlogger = MessageLogger() assert_synched_channels(channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, []) assert_synched_channels(channel(app1, app2, asset), deposit, [], channel(app2, app1, asset), deposit, []) # drain the channel app1 -> app2 amount = 80 direct_transfer(app1, app2, asset, amount) assert_synched_channels(channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, []) assert_synched_channels(channel(app1, app2, asset), deposit - amount, [], channel(app2, app1, asset), deposit + amount, []) # app1 -> app2 is the only available path and doens't have resource, app1 # needs to send RefundTransfer to app0 transfer(app0, app2, asset, 50) assert_synched_channels(channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, []) assert_synched_channels(channel(app1, app2, asset), deposit - amount, [], channel(app2, app1, asset), deposit + amount, []) assert len( messages ) == 6 # DirectTransfer + MediatedTransfer + RefundTransfer + a Ack for each app1_messages = mlogger.get_node_messages(pex(app1.raiden.address), only='sent') assert isinstance(app1_messages[-1], RefundTransfer)
def test_settled_lock(): """ After a lock has it's secret revealed and a transfer happened, the lock cannot be used to net any value with the contract. """ deposit = 100 asset = sha3('test_settled_lock')[:20] amount = 30 # pylint: disable=unbalanced-tuple-unpacking apps = create_sequential_network(num_nodes=4, deposit=deposit, asset=asset) # mediated transfer with the secret revealed transfer(apps[0], apps[3], asset, amount) # create the latest transfer direct_transfer(apps[0], apps[1], asset, amount) secret = '' # need to get the secret attack_channel = channel(apps[2], apps[1], asset) secret_transfer = get_received_transfer(attack_channel, 0) last_transfer = get_received_transfer(attack_channel, 1) nettingcontract_address = attack_channel.nettingcontract_address # create a fake proof merkle_proof = attack_channel.our_state.locked.get_proof(secret_transfer) # call close giving the secret for a transfer that has being revealed apps[1].raiden.chain.close( asset, nettingcontract_address, apps[1].raiden.address, [last_transfer], [(merkle_proof, secret_transfer.lock, secret)], ) # forward the block number to allow settle for _ in range(NettingChannelContract.locked_time): apps[2].raiden.chain.next_block() apps[1].raiden.chain.settle(asset, nettingcontract_address)
def test_pfs_send_capacity_updates_during_mediated_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait): 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) # Mock send_text on the PFS room transport0 = app0.raiden.transport pfs_room_name = make_room_alias(transport0.chain_id, PATH_FINDING_BROADCASTING_ROOM) pfs_room = transport0._broadcast_rooms.get(pfs_room_name) # need to assert for mypy that pfs_room is not None assert isinstance(pfs_room, Room) pfs_room.send_text = MagicMock(spec=pfs_room.send_text) amount = PaymentAmount(10) secrethash = transfer( initiator_app=app0, target_app=app1, token_address=token_address, amount=amount, identifier=PaymentID(1), timeout=network_wait * number_of_nodes, ) with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash): wait_assert( assert_succeeding_transfer_invariants, token_network_address, app0, deposit - amount, [], app1, deposit + amount, [], ) # We expect one PFSCapacityUpdate when locking and one when unlocking assert pfs_room.send_text.call_count == 2 assert "PFSCapacityUpdate" in str(pfs_room.send_text.call_args_list[0])
def test_mediated_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait ): 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 ) amount = PaymentAmount(10) secrethash = transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=amount, identifier=PaymentID(1), timeout=network_wait * number_of_nodes, ) with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash): wait_assert( assert_succeeding_transfer_invariants, token_network_address, app0, deposit - amount, [], app1, deposit + amount, [], ) with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash): wait_assert( assert_succeeding_transfer_invariants, token_network_address, app1, deposit - amount, [], app2, deposit + amount, [], )
def run_test_node_can_settle_if_close_didnt_use_any_balance_proof( raiden_network, number_of_nodes, token_addresses, network_wait, ): app0, app1 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address registry_address = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=chain_state, payment_network_id=payment_network_id, token_address=token_address, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier # make a transfer from app0 to app1 so that app1 is supposed to have a non # empty balance hash transfer( initiator_app=app0, target_app=app1, token_address=token_address, amount=1, identifier=1, timeout=network_wait * number_of_nodes, ) # stop app1 - the test uses token_network_contract now app1.stop() token_network_contract = TokenNetwork( jsonrpc_client=app1.raiden.chain.client, token_network_address=token_network_identifier, contract_manager=app1.raiden.contract_manager, ) # app1 closes the channel with an empty hash instead of the expected hash # of the transferred amount from app0 token_network_contract.close( channel_identifier=channel_identifier, partner=app0.raiden.address, balance_hash=EMPTY_HASH, nonce=0, additional_hash=EMPTY_HASH, signature=EMPTY_SIGNATURE, given_block_identifier='latest', ) waiting.wait_for_settle( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert search_for_item( state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, }, )
def test_cancel_transfer(raiden_chain, token_addresses, deposit): """ 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 # pylint: disable=unbalanced-tuple-unpacking token = token_addresses[0] assert_synched_channels( channel(app0, app1, token), deposit, [], channel(app1, app0, token), deposit, [] ) assert_synched_channels( channel(app1, app2, token), deposit, [], channel(app2, app1, token), deposit, [] ) # make a transfer to test the path app0 -> app1 -> app2 identifier_path = 1 amount_path = 1 transfer(app0, app2, token, amount_path, identifier_path) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = int(deposit * 0.8) direct_transfer(app1, app2, token, amount_drain, identifier_drain) # wait for the nodes to sync gevent.sleep(0.2) assert_synched_channels( channel(app0, app1, token), deposit - amount_path, [], channel(app1, app0, token), deposit + amount_path, [] ) assert_synched_channels( channel(app1, app2, token), deposit - amount_path - amount_drain, [], channel(app2, app1, token), deposit + amount_path + amount_drain, [] ) # app0 -> app1 -> app2 is the only available path but the channel app1 -> # app2 doesnt have resources and needs to send a RefundTransfer down the # path identifier_refund = 3 amount_refund = 50 async_result = app0.raiden.mediated_transfer_async( token, 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 app0_messages = app0.raiden.protocol.transport.get_sent_messages(app0.raiden.address) mediated_message = list( message for message in app0_messages if isinstance(message, MediatedTransfer) and message.target == app2.raiden.address )[-1] assert mediated_message app1_messages = app1.raiden.protocol.transport.get_sent_messages(app1.raiden.address) refund_message = next( message for message in app1_messages if isinstance(message, RefundTransfer) and message.recipient == app0.raiden.address ) assert refund_message assert mediated_message.lock.amount == refund_message.lock.amount assert mediated_message.lock.hashlock == refund_message.lock.hashlock assert mediated_message.lock.expiration > refund_message.lock.expiration # Both channels have the amount locked because of the refund message assert_synched_channels( channel(app0, app1, token), deposit - amount_path, [refund_message.lock], channel(app1, app0, token), deposit + amount_path, [mediated_message.lock], ) assert_synched_channels( channel(app1, app2, token), deposit - amount_path - amount_drain, [], channel(app2, app1, token), deposit + amount_path + amount_drain, [] )
def run_test_refund_transfer_after_2nd_hop( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, ): """Test the refund transfer sent due to failure after 2nd hop""" # Topology: # # 0 -> 1 -> 2 -> 3 # app0, app1, app2, app3 = 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 -> app3 identifier_path = 1 amount_path = 1 transfer( initiator_app=app0, target_app=app3, token_address=token_address, amount=amount_path, identifier=identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app2 -> app3 identifier_drain = 2 amount_drain = deposit * 8 // 10 transfer( initiator_app=app2, target_app=app3, 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, [], app2, deposit + amount_path, [], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app2, deposit - amount_path - amount_drain, [], app3, deposit + amount_path + amount_drain, [], ) # app0 -> app1 -> app2 > app3 is the only available path, but the channel # app2 -> app3 doesn't have capacity, so a refund will be sent on # app2 -> app1 -> app0 identifier_refund = 3 amount_refund = 50 payment_status = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app3.raiden.address, identifier_refund, ) msg = 'there is no path with capacity, the transfer must fail' assert payment_status.payment_done.wait() is False, msg gevent.sleep(0.2) # Lock structures with the correct amount send_locked1 = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': amount_refund } }}, ) assert send_locked1 send_refund1 = raiden_events_search_for_item(app1.raiden, SendRefundTransfer, {}) assert send_refund1 lock1 = send_locked1.transfer.lock refund_lock1 = send_refund1.transfer.lock assert lock1.amount == refund_lock1.amount assert lock1.secrethash == refund_lock1.secrethash send_locked2 = raiden_events_search_for_item( app1.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': amount_refund } }}, ) assert send_locked2 send_refund2 = raiden_events_search_for_item(app2.raiden, SendRefundTransfer, {}) assert send_refund2 lock2 = send_locked2.transfer.lock refund_lock2 = send_refund2.transfer.lock assert lock2.amount == refund_lock2.amount assert lock2.secrethash assert lock2.expiration # 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, [lock1], app1, deposit + amount_path, [refund_lock1], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit - amount_path, [lock2], app2, deposit + amount_path, [refund_lock2], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app2, deposit - amount_path - amount_drain, [], app3, deposit + amount_path + amount_drain, [], )
def run_test_refund_messages(raiden_chain, token_addresses, deposit, network_wait): # The network has the following topology: # # App0 <---> App1 <---> App2 app0, app1, app2 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking 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, ) # Exhaust the channel App1 <-> App2 (to force the refund transfer) exhaust_amount = deposit transfer( initiator_app=app1, target_app=app2, token_address=token_address, amount=exhaust_amount, identifier=1, ) refund_amount = deposit // 2 identifier = 1 payment_status = app0.raiden.mediated_transfer_async( token_network_identifier, refund_amount, app2.raiden.address, identifier, ) msg = 'Must fail, there are no routes available' assert payment_status.payment_done.wait() is False, msg # The transfer from app0 to app2 failed, so the balances did change. # Since the refund is not unlocked both channels have the corresponding # amount locked (issue #1091) send_lockedtransfer = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': refund_amount } }}, ) assert send_lockedtransfer send_refundtransfer = raiden_events_search_for_item( app1.raiden, SendRefundTransfer, {}) assert send_refundtransfer with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit, [send_lockedtransfer.transfer.lock], app1, deposit, [send_refundtransfer.transfer.lock], ) # This channel was exhausted to force the refund transfer with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, 0, [], app2, deposit * 2, [], )
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, ) 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_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, ) 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 test_cancel_transfer(raiden_chain, asset, deposit): app0, app1, app2, app3 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking messages = setup_messages_cb() mlogger = MessageLogger() assert_synched_channels( channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, [] ) assert_synched_channels( channel(app1, app2, asset), deposit, [], channel(app2, app1, asset), deposit, [] ) assert_synched_channels( channel(app2, app3, asset), deposit, [], channel(app3, app2, asset), deposit, [] ) assert_synched_channels( channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, [] ) # drain the channel app1 -> app2 amount12 = 50 direct_transfer(app1, app2, asset, amount12) # drain the channel app2 -> app3 amount23 = 80 direct_transfer(app2, app3, asset, amount23) assert_synched_channels( channel(app1, app2, asset), deposit - amount12, [], channel(app2, app1, asset), deposit + amount12, [] ) assert_synched_channels( channel(app2, app3, asset), deposit - amount23, [], channel(app3, app2, asset), deposit + amount23, [] ) # app1 -> app3 is the only available path but app2 -> app3 doesnt have # resources and needs to send a RefundTransfer down the path transfer(app0, app3, asset, 50) assert_synched_channels( channel(app0, app1, asset), deposit, [], channel(app1, app0, asset), deposit, [] ) assert_synched_channels( channel(app1, app2, asset), deposit - amount12, [], channel(app2, app1, asset), deposit + amount12, [] ) assert_synched_channels( channel(app2, app3, asset), deposit - amount23, [], channel(app3, app2, asset), deposit + amount23, [] ) assert len(messages) == 12 # DT + DT + SMT + MT + RT + RT + ACKs app1_messages = mlogger.get_node_messages(pex(app1.raiden.address), only='sent') assert isinstance(app1_messages[-1], RefundTransfer) app2_messages = mlogger.get_node_messages(pex(app2.raiden.address), only='sent') assert isinstance(app2_messages[-1], RefundTransfer)
def test_cancel_transfer(raiden_chain, token_addresses, deposit): """ 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 # pylint: disable=unbalanced-tuple-unpacking token = token_addresses[0] assert_synched_channels(channel(app0, app1, token), deposit, [], channel(app1, app0, token), deposit, []) assert_synched_channels(channel(app1, app2, token), deposit, [], channel(app2, app1, token), deposit, []) # make a transfer to test the path app0 -> app1 -> app2 identifier_path = 1 amount_path = 1 transfer(app0, app2, token, amount_path, identifier_path) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = int(deposit * 0.8) direct_transfer(app1, app2, token, amount_drain, identifier_drain) # wait for the nodes to sync gevent.sleep(0.2) assert_synched_channels(channel(app0, app1, token), deposit - amount_path, [], channel(app1, app0, token), deposit + amount_path, []) assert_synched_channels(channel(app1, app2, token), deposit - amount_path - amount_drain, [], channel(app2, app1, token), deposit + amount_path + amount_drain, []) # app0 -> app1 -> app2 is the only available path but the channel app1 -> # app2 doesnt have resources and needs to send a RefundTransfer down the # path identifier_refund = 3 amount_refund = 50 async_result = app0.raiden.mediated_transfer_async( token, 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 app0_messages = app0.raiden.protocol.transport.get_sent_messages( app0.raiden.address) mediated_message = list(message for message in app0_messages if isinstance(message, MediatedTransfer) and message.target == app2.raiden.address)[-1] assert mediated_message app1_messages = app1.raiden.protocol.transport.get_sent_messages( app1.raiden.address) refund_message = next(message for message in app1_messages if isinstance(message, RefundTransfer) and message.recipient == app0.raiden.address) assert refund_message assert mediated_message.lock.amount == refund_message.lock.amount assert mediated_message.lock.hashlock == refund_message.lock.hashlock assert mediated_message.lock.expiration > refund_message.lock.expiration # Both channels have the amount locked because of the refund message assert_synched_channels( channel(app0, app1, token), deposit - amount_path, [refund_message.lock], channel(app1, app0, token), deposit + amount_path, [mediated_message.lock], ) assert_synched_channels(channel(app1, app2, token), deposit - amount_path - amount_drain, [], channel(app2, app1, token), deposit + amount_path + amount_drain, [])
def test_recovery_unhappy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, # pylint: disable=unused-argument retry_timeout, ): app0, app1, app2 = raiden_network 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) # make a few transfers from app0 to app2 amount = 1 spent_amount = deposit - 2 for identifier in range(spent_amount): transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=amount, identifier=identifier, timeout=network_wait * number_of_nodes, ) app0.raiden.stop() host_port = ( app0.raiden.config["transport"]["udp"]["host"], app0.raiden.config["transport"]["udp"]["port"], ) socket = server._udp_socket(host_port) new_transport = UDPTransport( app0.raiden.address, app0.discovery, socket, app0.raiden.transport.throttle_policy, app0.raiden.config["transport"]["udp"], ) app0.stop() RaidenAPI(app1.raiden).channel_close(app1.raiden.default_registry.address, token_address, app0.raiden.address) channel01 = views.get_channelstate_for( views.state_from_app(app1), app1.raiden.default_registry.address, token_address, app0.raiden.address, ) waiting.wait_for_settle( app1.raiden, app1.raiden.default_registry.address, token_address, [channel01.identifier], retry_timeout, ) raiden_event_handler = RaidenEventHandler() message_handler = MessageHandler() app0_restart = App( config=app0.config, chain=app0.raiden.chain, query_start_block=0, default_registry=app0.raiden.default_registry, default_secret_registry=app0.raiden.default_secret_registry, default_service_registry=app0.raiden.default_service_registry, transport=new_transport, raiden_event_handler=raiden_event_handler, message_handler=message_handler, discovery=app0.raiden.discovery, ) del app0 # from here on the app0_restart should be used app0_restart.start() state_changes = app0_restart.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier="latest") assert search_for_item( state_changes, ContractReceiveChannelSettled, { "token_network_identifier": token_network_identifier, "channel_identifier": channel01.identifier, }, )
def test_recovery_happy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, # pylint: disable=unused-argument ): app0, app1, app2 = raiden_network 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) # make a few transfers from app0 to app2 amount = 1 spent_amount = deposit - 2 identifier = 0 for identifier in range(spent_amount): transfer_and_assert_path( path=raiden_network, token_address=token_address, amount=amount, identifier=identifier, timeout=network_wait * number_of_nodes, ) app0.raiden.stop() host_port = ( app0.raiden.config["transport"]["udp"]["host"], app0.raiden.config["transport"]["udp"]["port"], ) socket = server._udp_socket(host_port) new_transport = UDPTransport( app0.raiden.address, app0.discovery, socket, app0.raiden.transport.throttle_policy, app0.raiden.config["transport"]["udp"], ) raiden_event_handler = RaidenEventHandler() message_handler = WaitForMessage() app0_restart = App( config=app0.config, chain=app0.raiden.chain, query_start_block=0, default_registry=app0.raiden.default_registry, default_secret_registry=app0.raiden.default_secret_registry, default_service_registry=app0.raiden.default_service_registry, transport=new_transport, raiden_event_handler=raiden_event_handler, message_handler=message_handler, discovery=app0.raiden.discovery, ) app0.stop() del app0 # from here on the app0_restart should be used app0_restart.start() assert_synced_channel_state( token_network_identifier, app0_restart, deposit - spent_amount, [], app1, deposit + spent_amount, [], ) assert_synced_channel_state( token_network_identifier, app1, deposit - spent_amount, [], app2, deposit + spent_amount, [], ) # wait for the nodes' healthcheck to update the network statuses waiting.wait_for_healthy(app0_restart.raiden, app1.raiden.address, network_wait) waiting.wait_for_healthy(app1.raiden, app0_restart.raiden.address, network_wait) transfer( initiator_app=app2, target_app=app0_restart, token_address=token_address, amount=amount, identifier=create_default_identifier(), timeout=network_wait * number_of_nodes * 2, ) transfer( initiator_app=app0_restart, target_app=app2, token_address=token_address, amount=amount, identifier=create_default_identifier(), timeout=network_wait * number_of_nodes * 2, ) assert_synced_channel_state( token_network_identifier, app0_restart, deposit - spent_amount, [], app1, deposit + spent_amount, [], ) assert_synced_channel_state( token_network_identifier, app1, deposit - spent_amount, [], app2, deposit + spent_amount, [], )