def test_fullnetwork(raiden_chain): app0, app1, app2 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking asset_address = app0.raiden.chain.default_registry.asset_addresses()[0] amount = 80 random.seed(0) direct_transfer(app0, app1, asset_address, amount) # Assert default identifier is generated correctly fchannel = channel(app0, app1, asset_address) last_transfer = get_sent_transfer(fchannel, 0) random.seed(0) assert_identifier_correct(app0, asset_address, app1.raiden.address, last_transfer.identifier) amount = 50 direct_transfer(app1, app2, asset_address, amount) amount = 30 random.seed(0) mediated_transfer( app1, app2, asset_address, amount ) # Assert default identifier is generated correctly fchannel = channel(app1, app2, asset_address) last_transfer = get_sent_transfer(fchannel, 1) random.seed(0) assert_identifier_correct(app1, asset_address, app2.raiden.address, last_transfer.identifier)
def test_mediated_transfer_events(raiden_network, number_of_nodes, token_addresses, 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, ) amount = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) def test_initiator_events(): initiator_blockevents = app0.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) initiator_events = [blocknumber_event[1] for blocknumber_event in initiator_blockevents] return ( must_contain_entry(initiator_events, SendRevealSecret, {}) and must_contain_entry(initiator_events, EventUnlockSuccess, {}) ) assert wait_until(test_initiator_events, network_wait) def test_mediator_events(): mediator_blockevents = app1.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) mediator_events = [blocknumber_event[1] for blocknumber_event in mediator_blockevents] return ( must_contain_entry(mediator_events, EventUnlockSuccess, {}) and must_contain_entry(mediator_events, EventUnlockClaimSuccess, {}) ) assert wait_until(test_mediator_events, network_wait) def test_target_events(): target_blockevents = app2.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) target_events = [blocknumber_event[1] for blocknumber_event in target_blockevents] return ( must_contain_entry(target_events, SendSecretRequest, {}) and must_contain_entry(target_events, SendRevealSecret, {}) and must_contain_entry(target_events, EventUnlockClaimSuccess, {}) ) assert wait_until(test_target_events, network_wait)
def test_refund_messages(raiden_chain, token_addresses, deposit): # 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 mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=exhaust_amount, identifier=1, ) refund_amount = deposit // 2 identifier = 1 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, refund_amount, app2.raiden.address, identifier, ) assert async_result.wait() is False, 'Must fail, there are no routes available' # 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_must_contain_entry( app0.raiden, SendLockedTransfer, {'transfer': {'lock': {'amount': refund_amount}}}, ) assert send_lockedtransfer send_refundtransfer = raiden_events_must_contain_entry(app1.raiden, SendRefundTransfer, {}) assert send_refundtransfer 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 assert_synced_channel_state( token_network_identifier, app1, 0, [], app2, deposit * 2, [], )
def test_fullnetwork(deployed_network): app0, app1, app2 = deployed_network # pylint: disable=unbalanced-tuple-unpacking asset_address = app0.raiden.chain.default_registry.asset_addresses()[0] amount = 80 direct_transfer(app0, app1, asset_address, amount) amount = 50 direct_transfer(app1, app2, asset_address, amount) amount = 30 mediated_transfer(app1, app2, asset_address, amount)
def test_mediated_transfer_with_entire_deposit( raiden_network, number_of_nodes, token_addresses, deposit, network_wait, public_and_private_rooms, ): 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, ) mediated_transfer( app0, app2, token_network_identifier, deposit, timeout=network_wait * number_of_nodes, ) mediated_transfer( app2, app0, token_network_identifier, deposit * 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 test_mediated_transfer_messages_out_of_order( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_matrix, ): app0, app1, app2 = raiden_network _patch_transport(app1.raiden.transport) _patch_transport(app2.raiden.transport) 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 = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit - amount, [], app2, deposit + amount, [], )
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) 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 = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) wait_assert( token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], func=assert_synched_channel_state, timeout=network_wait, ) wait_assert( token_network_identifier, app1, deposit - amount, [], app2, deposit + amount, [], func=assert_synched_channel_state, timeout=network_wait, )
def test_api_channel_events(raiden_chain, token_addresses): app0, app1 = raiden_chain 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, ) amount = 30 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=amount, identifier=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() any(isinstance(event, EventPaymentSentSuccess) for event in app0_events) app1_events = app1.raiden.wal.storage.get_events() 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_node_can_settle_if_partner_does_not_call_update_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, chain_id, ): """ A node must be able to settle a channel, even if the partner did not call update transfer. This test will: - Make a transfer from app0 to app1, to make sure there are balance proofs available - Stop app1, to make sure update is not called. - Use app0 to close the channel. - Assert that app0 can settle the closed channel, even though app1 didn't use the latest balance proof """ 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=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, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) # 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_refund_messages(raiden_chain, token_addresses, deposit): # 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 mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, 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 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 assert_synced_channel_state( token_network_identifier, app1, 0, [], app2, deposit * 2, [], )
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_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 mediated_transfer( app0, app2, token_network_identifier, amount, 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, 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, expiration, UNIT_SECRETHASH), target=app2.raiden.address, initiator=app0.raiden.address, fee=0, ) sign_and_inject( mediated_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) wait_assert( token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], func=assert_synched_channel_state, timeout=network_wait, )
def test_recovery_unhappy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, 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 _ in range(spent_amount): mediated_transfer( app0, app2, token_network_identifier, amount, 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, 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel01.identifier, })
def test_automatic_dispute(raiden_network, deposit, token_addresses): app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) token_proxy = app0.raiden.chain.token(channel0.token_address) initial_balance0 = token_proxy.balance_of(app0.raiden.address) initial_balance1 = token_proxy.balance_of(app1.raiden.address) amount0_1 = 10 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=amount0_1, ) amount1_1 = 50 mediated_transfer( initiator_app=app1, target_app=app0, token_network_identifier=token_network_identifier, amount=amount1_1, ) amount0_2 = 60 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=amount0_2, ) # Alice can only provide one of Bob's transfer, so she is incentivized to # use the one with the largest transferred_amount. RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) # Bob needs to provide a transfer otherwise its netted balance will be # wrong, so he is incentivised to use Alice's transfer with the largest # transferred_amount. # # This is done automatically # channel1.external_state.update_transfer( # alice_second_transfer, # ) waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel0.identifier], app0.raiden.alarm.sleep_time, ) # check that the channel is properly settled and that Bob's client # automatically called updateTransfer() to reflect the actual transactions assert token_proxy.balance_of(token_network_identifier) == 0 total0 = amount0_1 + amount0_2 total1 = amount1_1 expected_balance0 = initial_balance0 + deposit - total0 + total1 expected_balance1 = initial_balance1 + deposit + total0 - total1 assert token_proxy.balance_of(app0.raiden.address) == expected_balance0 assert token_proxy.balance_of(app1.raiden.address) == expected_balance1
def test_fullnetwork( raiden_chain, token_addresses, deposit, settle_timeout, reveal_timeout): # pylint: disable=too-many-locals,too-many-statements # The network has the following topology: # # App0 <---> App1 # ^ ^ # | | # v v # App3 <---> App2 token_address = token_addresses[0] app0, app1, app2, app3 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking channel_0_1 = channel(app0, app1, token_address) channel_3_2 = channel(app3, app2, token_address) channel_0_3 = channel(app0, app3, token_address) # Exhaust the channel deposit (to force the mediated transfer to go backwards) amount = deposit direct_transfer(app0, app1, token_address, amount, identifier=1) assert get_sent_transfer(channel_0_1, 0).transferred_amount == amount amount = int(deposit / 2.) mediated_transfer( app0, app2, token_address, amount ) gevent.sleep(0.5) # This is the only possible path, the transfer must go backwards assert_path_mediated_transfer( get_sent_transfer(channel_0_3, 0), get_sent_transfer(channel_3_2, 0), ) app0_state_changes = [ change[1] for change in get_all_state_changes(app0.raiden.transaction_log) ] app0_events = [ event.event_object for event in get_all_state_events(app0.raiden.transaction_log) ] secret = None for event in app0_events: if isinstance(event, SendRevealSecret): secret = event.secret assert secret is not None hashlock = sha3(secret) # app0 initiates the direct transfer and mediated_transfer assert must_contain_entry(app0_state_changes, ActionInitInitiator, { 'our_address': app0.raiden.address, 'transfer': { 'amount': amount, 'token': token_address, 'initiator': app0.raiden.address, 'target': app2.raiden.address, 'expiration': None, 'hashlock': None, 'secret': None, } }) # Of these 2 the state machine will in the future choose the one with the most # available balance not_taken_route = RouteState( state='opened', node_address=app1.raiden.address, channel_address=channel_0_1.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) taken_route = RouteState( state='opened', node_address=app3.raiden.address, channel_address=channel_0_3.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) for state_change in app0_state_changes: if isinstance(state_change, ActionInitMediator): assert taken_route in state_change.routes.available_routes assert not_taken_route not in state_change.routes.available_routes # app1 received one direct transfers app1_state_changes = [ change[1] for change in get_all_state_changes(app1.raiden.transaction_log) ] assert must_contain_entry(app1_state_changes, ReceiveBalanceProof, {}) assert must_contain_entry(app1_state_changes, ReceiveTransferDirect, {}) app2_state_changes = [ change[1] for change in get_all_state_changes(app2.raiden.transaction_log) ] assert must_contain_entry(app2_state_changes, ActionInitTarget, { 'our_address': app2.raiden.address, 'from_route': { 'state': 'opened', 'node_address': app3.raiden.address, 'channel_address': channel_3_2.channel_address, 'available_balance': deposit, 'settle_timeout': settle_timeout, 'reveal_timeout': reveal_timeout, 'closed_block': None }, 'from_transfer': { 'amount': amount, 'hashlock': hashlock, 'token': token_address, 'initiator': app0.raiden.address, 'target': app2.raiden.address, } }) assert must_contain_entry(app2_state_changes, ReceiveSecretReveal, { 'sender': app0.raiden.address, 'secret': secret, }) assert must_contain_entry(app2_state_changes, ReceiveSecretReveal, { 'sender': app3.raiden.address, 'secret': secret, }) app2_events = [ event.event_object for event in get_all_state_events(app2.raiden.transaction_log) ] assert must_contain_entry(app2_events, SendSecretRequest, { 'amount': amount, 'hashlock': hashlock, 'receiver': app0.raiden.address, }) assert must_contain_entry(app2_events, SendRevealSecret, { 'token': token_address, 'secret': secret, 'receiver': app3.raiden.address, 'sender': app2.raiden.address, }) assert must_contain_entry(app0_state_changes, ReceiveSecretRequest, { 'amount': amount, 'sender': app2.raiden.address, 'hashlock': hashlock, }) assert must_contain_entry(app0_state_changes, ReceiveSecretReveal, { 'sender': app3.raiden.address, 'secret': secret, }) assert must_contain_entry(app0_events, EventTransferSentSuccess, {}) assert must_contain_entry(app0_events, SendMediatedTransfer, { 'token': token_address, 'amount': amount, 'hashlock': hashlock, 'initiator': app0.raiden.address, 'target': app2.raiden.address, 'receiver': app3.raiden.address, }) assert must_contain_entry(app0_events, SendRevealSecret, { 'secret': secret, 'token': token_address, 'receiver': app2.raiden.address, 'sender': app0.raiden.address, }) assert must_contain_entry(app0_events, SendBalanceProof, { 'token': token_address, 'channel_address': channel_0_3.channel_address, 'receiver': app3.raiden.address, 'secret': secret, }) assert must_contain_entry(app0_events, EventTransferSentSuccess, {}) assert must_contain_entry(app0_events, EventUnlockSuccess, { 'hashlock': hashlock, }) app3_state_changes = [ change[1] for change in get_all_state_changes(app3.raiden.transaction_log) ] assert must_contain_entry(app3_state_changes, ActionInitMediator, { 'our_address': app3.raiden.address, 'from_route': { 'state': 'opened', 'node_address': app0.raiden.address, 'channel_address': channel_0_3.channel_address, 'available_balance': deposit, 'settle_timeout': settle_timeout, 'reveal_timeout': reveal_timeout, 'closed_block': None, }, 'from_transfer': { 'amount': amount, 'hashlock': hashlock, 'token': token_address, 'initiator': app0.raiden.address, 'target': app2.raiden.address, } }) assert must_contain_entry(app3_state_changes, ReceiveSecretReveal, { 'sender': app2.raiden.address, 'secret': secret, }) assert must_contain_entry(app3_state_changes, ReceiveSecretReveal, { 'sender': app2.raiden.address, 'secret': secret, }) app3_events = [ event.event_object for event in get_all_state_events(app3.raiden.transaction_log) ] assert must_contain_entry(app3_events, SendMediatedTransfer, { 'token': token_address, 'amount': amount, 'hashlock': hashlock, 'initiator': app0.raiden.address, 'target': app2.raiden.address, 'receiver': app2.raiden.address, }) assert must_contain_entry(app3_events, SendRevealSecret, { 'secret': secret, 'token': token_address, 'receiver': app0.raiden.address, 'sender': app3.raiden.address, }) assert must_contain_entry(app3_events, SendBalanceProof, { 'token': token_address, 'channel_address': channel_3_2.channel_address, 'receiver': app2.raiden.address, 'secret': secret, }) assert must_contain_entry(app3_events, EventUnlockSuccess, {})
def test_node_can_settle_if_close_didnt_use_any_balance_proof( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, ): """ A node must be able to settle a channel, even if the partner used an old balance proof to close it. This test will: - Make a transfer from app0 to app1, to make sure there are balance proofs available - Call close manually in behalf of app1, without any balance proof data - Assert that app0 can settle the closed channel, even though app1 didn't use the latest balance proof """ 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=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, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_recovery_unhappy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, retry_timeout, ): app0, app1, app2 = raiden_network token_address = token_addresses[0] node_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( node_state, payment_network_id, token_address, ) # make a few transfers from app0 to app2 amount = 1 spent_amount = deposit - 2 for _ in range(spent_amount): mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) app0.raiden.stop() host_port = (app0.raiden.config['host'], app0.raiden.config['port']) socket = server._udp_socket(host_port) new_transport = UDPTransport( app0.discovery, socket, app0.raiden.transport.throttle_policy, app0.raiden.config['transport'], ) 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, ) app0_restart = App( app0.config, app0.raiden.chain, app0.raiden.default_registry, app0.raiden.default_secret_registry, new_transport, app0.raiden.discovery, ) del app0 # from here on the app0_restart should be used assert_synched_channel_state( token_network_identifier, app0_restart, deposit - spent_amount, [], app1, deposit + spent_amount, [], ) assert_synched_channel_state( token_network_identifier, app1, deposit - spent_amount, [], app2, deposit + spent_amount, [], )
def test_refund_transfer(raiden_chain, token_addresses, deposit, network_wait): """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] # make a transfer to test the path app0 -> app1 -> app2 identifier_path = 1 amount_path = 1 mediated_transfer( app0, app2, token_address, amount_path, identifier_path, timeout=network_wait, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 direct_transfer( app1, app2, token_address, amount_drain, identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synched_channel_state( token_address, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) assert_synched_channel_state( token_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 async_result = app0.raiden.mediated_transfer_async( token_address, 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, LockedTransfer) 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.secrethash == refund_message.lock.secrethash assert mediated_message.lock.expiration > refund_message.lock.expiration # Both channels have the amount locked because of the refund message assert_synched_channel_state( token_address, app0, deposit - amount_path, [lockstate_from_lock(mediated_message.lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_message.lock)], ) assert_synched_channel_state( token_address, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], )
def test_refund_transfer(raiden_chain, number_of_nodes, token_addresses, deposit, network_wait): """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 direct_transfer( app1, app2, token_network_identifier, amount_drain, identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synched_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) assert_synched_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 send_refund = raiden_events_must_contain_entry(app1.raiden, SendRefundTransfer, {}) assert send_refund lock = send_locked.transfer.lock refund_lock = send_refund.lock assert lock.amount == refund_lock.amount assert lock.secrethash assert lock.expiration # Both channels have the amount locked because of the refund message assert_synched_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) assert_synched_channel_state( token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], )
def test_fullnetwork(raiden_chain, token_addresses, deposit, settle_timeout, reveal_timeout): # The network has the following topology: # # App0 <---> App1 # ^ ^ # | | # v v # App3 <---> App2 token_address = token_addresses[0] app0, app1, app2, app3 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking channel_0_1 = channel(app0, app1, token_address) channel_3_2 = channel(app3, app2, token_address) channel_0_3 = channel(app0, app3, token_address) # Exhaust the channel deposit (to force the mediated transfer to go backwards) amount = deposit direct_transfer(app0, app1, token_address, amount) assert get_sent_transfer(channel_0_1, 0).transferred_amount == amount amount = int(deposit / 2.) mediated_transfer(app0, app2, token_address, amount) # This is the only possible path, the transfer must go backwards assert_path_mediated_transfer( get_sent_transfer(channel_0_3, 0), get_sent_transfer(channel_3_2, 0), ) # Now let's query the WAL to see if the state changes were logged as expected app0_state_changes = [ change[1] for change in get_all_state_changes(app0.raiden.transaction_log) if not isinstance(change[1], Block) ] app0_events = [ event.event_object for event in get_all_state_events(app0.raiden.transaction_log) ] app1_state_changes = [ change[1] for change in get_all_state_changes(app1.raiden.transaction_log) if not isinstance(change[1], Block) ] app1_events = [ event.event_object for event in get_all_state_events(app1.raiden.transaction_log) ] app2_state_changes = [ change[1] for change in get_all_state_changes(app2.raiden.transaction_log) if not isinstance(change[1], Block) ] app2_events = [ event.event_object for event in get_all_state_events(app2.raiden.transaction_log) ] app3_state_changes = [ change[1] for change in get_all_state_changes(app3.raiden.transaction_log) if not isinstance(change[1], Block) ] app3_events = [ event.event_object for event in get_all_state_events(app3.raiden.transaction_log) ] # app1 received one direct transfers assert len(app1_state_changes) == 1 assert len(app1_events) == 1 # app0 initiates the direct transfer and mediated_transfer assert len(app0_state_changes) == 4 assert isinstance(app0_state_changes[1], ActionInitInitiator) assert app0_state_changes[1].our_address == app0.raiden.address assert app0_state_changes[1].transfer.amount == amount assert app0_state_changes[1].transfer.token == token_address assert app0_state_changes[1].transfer.initiator == app0.raiden.address assert app0_state_changes[1].transfer.target == app2.raiden.address # The ActionInitInitiator state change does not have the following fields populated. # They get populated via an event during the processing of the state change inside # this function: mediated_transfer.mediated_transfer.initiator.try_new_route() assert app0_state_changes[1].transfer.expiration is None assert app0_state_changes[1].transfer.hashlock is None assert app0_state_changes[1].transfer.secret is None # We should have one available route assert len(app0_state_changes[1].routes.available_routes) == 1 assert len(app0_state_changes[1].routes.ignored_routes) == 0 assert len(app0_state_changes[1].routes.refunded_routes) == 0 assert len(app0_state_changes[1].routes.canceled_routes) == 0 # Of these 2 the state machine will in the future choose the one with the most # available balance not_taken_route = RouteState( state='opened', node_address=app1.raiden.address, channel_address=channel_0_1.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) taken_route = RouteState( state='opened', node_address=app3.raiden.address, channel_address=channel_0_3.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) assert taken_route in app0_state_changes[1].routes.available_routes assert not_taken_route not in app0_state_changes[1].routes.available_routes # app0 will also receive a secret request from the target assert isinstance(app0_state_changes[2], ReceiveSecretRequest) assert app0_state_changes[2].amount == amount assert app0_state_changes[2].sender == app2.raiden.address hashlock = app0_state_changes[2].hashlock # app0 will also receive a secret reveal from the immediate neighbour assert isinstance(app0_state_changes[3], ReceiveSecretReveal) assert app0_state_changes[3].sender == app3.raiden.address secret = app0_state_changes[3].secret assert sha3(secret) == hashlock assert len(app0_events) == 6 # Direct transfer assert isinstance(app0_events[0], EventTransferSentSuccess) # not checking the expiration and identifier assert isinstance(app0_events[1], SendMediatedTransfer) assert app0_events[1].token == token_address assert app0_events[1].amount == amount assert app0_events[1].hashlock == hashlock assert app0_events[1].initiator == app0.raiden.address assert app0_events[1].target == app2.raiden.address assert app0_events[1].receiver == app3.raiden.address # not checking the identifier assert isinstance(app0_events[2], SendRevealSecret) assert app0_events[2].secret == secret assert app0_events[2].token == token_address assert app0_events[2].receiver == app2.raiden.address assert app0_events[2].sender == app0.raiden.address # not checking the identifier assert isinstance(app0_events[3], SendBalanceProof) assert app0_events[3].token == token_address assert app0_events[3].channel_address == channel_0_3.channel_address assert app0_events[3].receiver == app3.raiden.address assert app0_events[3].secret == secret assert isinstance(app0_events[4], EventTransferSentSuccess) # EventUnlockSuccess, not checking the identifier assert isinstance(app0_events[5], EventUnlockSuccess) assert app0_events[5].hashlock == hashlock # app3 is the mediator assert isinstance(app3_state_changes[0], ActionInitMediator) assert app3_state_changes[0].our_address == app3.raiden.address # We should have only 1 available route from mediator to target from_route = RouteState( state='opened', node_address=app0.raiden.address, channel_address=channel_0_3.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) to_route = RouteState( state='opened', node_address=app2.raiden.address, channel_address=channel_3_2.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) assert app3_state_changes[0].from_route == from_route assert len(app3_state_changes[0].routes.available_routes) == 1 assert len(app3_state_changes[0].routes.ignored_routes) == 0 assert len(app3_state_changes[0].routes.refunded_routes) == 0 assert len(app3_state_changes[0].routes.canceled_routes) == 0 assert app3_state_changes[0].routes.available_routes[0] == to_route # check the from_transfer is correct assert app3_state_changes[0].from_transfer.amount == amount assert app3_state_changes[0].from_transfer.hashlock == hashlock assert app3_state_changes[0].from_transfer.token == token_address assert app3_state_changes[0].from_transfer.initiator == app0.raiden.address assert app3_state_changes[0].from_transfer.target == app2.raiden.address # The mediator should have also received a SecretReveal from the target assert isinstance(app3_state_changes[1], ReceiveSecretReveal) assert app3_state_changes[1].sender == app2.raiden.address assert app3_state_changes[1].secret == secret # If the mediator received any more it is from the initiator # TODO: Figure out why we may get two times the secret reveal from the initiator for state_change in app3_state_changes[2:]: assert isinstance(state_change, ReceiveSecretReveal) assert state_change.sender == app0.raiden.address assert state_change.secret == secret # check app3 state events assert len(app3_events) == 4 assert isinstance(app3_events[0], SendMediatedTransfer) assert app3_events[0].token == token_address assert app3_events[0].amount == amount assert app3_events[0].hashlock == hashlock assert app3_events[0].initiator == app0.raiden.address assert app3_events[0].target == app2.raiden.address assert app3_events[0].receiver == app2.raiden.address assert isinstance(app3_events[1], SendRevealSecret) assert app3_events[1].secret == secret assert app3_events[1].token == token_address assert app3_events[1].receiver == app0.raiden.address assert app3_events[1].sender == app3.raiden.address assert isinstance(app3_events[2], SendBalanceProof) assert app3_events[2].token == token_address assert app3_events[2].channel_address == channel_3_2.channel_address assert app3_events[2].receiver == app2.raiden.address assert app3_events[2].secret == secret assert isinstance(app3_events[3], EventUnlockSuccess) # app2 is the target of the mediated transfer assert len(app2_state_changes ) == 4 # We get 2 secret reveals from the mediator. WHY? assert isinstance(app2_state_changes[0], ActionInitTarget) assert app2_state_changes[0].our_address == app2.raiden.address # check the route the transfer came from from_route = RouteState( state='opened', node_address=app3.raiden.address, channel_address=channel_3_2.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) assert app2_state_changes[0].from_route == from_route # check the from_transfer is correct assert app2_state_changes[0].from_transfer.amount == amount assert app2_state_changes[0].from_transfer.hashlock == hashlock assert app2_state_changes[0].from_transfer.token == token_address assert app2_state_changes[0].from_transfer.initiator == app0.raiden.address assert app2_state_changes[0].from_transfer.target == app2.raiden.address # We also get secret reveals from the initiator and the mediator. assert isinstance(app2_state_changes[1], ReceiveSecretReveal) assert app2_state_changes[1].sender == app0.raiden.address assert app2_state_changes[1].secret == secret # TODO: Figure out why we get two times the Secret Reveal from the mediator assert isinstance(app2_state_changes[2], ReceiveSecretReveal) assert app2_state_changes[2].sender == app3.raiden.address assert app2_state_changes[2].secret == secret assert isinstance(app2_state_changes[3], ReceiveSecretReveal) assert app2_state_changes[3].sender == app3.raiden.address assert app2_state_changes[3].secret == secret # check app2 state events assert len(app2_events) == 2 assert isinstance(app2_events[0], SendSecretRequest) assert app2_events[0].amount == amount assert app2_events[0].hashlock == hashlock assert app2_events[0].receiver == app0.raiden.address assert isinstance(app2_events[1], SendRevealSecret) assert app2_events[1].token == token_address assert app2_events[1].secret == secret assert app2_events[1].receiver == app3.raiden.address assert app2_events[1].sender == app2.raiden.address
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 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 assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lock], app1, deposit + amount_path, [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_recovery_unhappy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, 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 _ in range(spent_amount): mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) app0.raiden.stop() host_port = (app0.raiden.config['host'], app0.raiden.config['port']) socket = server._udp_socket(host_port) new_transport = UDPTransport( app0.discovery, socket, app0.raiden.transport.throttle_policy, app0.raiden.config['transport'], ) 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, ) 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, transport=new_transport, discovery=app0.raiden.discovery, ) del app0 # from here on the app0_restart should be used assert_synched_channel_state( token_network_identifier, app0_restart, deposit - spent_amount, [], app1, deposit + spent_amount, [], ) assert_synched_channel_state( token_network_identifier, app1, deposit - spent_amount, [], app2, deposit + spent_amount, [], )
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_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 mediated_transfer( app0, app2, token_network_identifier, amount, 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, 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, expiration, UNIT_SECRETHASH), target=app2.raiden.address, initiator=app0.raiden.address, fee=0, ) sign_and_inject( mediated_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], )
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_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 mediated_transfer( app0, app3, token_network_identifier, amount_path, identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app2 -> app3 identifier_drain = 2 amount_drain = deposit * 8 // 10 direct_transfer( app2, app3, token_network_identifier, amount_drain, 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, [], app2, deposit + amount_path, [], ) 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 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app3.raiden.address, identifier_refund, ) assert async_result.wait( ) is False, 'there is no path with capacity, the transfer must fail' gevent.sleep(0.2) # Lock structures with the correct amount send_locked1 = raiden_events_must_contain_entry( app0.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': amount_refund } }}, ) assert send_locked1 send_refund1 = raiden_events_must_contain_entry(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_must_contain_entry( app1.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': amount_refund } }}, ) assert send_locked2 send_refund2 = raiden_events_must_contain_entry(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 assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock1)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock1)], ) assert_synced_channel_state( token_network_identifier, app1, deposit - amount_path, [lockstate_from_lock(lock2)], app2, deposit + amount_path, [lockstate_from_lock(refund_lock2)], ) assert_synced_channel_state( token_network_identifier, app2, deposit - amount_path - amount_drain, [], app3, deposit + amount_path + amount_drain, [], )
def test_mediated_transfer_events(raiden_network, number_of_nodes, token_addresses, 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, ) amount = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) def test_initiator_events(): initiator_blockevents = app0.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) initiator_events = [ blocknumber_event[1] for blocknumber_event in initiator_blockevents ] return (must_contain_entry(initiator_events, SendRevealSecret, {}) and must_contain_entry(initiator_events, EventUnlockSuccess, {})) assert wait_until(test_initiator_events, network_wait) def test_mediator_events(): mediator_blockevents = app1.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) mediator_events = [ blocknumber_event[1] for blocknumber_event in mediator_blockevents ] return (must_contain_entry(mediator_events, EventUnlockSuccess, {}) and must_contain_entry(mediator_events, EventUnlockClaimSuccess, {})) assert wait_until(test_mediator_events, network_wait) def test_target_events(): target_blockevents = app2.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) target_events = [ blocknumber_event[1] for blocknumber_event in target_blockevents ] return (must_contain_entry(target_events, SendSecretRequest, {}) and must_contain_entry(target_events, SendRevealSecret, {}) and must_contain_entry(target_events, EventUnlockClaimSuccess, {})) assert wait_until(test_target_events, network_wait)
def test_settled_lock(token_addresses, raiden_network, deposit): """ Any transfer following a secret reveal must update the locksroot, so that an attacker cannot reuse a secret to double claim a lock. """ app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] amount = 30 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) hold_event_handler = HoldOffChainSecretRequest() app1.raiden.raiden_event_handler = hold_event_handler address0 = app0.raiden.address address1 = app1.raiden.address deposit0 = deposit deposit1 = deposit token_proxy = app0.raiden.chain.token(token_address) initial_balance0 = token_proxy.balance_of(address0) initial_balance1 = token_proxy.balance_of(address1) identifier = 1 target = app1.raiden.address secret = sha3(target) secrethash = sha3(secret) secret_available = hold_event_handler.hold_secretrequest_for( secrethash=secrethash) app0.raiden.start_mediated_transfer_with_secret( token_network_identifier, amount, target, identifier, secret, ) secret_available.wait() # wait for the messages to be exchanged # Save the merkle tree leaves from the pending transfer, used to test the unlock channelstate_0_1 = get_channelstate(app0, app1, token_network_identifier) batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state) assert batch_unlock hold_event_handler.release_secretrequest_for( app1.raiden, secrethash, ) mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=amount, identifier=2, ) RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_settle( app1.raiden, app1.raiden.default_registry.address, token_address, [channelstate_0_1.identifier], app1.raiden.alarm.sleep_time, ) netting_channel = app1.raiden.chain.payment_channel( token_network_identifier, channelstate_0_1.identifier, ) # The transfer locksroot must not contain the unlocked lock, the # unlock must fail. with pytest.raises(Exception): netting_channel.unlock( channelstate_0_1.partner_state.address, batch_unlock, ) expected_balance0 = initial_balance0 + deposit0 - amount * 2 expected_balance1 = initial_balance1 + deposit1 + amount * 2 assert token_proxy.balance_of(address0) == expected_balance0 assert token_proxy.balance_of(address1) == expected_balance1
def test_automatic_dispute(raiden_network, deposit, token_addresses): app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) token_proxy = app0.raiden.chain.token(channel0.token_address) initial_balance0 = token_proxy.balance_of(app0.raiden.address) initial_balance1 = token_proxy.balance_of(app1.raiden.address) amount0_1 = 10 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=amount0_1, ) amount1_1 = 50 mediated_transfer( initiator_app=app1, target_app=app0, token_network_identifier=token_network_identifier, amount=amount1_1, ) amount0_2 = 60 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=amount0_2, ) # Alice can only provide one of Bob's transfer, so she is incentivized to # use the one with the largest transferred_amount. RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) # Bob needs to provide a transfer otherwise its netted balance will be # wrong, so he is incentivised to use Alice's transfer with the largest # transferred_amount. # # This is done automatically # channel1.external_state.update_transfer( # alice_second_transfer, # ) waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel0.identifier], app0.raiden.alarm.sleep_time, ) # check that the channel is properly settled and that Bob's client # automatically called updateTransfer() to reflect the actual transactions assert token_proxy.balance_of(token_network_identifier) == 0 total0 = amount0_1 + amount0_2 total1 = amount1_1 expected_balance0 = initial_balance0 + deposit - total0 + total1 expected_balance1 = initial_balance1 + deposit + total0 - total1 assert token_proxy.balance_of(app0.raiden.address) == expected_balance0 assert token_proxy.balance_of(app1.raiden.address) == expected_balance1
def test_node_can_settle_if_partner_does_not_call_update_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, chain_id, ): """ A node must be able to settle a channel, even if the partner did not call update transfer. This test will: - Make a transfer from app0 to app1, to make sure there are balance proofs available - Stop app1, to make sure update is not called. - Use app0 to close the channel. - Assert that app0 can settle the closed channel, even though app1 didn't use the latest balance proof """ 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=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, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) # 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_node_can_settle_if_close_didnt_use_any_balance_proof( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, ): """ A node must be able to settle a channel, even if the partner used an old balance proof to close it. This test will: - Make a transfer from app0 to app1, to make sure there are balance proofs available - Call close manually in behalf of app1, without any balance proof data - Assert that app0 can settle the closed channel, even though app1 didn't use the latest balance proof """ 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=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, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) 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_settled_lock(token_addresses, raiden_network, deposit): """ Any transfer following a secret reveal must update the locksroot, so that an attacker cannot reuse a secret to double claim a lock. """ app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] amount = 30 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) hold_event_handler = HoldOffChainSecretRequest() app1.raiden.raiden_event_handler = hold_event_handler address0 = app0.raiden.address address1 = app1.raiden.address deposit0 = deposit deposit1 = deposit token_proxy = app0.raiden.chain.token(token_address) initial_balance0 = token_proxy.balance_of(address0) initial_balance1 = token_proxy.balance_of(address1) identifier = 1 target = app1.raiden.address secret = sha3(target) secrethash = sha3(secret) secret_available = hold_event_handler.hold_secretrequest_for(secrethash=secrethash) app0.raiden.start_mediated_transfer_with_secret( token_network_identifier, amount, target, identifier, secret, ) secret_available.wait() # wait for the messages to be exchanged # Save the merkle tree leaves from the pending transfer, used to test the unlock channelstate_0_1 = get_channelstate(app0, app1, token_network_identifier) batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state) assert batch_unlock hold_event_handler.release_secretrequest_for( app1.raiden, secrethash, ) mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=amount, identifier=2, ) RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_settle( app1.raiden, app1.raiden.default_registry.address, token_address, [channelstate_0_1.identifier], app1.raiden.alarm.sleep_time, ) netting_channel = app1.raiden.chain.payment_channel( token_network_identifier, channelstate_0_1.identifier, ) # The transfer locksroot must not contain the unlocked lock, the # unlock must fail. with pytest.raises(Exception): netting_channel.unlock( channelstate_0_1.partner_state.address, batch_unlock, ) expected_balance0 = initial_balance0 + deposit0 - amount * 2 expected_balance1 = initial_balance1 + deposit1 + amount * 2 assert token_proxy.balance_of(address0) == expected_balance0 assert token_proxy.balance_of(address1) == expected_balance1
def 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 mediated_transfer( initiator_app=app0, target_app=app3, token_network_identifier=token_network_identifier, 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 mediated_transfer( initiator_app=app2, target_app=app3, 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, [], app2, deposit + amount_path, [], ) 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 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app3.raiden.address, identifier_refund, ) assert async_result.wait() is False, 'there is no path with capacity, the transfer must fail' gevent.sleep(0.2) # Lock structures with the correct amount send_locked1 = raiden_events_must_contain_entry( app0.raiden, SendLockedTransfer, {'transfer': {'lock': {'amount': amount_refund}}}, ) assert send_locked1 send_refund1 = raiden_events_must_contain_entry(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_must_contain_entry( app1.raiden, SendLockedTransfer, {'transfer': {'lock': {'amount': amount_refund}}}, ) assert send_locked2 send_refund2 = raiden_events_must_contain_entry(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 assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock1)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock1)], ) assert_synced_channel_state( token_network_identifier, app1, deposit - amount_path, [lockstate_from_lock(lock2)], app2, deposit + amount_path, [lockstate_from_lock(refund_lock2)], ) assert_synced_channel_state( token_network_identifier, app2, deposit - amount_path - amount_drain, [], app3, deposit + amount_path + amount_drain, [], )
def test_fullnetwork(raiden_chain, token_addresses, deposit, settle_timeout, reveal_timeout): # pylint: disable=too-many-locals,too-many-statements # The network has the following topology: # # App0 <---> App1 # ^ ^ # | | # v v # App3 <---> App2 token_address = token_addresses[0] app0, app1, app2, app3 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking channel_0_1 = channel(app0, app1, token_address) channel_3_2 = channel(app3, app2, token_address) channel_0_3 = channel(app0, app3, token_address) # Exhaust the channel deposit (to force the mediated transfer to go backwards) amount = deposit direct_transfer(app0, app1, token_address, amount, identifier=1) assert get_sent_transfer(channel_0_1, 0).transferred_amount == amount amount = int(deposit / 2.) mediated_transfer(app0, app2, token_address, amount) gevent.sleep(0.5) # This is the only possible path, the transfer must go backwards assert_path_mediated_transfer( get_sent_transfer(channel_0_3, 0), get_sent_transfer(channel_3_2, 0), ) app0_state_changes = [ change[1] for change in get_all_state_changes(app0.raiden.transaction_log) ] app0_events = [ event.event_object for event in get_all_state_events(app0.raiden.transaction_log) ] secret = None for event in app0_events: if isinstance(event, SendRevealSecret): secret = event.secret assert secret is not None hashlock = sha3(secret) # app0 initiates the direct transfer and mediated_transfer assert must_contain_entry( app0_state_changes, ActionInitInitiator, { 'our_address': app0.raiden.address, 'transfer': { 'amount': amount, 'token': token_address, 'initiator': app0.raiden.address, 'target': app2.raiden.address, 'expiration': None, 'hashlock': None, 'secret': None, } }) # Of these 2 the state machine will in the future choose the one with the most # available balance not_taken_route = RouteState( state='opened', node_address=app1.raiden.address, channel_address=channel_0_1.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) taken_route = RouteState( state='opened', node_address=app3.raiden.address, channel_address=channel_0_3.channel_address, available_balance=deposit, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) for state_change in app0_state_changes: if isinstance(state_change, ActionInitMediator): assert taken_route in state_change.routes.available_routes assert not_taken_route not in state_change.routes.available_routes # app1 received one direct transfers app1_state_changes = [ change[1] for change in get_all_state_changes(app1.raiden.transaction_log) ] assert must_contain_entry(app1_state_changes, ReceiveBalanceProof, {}) assert must_contain_entry(app1_state_changes, ReceiveTransferDirect, {}) app2_state_changes = [ change[1] for change in get_all_state_changes(app2.raiden.transaction_log) ] assert must_contain_entry( app2_state_changes, ActionInitTarget, { 'our_address': app2.raiden.address, 'from_route': { 'state': 'opened', 'node_address': app3.raiden.address, 'channel_address': channel_3_2.channel_address, 'available_balance': deposit, 'settle_timeout': settle_timeout, 'reveal_timeout': reveal_timeout, 'closed_block': None }, 'from_transfer': { 'amount': amount, 'hashlock': hashlock, 'token': token_address, 'initiator': app0.raiden.address, 'target': app2.raiden.address, } }) assert must_contain_entry(app2_state_changes, ReceiveSecretReveal, { 'sender': app0.raiden.address, 'secret': secret, }) assert must_contain_entry(app2_state_changes, ReceiveSecretReveal, { 'sender': app3.raiden.address, 'secret': secret, }) app2_events = [ event.event_object for event in get_all_state_events(app2.raiden.transaction_log) ] assert must_contain_entry(app2_events, SendSecretRequest, { 'amount': amount, 'hashlock': hashlock, 'receiver': app0.raiden.address, }) assert must_contain_entry( app2_events, SendRevealSecret, { 'token': token_address, 'secret': secret, 'receiver': app3.raiden.address, 'sender': app2.raiden.address, }) assert must_contain_entry(app0_state_changes, ReceiveSecretRequest, { 'amount': amount, 'sender': app2.raiden.address, 'hashlock': hashlock, }) assert must_contain_entry(app0_state_changes, ReceiveSecretReveal, { 'sender': app3.raiden.address, 'secret': secret, }) assert must_contain_entry(app0_events, EventTransferSentSuccess, {}) assert must_contain_entry( app0_events, SendMediatedTransfer, { 'token': token_address, 'amount': amount, 'hashlock': hashlock, 'initiator': app0.raiden.address, 'target': app2.raiden.address, 'receiver': app3.raiden.address, }) assert must_contain_entry( app0_events, SendRevealSecret, { 'secret': secret, 'token': token_address, 'receiver': app2.raiden.address, 'sender': app0.raiden.address, }) assert must_contain_entry( app0_events, SendBalanceProof, { 'token': token_address, 'channel_address': channel_0_3.channel_address, 'receiver': app3.raiden.address, 'secret': secret, }) assert must_contain_entry(app0_events, EventTransferSentSuccess, {}) assert must_contain_entry(app0_events, EventUnlockSuccess, { 'hashlock': hashlock, }) app3_state_changes = [ change[1] for change in get_all_state_changes(app3.raiden.transaction_log) ] assert must_contain_entry( app3_state_changes, ActionInitMediator, { 'our_address': app3.raiden.address, 'from_route': { 'state': 'opened', 'node_address': app0.raiden.address, 'channel_address': channel_0_3.channel_address, 'available_balance': deposit, 'settle_timeout': settle_timeout, 'reveal_timeout': reveal_timeout, 'closed_block': None, }, 'from_transfer': { 'amount': amount, 'hashlock': hashlock, 'token': token_address, 'initiator': app0.raiden.address, 'target': app2.raiden.address, } }) assert must_contain_entry(app3_state_changes, ReceiveSecretReveal, { 'sender': app2.raiden.address, 'secret': secret, }) assert must_contain_entry(app3_state_changes, ReceiveSecretReveal, { 'sender': app2.raiden.address, 'secret': secret, }) app3_events = [ event.event_object for event in get_all_state_events(app3.raiden.transaction_log) ] assert must_contain_entry( app3_events, SendMediatedTransfer, { 'token': token_address, 'amount': amount, 'hashlock': hashlock, 'initiator': app0.raiden.address, 'target': app2.raiden.address, 'receiver': app2.raiden.address, }) assert must_contain_entry( app3_events, SendRevealSecret, { 'secret': secret, 'token': token_address, 'receiver': app0.raiden.address, 'sender': app3.raiden.address, }) assert must_contain_entry( app3_events, SendBalanceProof, { 'token': token_address, 'channel_address': channel_3_2.channel_address, 'receiver': app2.raiden.address, 'secret': secret, }) assert must_contain_entry(app3_events, EventUnlockSuccess, {})
def test_recovery_unhappy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, 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 _ in range(spent_amount): mediated_transfer( app0, app2, token_network_identifier, amount, 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, 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel01.identifier, })
def test_refund_transfer(raiden_chain, token_addresses, deposit, network_wait): """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, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 direct_transfer( app1, app2, token_network_identifier, amount_drain, identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synched_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) assert_synched_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 = next( event for _, event in app0.raiden.wal.storage.get_events_by_identifier(0, 'latest') if isinstance(event, SendLockedTransfer) and event.transfer.lock.amount == amount_refund ) assert send_locked send_refund = next( event for _, event in app1.raiden.wal.storage.get_events_by_identifier(0, 'latest') if isinstance(event, SendRefundTransfer) ) assert send_refund lock = send_locked.transfer.lock refund_lock = send_refund.lock assert lock.amount == refund_lock.amount assert lock.secrethash assert lock.expiration # Both channels have the amount locked because of the refund message assert_synched_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) assert_synched_channel_state( token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], )
def test_invalid_update_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, chain_id, ): 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=1, timeout=network_wait * number_of_nodes, ) # stop app1 - the test uses token_network_contract now app1.stop() # close the channel RaidenAPI(app0.raiden).channel_close( registry_address=registry_address, token_address=token_address, partner_address=app1.raiden.address, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) # app1 won't update the channel # app0 waits for settle 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_recovery_happy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, ): 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 _ in range(spent_amount): mediated_transfer( app0, app2, token_network_identifier, amount, 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 = 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, 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, ) mediated_transfer( app2, app0_restart, token_network_identifier, amount, timeout=network_wait * number_of_nodes * 2, ) mediated_transfer( app0_restart, app2, token_network_identifier, amount, 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, [], )
def test_fullnetwork(raiden_chain, settle_timeout, reveal_timeout): app0, app1, app2, app3 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = app0.raiden.chain.default_registry.token_addresses()[0] channel_0_1 = channel(app0, app1, token_address) channel_1_2 = channel(app1, app2, token_address) channel_3_2 = channel(app3, app2, token_address) channel_0_3 = channel(app0, app3, token_address) amount = 80 direct_transfer(app0, app1, token_address, amount) last_transfer = get_sent_transfer(channel_0_1, 0) assert last_transfer.transferred_amount == 80 amount = 50 direct_transfer(app1, app2, token_address, amount) last_transfer = get_sent_transfer(channel_1_2, 0) assert last_transfer.transferred_amount == 50 amount = 30 mediated_transfer(app0, app2, token_address, amount) last_transfer = get_sent_transfer(channel_0_1, 0) assert isinstance(last_transfer, DirectTransfer) initiator_transfer = get_sent_transfer(channel_0_3, 0) mediator_transfer = get_sent_transfer(channel_3_2, 0) assert initiator_transfer.identifier == mediator_transfer.identifier assert initiator_transfer.lock.amount == amount assert mediator_transfer.lock.amount == amount # Now let's query the WAL to see if the state changes were logged as expected app0_state_changes = [ change[1] for change in get_all_state_changes(app0.raiden.transaction_log) if not isinstance(change[1], Block) ] app0_events = [ event[2] for event in get_all_state_events(app0.raiden.transaction_log) ] app1_state_changes = [ change[1] for change in get_all_state_changes(app1.raiden.transaction_log) if not isinstance(change[1], Block) ] app1_events = [ event[2] for event in get_all_state_events(app1.raiden.transaction_log) ] app2_state_changes = [ change[1] for change in get_all_state_changes(app2.raiden.transaction_log) if not isinstance(change[1], Block) ] app2_events = [ event[2] for event in get_all_state_events(app2.raiden.transaction_log) ] app3_state_changes = [ change[1] for change in get_all_state_changes(app3.raiden.transaction_log) if not isinstance(change[1], Block) ] app3_events = [ event[2] for event in get_all_state_events(app3.raiden.transaction_log) ] # app1 does not take part in the mediated transfer. assert len(app1_state_changes) == 0 assert len(app1_events) == 0 # app0 initiates the mediated_transfer assert len(app0_state_changes) == 3 assert isinstance(app0_state_changes[0], ActionInitInitiator) assert app0_state_changes[0].our_address == app0.raiden.address assert app0_state_changes[0].transfer.amount == amount assert app0_state_changes[0].transfer.token == token_address assert app0_state_changes[0].transfer.initiator == app0.raiden.address assert app0_state_changes[0].transfer.target == app2.raiden.address # The ActionInitInitiator state change does not have the following fields populated. # They get populated via an event during the processing of the state change inside # this function: mediated_transfer.mediated_transfer.initiator.try_new_route() assert app0_state_changes[0].transfer.expiration is None assert app0_state_changes[0].transfer.hashlock is None assert app0_state_changes[0].transfer.secret is None # We should have two available routes assert len(app0_state_changes[0].routes.available_routes) == 2 assert len(app0_state_changes[0].routes.ignored_routes) == 0 assert len(app0_state_changes[0].routes.refunded_routes) == 0 assert len(app0_state_changes[0].routes.canceled_routes) == 0 # Of these 2 the state machine will in the future choose the one with the most # available balance not_taken_route = RouteState( state='opened', node_address=app1.raiden.address, channel_address=channel_0_1.channel_address, available_balance=1048496, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) taken_route = RouteState( state='opened', node_address=app3.raiden.address, channel_address=channel_0_3.channel_address, available_balance=1048576, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) assert taken_route in app0_state_changes[0].routes.available_routes assert not_taken_route in app0_state_changes[0].routes.available_routes # app0 will also receive a secret request from the target assert isinstance(app0_state_changes[1], ReceiveSecretRequest) assert app0_state_changes[1].amount == amount assert app0_state_changes[1].sender == app2.raiden.address hashlock = app0_state_changes[1].hashlock # app0 will also receive a secret reveal from the immediate neighbour assert isinstance(app0_state_changes[2], ReceiveSecretReveal) assert app0_state_changes[2].sender == app3.raiden.address secret = app0_state_changes[2].secret assert sha3(secret) == hashlock # check app0 state events assert len(app0_events) == 4 assert isinstance(app0_events[0], SendMediatedTransfer) assert app0_events[0].token == token_address assert app0_events[0].amount == amount assert app0_events[0].hashlock == hashlock assert app0_events[0].initiator == app0.raiden.address assert app0_events[0].target == app2.raiden.address assert app0_events[0].receiver == app3.raiden.address assert isinstance(app0_events[1], SendRevealSecret) assert app0_events[1].secret == secret assert app0_events[1].token == token_address assert app0_events[1].receiver == app2.raiden.address assert app0_events[1].sender == app0.raiden.address assert isinstance(app0_events[2], SendBalanceProof) assert app0_events[2].token == token_address assert app0_events[2].channel_address == channel_0_3.channel_address assert app0_events[2].receiver == app3.raiden.address assert app0_events[2].secret == secret assert isinstance(app0_events[3], EventTransferCompleted) assert app0_events[3].secret == secret assert app0_events[3].hashlock == hashlock # app3 is the mediator assert isinstance(app3_state_changes[0], ActionInitMediator) assert app3_state_changes[0].our_address == app3.raiden.address # We should have only 1 available route from mediator to target from_route = RouteState( state='opened', node_address=app0.raiden.address, channel_address=channel_0_3.channel_address, available_balance=1048576, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) to_route = RouteState( state='opened', node_address=app2.raiden.address, channel_address=channel_3_2.channel_address, available_balance=1048576, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) assert app3_state_changes[0].from_route == from_route assert len(app3_state_changes[0].routes.available_routes) == 1 assert len(app3_state_changes[0].routes.ignored_routes) == 0 assert len(app3_state_changes[0].routes.refunded_routes) == 0 assert len(app3_state_changes[0].routes.canceled_routes) == 0 assert app3_state_changes[0].routes.available_routes[0] == to_route # check the from_transfer is correct assert app3_state_changes[0].from_transfer.amount == amount assert app3_state_changes[0].from_transfer.hashlock == hashlock assert app3_state_changes[0].from_transfer.token == token_address assert app3_state_changes[0].from_transfer.initiator == app0.raiden.address assert app3_state_changes[0].from_transfer.target == app2.raiden.address # The mediator should have also received a SecretReveal from the target assert isinstance(app3_state_changes[1], ReceiveSecretReveal) assert app3_state_changes[1].sender == app2.raiden.address assert app3_state_changes[1].secret == secret # If the mediator received any more it is from the initiator # TODO: Figure out why we may get two times the secret reveal from the initiator for state_change in app3_state_changes[2:]: assert isinstance(state_change, ReceiveSecretReveal) assert state_change.sender == app0.raiden.address assert state_change.secret == secret # check app3 state events assert len(app3_events) == 3 assert isinstance(app3_events[0], SendMediatedTransfer) assert app3_events[0].token == token_address assert app3_events[0].amount == amount assert app3_events[0].hashlock == hashlock assert app3_events[0].initiator == app0.raiden.address assert app3_events[0].target == app2.raiden.address assert app3_events[0].receiver == app2.raiden.address assert isinstance(app3_events[1], SendRevealSecret) assert app3_events[1].secret == secret assert app3_events[1].token == token_address assert app3_events[1].receiver == app0.raiden.address assert app3_events[1].sender == app3.raiden.address assert isinstance(app3_events[2], SendBalanceProof) assert app3_events[2].token == token_address assert app3_events[2].channel_address == channel_3_2.channel_address assert app3_events[2].receiver == app2.raiden.address assert app3_events[2].secret == secret # app2 is the target of the mediated transfer assert len(app2_state_changes ) == 4 # We get 2 secret reveals from the mediator. WHY? assert isinstance(app2_state_changes[0], ActionInitTarget) assert app2_state_changes[0].our_address == app2.raiden.address # check the route the transfer came from from_route = RouteState( state='opened', node_address=app3.raiden.address, channel_address=channel_3_2.channel_address, available_balance=1048576, settle_timeout=settle_timeout, reveal_timeout=reveal_timeout, closed_block=None, ) assert app2_state_changes[0].from_route == from_route # check the from_transfer is correct assert app2_state_changes[0].from_transfer.amount == amount assert app2_state_changes[0].from_transfer.hashlock == hashlock assert app2_state_changes[0].from_transfer.token == token_address assert app2_state_changes[0].from_transfer.initiator == app0.raiden.address assert app2_state_changes[0].from_transfer.target == app2.raiden.address # We also get secret reveals from the initiator and the mediator. assert isinstance(app2_state_changes[1], ReceiveSecretReveal) assert app2_state_changes[1].sender == app0.raiden.address assert app2_state_changes[1].secret == secret # TODO: Figure out why we get two times the Secret Reveal from the mediator assert isinstance(app2_state_changes[2], ReceiveSecretReveal) assert app2_state_changes[2].sender == app3.raiden.address assert app2_state_changes[2].secret == secret assert isinstance(app2_state_changes[3], ReceiveSecretReveal) assert app2_state_changes[3].sender == app3.raiden.address assert app2_state_changes[3].secret == secret # check app2 state events assert len(app2_events) == 2 assert isinstance(app2_events[0], SendSecretRequest) assert app2_events[0].amount == amount assert app2_events[0].hashlock == hashlock assert app2_events[0].receiver == app0.raiden.address assert isinstance(app2_events[1], SendRevealSecret) assert app2_events[1].token == token_address assert app2_events[1].secret == secret assert app2_events[1].receiver == app3.raiden.address assert app2_events[1].sender == app2.raiden.address
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, # 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 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 assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lock], app1, deposit + amount_path, [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_recovery_happy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, ): app0, app1, app2 = raiden_network token_address = token_addresses[0] app2_wait_for = WaitForMessage() app2.raiden.message_handler = app2_wait_for 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 _ in range(spent_amount): mediated_transfer( app0, app2, token_network_identifier, amount, 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 = 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, 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, ) identifier = create_default_identifier() wait_for_payment = app2_wait_for.wait_for_message(Secret, {'payment_identifier': identifier}) mediated_transfer( app2, app0_restart, token_network_identifier, amount, timeout=network_wait * number_of_nodes * 2, ) mediated_transfer( initiator_app=app0_restart, target_app=app2, token_network_identifier=token_network_identifier, amount=amount, identifier=identifier, timeout=network_wait * number_of_nodes * 2, ) assert_synced_channel_state( token_network_identifier, app0_restart, deposit - spent_amount, [], app1, deposit + spent_amount, [], ) wait_for_payment.wait() assert_synced_channel_state( token_network_identifier, app1, deposit - spent_amount, [], app2, deposit + spent_amount, [], )
def test_invalid_close( 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) 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=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, manager_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, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })