def test_target_log_directransfer_message( raiden_chain, token_addresses, deposit): token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 21 app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking direct_transfer( app0, app1, token_address, amount, identifier, ) app1_state_changes = get_all_state_changes(app1.raiden.transaction_log) received_transfers = [ state_change for _, state_change in app1_state_changes if isinstance(state_change, ReceiveTransferDirect) ] assert received_transfers[0] == ReceiveTransferDirect( identifier, amount, token_address, app0.raiden.address, )
def test_target_log_directransfer_message( raiden_chain, token_addresses, deposit): token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 21 app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking direct_transfer( app0, app1, token_address, amount, identifier, ) app1_state_changes = get_all_state_changes(app1.raiden.transaction_log) received_transfers = [ state_change for _, state_change in app1_state_changes if isinstance(state_change, ReceiveTransferDirect) ] assert received_transfers[0] == ReceiveTransferDirect( identifier, amount, token_address, app0.raiden.address, )
def test_initiator_log_directransfer_action( raiden_chain, token_addresses, deposit): """ The action that start a direct transfer must be logged in the WAL. """ token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 13 app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking direct_transfer( app0, app1, token_address, amount, identifier, ) app0_state_changes = get_all_state_changes(app0.raiden.transaction_log) direct_transfers = [ state_change for _, state_change in app0_state_changes if isinstance(state_change, ActionTransferDirect) ] assert direct_transfers[0] == ActionTransferDirect( identifier, amount, token_address, app1.raiden.address, )
def test_initiator_log_directransfer_action( raiden_chain, token_addresses, deposit): """ The action that start a direct transfer must be logged in the WAL. """ token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 13 app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking direct_transfer( app0, app1, token_address, amount, identifier, ) app0_state_changes = get_all_state_changes(app0.raiden.transaction_log) direct_transfers = [ state_change for _, state_change in app0_state_changes if isinstance(state_change, ActionTransferDirect) ] assert direct_transfers[0] == ActionTransferDirect( identifier, amount, token_address, app1.raiden.address, )
def test_settlement(raiden_network, settle_timeout, reveal_timeout): alice_app, bob_app = raiden_network # pylint: disable=unbalanced-tuple-unpacking setup_messages_cb() alice_graph = alice_app.raiden.channelgraphs.values()[0] bob_graph = bob_app.raiden.channelgraphs.values()[0] assert alice_graph.token_address == bob_graph.token_address alice_bob_channel = alice_graph.partneraddress_channel[ bob_app.raiden.address] bob_alice_channel = bob_graph.partneraddress_channel[ alice_app.raiden.address] alice_deposit = alice_bob_channel.balance bob_deposit = bob_alice_channel.balance token = alice_app.raiden.chain.token(alice_bob_channel.token_address) alice_balance = token.balance_of(alice_app.raiden.address) bob_balance = token.balance_of(bob_app.raiden.address) alice_chain = alice_app.raiden.chain alice_to_bob_amount = 10 expiration = alice_app.raiden.chain.block_number() + reveal_timeout + 1 secret = 'secretsecretsecretsecretsecretse' hashlock = sha3(secret) assert bob_app.raiden.address in alice_graph.partneraddress_channel nettingaddress0 = alice_bob_channel.external_state.netting_channel.address nettingaddress1 = bob_alice_channel.external_state.netting_channel.address assert nettingaddress0 == nettingaddress1 identifier = 1 fee = 0 transfermessage = alice_bob_channel.create_mediatedtransfer( alice_app.raiden.get_block_number(), alice_app.raiden.address, bob_app.raiden.address, fee, alice_to_bob_amount, identifier, expiration, hashlock, ) alice_app.raiden.sign(transfermessage) alice_bob_channel.register_transfer( alice_app.raiden.get_block_number(), transfermessage, ) bob_alice_channel.register_transfer( bob_app.raiden.get_block_number(), transfermessage, ) assert_synched_channels( alice_bob_channel, alice_deposit, [], bob_alice_channel, bob_deposit, [transfermessage.lock], ) # At this point we are assuming the following: # # A -> B MediatedTransfer # B -> A SecretRequest # A -> B RevealSecret # - protocol didn't continue # # B knowns the secret but doesn't have an updated balance proof, B needs to # call settle. # get proof, that locked transfermessage was in merkle tree, with locked.root lock = bob_alice_channel.our_state.balance_proof.get_lock_by_hashlock( hashlock) assert sha3(secret) == hashlock unlock_proof = bob_alice_channel.our_state.balance_proof.compute_proof_for_lock( secret, lock) root = bob_alice_channel.our_state.balance_proof.merkleroot_for_unclaimed() assert check_proof( unlock_proof.merkle_proof, root, sha3(transfermessage.lock.as_bytes), ) assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes assert unlock_proof.secret == secret # a ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle bob_alice_channel.external_state.netting_channel.close(transfermessage) wait_until_block(alice_chain, alice_chain.block_number() + 1) assert alice_bob_channel.external_state.close_event.wait(timeout=15) assert bob_alice_channel.external_state.close_event.wait(timeout=15) assert alice_bob_channel.external_state.closed_block != 0 assert bob_alice_channel.external_state.closed_block != 0 assert alice_bob_channel.external_state.settled_block == 0 assert bob_alice_channel.external_state.settled_block == 0 # unlock will not be called by Channel.channel_closed because we did not # register the secret assert lock.expiration > alice_app.raiden.chain.block_number() assert lock.hashlock == sha3(secret) bob_alice_channel.external_state.netting_channel.withdraw([unlock_proof]) settle_expiration = alice_chain.block_number() + settle_timeout + 2 wait_until_block(alice_chain, settle_expiration) assert alice_bob_channel.external_state.settle_event.wait(timeout=15) assert bob_alice_channel.external_state.settle_event.wait(timeout=15) # settle must be called by the apps triggered by the ChannelClose event, # and the channels must update it's state based on the ChannelSettled event assert alice_bob_channel.external_state.settled_block != 0 assert bob_alice_channel.external_state.settled_block != 0 address0 = alice_app.raiden.address address1 = bob_app.raiden.address alice_netted_balance = alice_balance + alice_deposit - alice_to_bob_amount bob_netted_balance = bob_balance + bob_deposit + alice_to_bob_amount assert token.balance_of(address0) == alice_netted_balance assert token.balance_of(address1) == bob_netted_balance # Now let's query the WAL to see if the state changes were logged as expected state_changes = [ change[1] for change in get_all_state_changes(alice_app.raiden.transaction_log) if not isinstance(change[1], Block) ] state_change1 = state_changes[0] state_change2 = state_changes[1] state_change3 = state_changes[2] state_change4 = state_changes[3] assert isinstance(state_change1, ContractReceiveClosed) assert state_change1.channel_address == nettingaddress0 assert state_change1.closing_address == bob_app.raiden.address assert state_change1.block_number == alice_bob_channel.external_state.closed_block # Can't be sure of the order in which we encounter the SecretReveal and the withdraw assert_secretreveal_or_withdraw(state_change2, secret, nettingaddress0, bob_app.raiden.address) assert_secretreveal_or_withdraw(state_change3, secret, nettingaddress0, bob_app.raiden.address) assert isinstance(state_change4, ContractReceiveSettled) assert state_change4.channel_address == nettingaddress0 assert state_change4.block_number == bob_alice_channel.external_state.settled_block
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_settlement(raiden_network, settle_timeout, reveal_timeout): alice_app, bob_app = raiden_network # pylint: disable=unbalanced-tuple-unpacking setup_messages_cb() alice_graph = list(alice_app.raiden.token_to_channelgraph.values())[0] bob_graph = list(bob_app.raiden.token_to_channelgraph.values())[0] assert alice_graph.token_address == bob_graph.token_address alice_bob_channel = alice_graph.partneraddress_to_channel[bob_app.raiden.address] bob_alice_channel = bob_graph.partneraddress_to_channel[alice_app.raiden.address] alice_deposit = alice_bob_channel.balance bob_deposit = bob_alice_channel.balance token = alice_app.raiden.chain.token(alice_bob_channel.token_address) alice_balance = token.balance_of(alice_app.raiden.address) bob_balance = token.balance_of(bob_app.raiden.address) alice_chain = alice_app.raiden.chain alice_to_bob_amount = 10 expiration = alice_app.raiden.chain.block_number() + reveal_timeout + 1 secret = b'secretsecretsecretsecretsecretse' hashlock = sha3(secret) assert bob_app.raiden.address in alice_graph.partneraddress_to_channel nettingaddress0 = alice_bob_channel.external_state.netting_channel.address nettingaddress1 = bob_alice_channel.external_state.netting_channel.address assert nettingaddress0 == nettingaddress1 identifier = 1 fee = 0 transfermessage = alice_bob_channel.create_mediatedtransfer( alice_app.raiden.address, bob_app.raiden.address, fee, alice_to_bob_amount, identifier, expiration, hashlock, ) alice_app.raiden.sign(transfermessage) alice_bob_channel.register_transfer( alice_app.raiden.get_block_number(), transfermessage, ) bob_alice_channel.register_transfer( bob_app.raiden.get_block_number(), transfermessage, ) assert_synched_channels( alice_bob_channel, alice_deposit, [], bob_alice_channel, bob_deposit, [transfermessage.lock], ) # At this point we are assuming the following: # # A -> B MediatedTransfer # B -> A SecretRequest # A -> B RevealSecret # - protocol didn't continue # # B knowns the secret but doesn't have an updated balance proof, B needs to # call settle. # get proof, that locked transfermessage was in merkle tree, with locked.root lock = bob_alice_channel.partner_state.get_lock_by_hashlock(hashlock) assert sha3(secret) == hashlock unlock_proof = bob_alice_channel.partner_state.compute_proof_for_lock(secret, lock) root = merkleroot(bob_alice_channel.partner_state.merkletree) assert validate_proof( unlock_proof.merkle_proof, root, sha3(transfermessage.lock.as_bytes), ) assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes assert unlock_proof.secret == secret # a ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle balance_proof = transfermessage.to_balanceproof() bob_alice_channel.external_state.close(balance_proof) wait_until_block(alice_chain, alice_chain.block_number() + 1) assert alice_bob_channel.external_state.close_event.wait(timeout=15) assert bob_alice_channel.external_state.close_event.wait(timeout=15) assert alice_bob_channel.external_state.closed_block != 0 assert bob_alice_channel.external_state.closed_block != 0 assert alice_bob_channel.external_state.settled_block == 0 assert bob_alice_channel.external_state.settled_block == 0 # unlock will not be called by Channel.channel_closed because we did not # register the secret assert lock.expiration > alice_app.raiden.chain.block_number() assert lock.hashlock == sha3(secret) bob_alice_channel.external_state.netting_channel.withdraw([unlock_proof]) settle_expiration = alice_chain.block_number() + settle_timeout + 2 wait_until_block(alice_chain, settle_expiration) assert alice_bob_channel.external_state.settle_event.wait(timeout=15) assert bob_alice_channel.external_state.settle_event.wait(timeout=15) # settle must be called by the apps triggered by the ChannelClose event, # and the channels must update it's state based on the ChannelSettled event assert alice_bob_channel.external_state.settled_block != 0 assert bob_alice_channel.external_state.settled_block != 0 address0 = alice_app.raiden.address address1 = bob_app.raiden.address alice_netted_balance = alice_balance + alice_deposit - alice_to_bob_amount bob_netted_balance = bob_balance + bob_deposit + alice_to_bob_amount assert token.balance_of(address0) == alice_netted_balance assert token.balance_of(address1) == bob_netted_balance # Now let's query the WAL to see if the state changes were logged as expected state_changes = [ change[1] for change in get_all_state_changes(alice_app.raiden.transaction_log) if not isinstance(change[1], Block) ] assert must_contain_entry(state_changes, ContractReceiveClosed, { 'channel_address': nettingaddress0, 'closing_address': bob_app.raiden.address, 'block_number': alice_bob_channel.external_state.closed_block, }) assert must_contain_entry(state_changes, ReceiveSecretReveal, { 'secret': secret, 'sender': bob_app.raiden.address, }) assert must_contain_entry(state_changes, ContractReceiveWithdraw, { 'channel_address': nettingaddress0, 'secret': secret, 'receiver': bob_app.raiden.address, }) assert must_contain_entry(state_changes, ContractReceiveSettled, { 'channel_address': nettingaddress0, 'block_number': bob_alice_channel.external_state.settled_block, })
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_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_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, {})