def test_regression_unavailable_nodes_must_be_properly_filtered(): """The list of available routes provided must be filtered based on the network status of the partner node. Regression test for: https://github.com/raiden-network/raiden/issues/3567 """ block_number = 5 pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_signed_transfer_for( channels[0], LONG_EXPIRATION) all_nodes_offline = { channel.partner_state.address: NODE_NETWORK_UNREACHABLE for channel in channels.channels } initial_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action( channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=all_nodes_offline, pseudo_random_generator=pseudo_random_generator, block_number=block_number, block_hash=factories.make_block_hash(), ) send_transfer = search_for_item(initial_iteration.events, SendLockedTransfer, {}) msg = ( 'All available routes are with unavailable nodes, therefore no send ' 'should be produced') assert send_transfer is None, msg
def test_regression_mediator_send_lock_expired_with_new_block(): """The mediator must send the lock expired, but it must **not** clear itself if it has not **received** the corresponding message. """ pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_signed_transfer_for( channels[0], LONG_EXPIRATION) init_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action( channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, addresses_to_channel=channels.addresses_to_channel(), nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=5, block_hash=factories.make_block_hash(), ) assert init_iteration.new_state is not None send_transfer = search_for_item(init_iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = channel.get_sender_expiration_threshold( transfer.lock.expiration) block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=init_iteration.new_state, state_change=block, channelidentifiers_to_channels=channels.channel_map, addresses_to_channel=channels.addresses_to_channel(), nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, block_hash=factories.make_block_hash(), ) msg = ("The payer's lock has also expired, " "but it must not be removed locally (without an Expired lock)") assert transfer.lock.secrethash in channels[ 0].partner_state.secrethashes_to_lockedlocks, msg msg = "The payer has not yet sent an expired lock, the task can not be cleared yet" assert iteration.new_state is not None, msg assert search_for_item(iteration.events, SendLockExpired, {"secrethash": transfer.lock.secrethash}) assert transfer.lock.secrethash not in channels[ 1].our_state.secrethashes_to_lockedlocks
def test_regression_mediator_send_lock_expired_with_new_block(): """ The mediator must send the lock expired, but it must **not** clear itself if it has not **received** the corresponding message. """ pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_default_signed_transfer_for( channels[0], initiator=HOP1, expiration=30, ) init_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action( channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=5, ) assert init_iteration.new_state is not None send_transfer = must_contain_entry(init_iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2 block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=init_iteration.new_state, state_change=block, channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, ) msg = ("The payer's lock has also expired, " "but it must not be removed locally (without an Expired lock)") assert transfer.lock.secrethash in channels[ 0].partner_state.secrethashes_to_lockedlocks, msg msg = 'The payer has not yet sent an expired lock, the task can not be cleared yet' assert iteration.new_state is not None, msg assert must_contain_entry(iteration.events, SendLockExpired, { 'secrethash': transfer.lock.secrethash, }) assert transfer.lock.secrethash not in channels[ 1].our_state.secrethashes_to_lockedlocks
def test_get_state_change_with_transfer_by_secrethash(): serializer = JSONSerializer() storage = SerializedSQLiteStorage(":memory:", serializer) mediator_secret, mediator_secrethash = factories.make_secret_with_hash() channels = factories.mediator_make_channel_pair() mediator_transfer = factories.create( factories.LockedTransferSignedStateProperties( secret=mediator_secret, target=channels.partner_address(1), initiator=channels.partner_address(0), ) ) mediator_state_change = factories.mediator_make_init_action(channels, mediator_transfer) target_secret, target_secrethash = factories.make_secret_with_hash() from_channel = factories.create( factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( balance=100, address=factories.make_address() ) ) ) target_transfer = factories.create( factories.LockedTransferSignedStateProperties( secret=target_secret, target=channels.our_address(0), initiator=channels.partner_address(1), ) ) target_state_change = ActionInitTarget( from_hop=HopState( node_address=from_channel.partner_state.address, channel_identifier=from_channel.canonical_identifier.channel_identifier, ), transfer=target_transfer, balance_proof=target_transfer.balance_proof, sender=target_transfer.balance_proof.sender, # pylint: disable=no-member ) assert storage.count_state_changes() == 0 storage.write_state_changes([mediator_state_change, target_state_change]) assert storage.count_state_changes() == 2 restored = get_state_change_with_transfer_by_secrethash(storage, mediator_secrethash) assert isinstance(restored.data, ActionInitMediator) assert restored.data.from_transfer == mediator_transfer restored = get_state_change_with_transfer_by_secrethash(storage, target_secrethash) assert isinstance(restored.data, ActionInitTarget) assert restored.data.transfer == target_transfer
def test_regression_mediator_send_lock_expired_with_new_block(): """ The mediator must send the lock expired, but it must **not** clear itself if it has not **received** the corresponding message. """ pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_signed_transfer_for(channels[0], LONG_EXPIRATION) init_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action(channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=5, ) assert init_iteration.new_state is not None send_transfer = must_contain_entry(init_iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = channel.get_sender_expiration_threshold(transfer.lock) block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=init_iteration.new_state, state_change=block, channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, ) msg = ( "The payer's lock has also expired, " "but it must not be removed locally (without an Expired lock)" ) assert transfer.lock.secrethash in channels[0].partner_state.secrethashes_to_lockedlocks, msg msg = 'The payer has not yet sent an expired lock, the task can not be cleared yet' assert iteration.new_state is not None, msg assert must_contain_entry(iteration.events, SendLockExpired, { 'secrethash': transfer.lock.secrethash, }) assert transfer.lock.secrethash not in channels[1].our_state.secrethashes_to_lockedlocks
def test_payer_enter_danger_zone_with_transfer_payed(): """ A mediator may have paid the next hop (payee), and didn't get paid by the previous hop (payer). When this happens, an assertion must not be hit, because it means the transfer must be unlocked on-chain. Issue: https://github.com/raiden-network/raiden/issues/1013 """ block_number = 5 pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_signed_transfer_for( channels[0], LONG_EXPIRATION) initial_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action( channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_number, block_hash=factories.make_block_hash(), ) send_transfer = search_for_item(initial_iteration.events, SendLockedTransfer, {}) assert send_transfer lock_expiration = send_transfer.transfer.lock.expiration new_state = initial_iteration.new_state for block_number in range(block_number, lock_expiration - channels[1].reveal_timeout): block_state_change = Block( block_number=block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) block_iteration = mediator.handle_block( new_state, block_state_change, channels.channel_map, pseudo_random_generator, ) new_state = block_iteration.new_state # send the balance proof, transitioning the payee state to paid assert new_state.transfers_pair[0].payee_state == 'payee_pending' receive_secret = ReceiveSecretReveal( UNIT_SECRET, channels[1].partner_state.address, ) paid_iteration = mediator.state_transition( mediator_state=new_state, state_change=receive_secret, channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_number, block_hash=factories.make_block_hash(), ) paid_state = paid_iteration.new_state assert paid_state.transfers_pair[0].payee_state == 'payee_balance_proof' # move to the block in which the payee lock expires. This must not raise an # assertion expired_block_number = lock_expiration + 1 expired_block_state_change = Block( block_number=expired_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) block_iteration = mediator.handle_block( mediator_state=paid_state, state_change=expired_block_state_change, channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, )
def test_regression_mediator_not_update_payer_state_twice(): """ Regression Test for https://github.com/raiden-network/raiden/issues/3086 Make sure that after a lock expired the mediator doesn't update the pair twice causing EventUnlockClaimFailed to be generated at every block. """ pseudo_random_generator = random.Random() pair = factories.mediator_make_channel_pair() payer_channel, payee_channel = pair.channels payer_route = factories.route_from_channel(payer_channel) payer_transfer = factories.make_signed_transfer_for( payer_channel, LONG_EXPIRATION) available_routes = [factories.route_from_channel(payee_channel)] init_state_change = ActionInitMediator( routes=available_routes, from_route=payer_route, from_transfer=payer_transfer, ) iteration = mediator.state_transition( mediator_state=None, state_change=init_state_change, channelidentifiers_to_channels=pair.channel_map, nodeaddresses_to_networkstates=pair.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=5, block_hash=factories.make_block_hash(), ) assert iteration.new_state is not None current_state = iteration.new_state send_transfer = search_for_item(iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = channel.get_sender_expiration_threshold( transfer.lock) block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=current_state, state_change=block, channelidentifiers_to_channels=pair.channel_map, nodeaddresses_to_networkstates=pair.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, block_hash=factories.make_block_hash(), ) msg = 'At the expiration block we should get an EventUnlockClaimFailed' assert search_for_item(iteration.events, EventUnlockClaimFailed, {}), msg current_state = iteration.new_state next_block = Block( block_number=block_expiration_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) # Initiator receives the secret reveal after the lock expired receive_secret = ReceiveSecretReveal( secret=UNIT_SECRET, sender=payee_channel.partner_state.address, ) iteration = mediator.state_transition( mediator_state=current_state, state_change=receive_secret, channelidentifiers_to_channels=pair.channel_map, nodeaddresses_to_networkstates=pair.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=next_block.block_number, block_hash=next_block.block_hash, ) current_state = iteration.new_state lock = payer_transfer.lock secrethash = lock.secrethash assert secrethash in payer_channel.partner_state.secrethashes_to_lockedlocks assert current_state.transfers_pair[0].payee_state == 'payee_expired' assert not channel.is_secret_known(payer_channel.partner_state, secrethash) safe_to_wait, _ = mediator.is_safe_to_wait( lock_expiration=lock.expiration, reveal_timeout=payer_channel.reveal_timeout, block_number=lock.expiration + 10, ) assert not safe_to_wait iteration = mediator.state_transition( mediator_state=current_state, state_change=next_block, channelidentifiers_to_channels=pair.channel_map, nodeaddresses_to_networkstates=pair.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, block_hash=factories.make_block_hash(), ) msg = 'At the next block we should not get the same event' assert not search_for_item(iteration.events, EventUnlockClaimFailed, {}), msg
def test_payer_enter_danger_zone_with_transfer_payed(): """ A mediator may have paid the next hop (payee), and didn't get paid by the previous hop (payer). When this happens, an assertion must not be hit, because it means the transfer must be unlocked on-chain. Issue: https://github.com/raiden-network/raiden/issues/1013 """ block_number = 5 pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_signed_transfer_for(channels[0], LONG_EXPIRATION) initial_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action(channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) send_transfer = must_contain_entry(initial_iteration.events, SendLockedTransfer, {}) assert send_transfer lock_expiration = send_transfer.transfer.lock.expiration new_state = initial_iteration.new_state for block_number in range(block_number, lock_expiration - channels[1].reveal_timeout): block_state_change = Block( block_number=block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) block_iteration = mediator.handle_block( new_state, block_state_change, channels.channel_map, pseudo_random_generator, ) new_state = block_iteration.new_state # send the balance proof, transitioning the payee state to paid assert new_state.transfers_pair[0].payee_state == 'payee_pending' receive_secret = ReceiveSecretReveal( UNIT_SECRET, channels[1].partner_state.address, ) paid_iteration = mediator.state_transition( mediator_state=new_state, state_change=receive_secret, channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) paid_state = paid_iteration.new_state assert paid_state.transfers_pair[0].payee_state == 'payee_balance_proof' # move to the block in which the payee lock expires. This must not raise an # assertion expired_block_number = lock_expiration + 1 expired_block_state_change = Block( block_number=expired_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) block_iteration = mediator.handle_block( mediator_state=paid_state, state_change=expired_block_state_change, channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, )
def test_regression_mediator_not_update_payer_state_twice(): """ Regression Test for https://github.com/raiden-network/raiden/issues/3086 Make sure that after a lock expired the mediator doesn't update the pair twice causing EventUnlockClaimFailed to be generated at every block. """ pseudo_random_generator = random.Random() pair = factories.mediator_make_channel_pair() payer_channel, payee_channel = pair.channels payer_route = factories.route_from_channel(payer_channel) payer_transfer = factories.make_signed_transfer_for(payer_channel, LONG_EXPIRATION) available_routes = [factories.route_from_channel(payee_channel)] init_state_change = ActionInitMediator( routes=available_routes, from_route=payer_route, from_transfer=payer_transfer, ) iteration = mediator.state_transition( mediator_state=None, state_change=init_state_change, channelidentifiers_to_channels=pair.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=5, ) assert iteration.new_state is not None current_state = iteration.new_state send_transfer = must_contain_entry(iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = channel.get_sender_expiration_threshold(transfer.lock) block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=current_state, state_change=block, channelidentifiers_to_channels=pair.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, ) msg = 'At the expiration block we should get an EventUnlockClaimFailed' assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg current_state = iteration.new_state next_block = Block( block_number=block_expiration_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) # Initiator receives the secret reveal after the lock expired receive_secret = ReceiveSecretReveal( secret=UNIT_SECRET, sender=payee_channel.partner_state.address, ) iteration = mediator.state_transition( mediator_state=current_state, state_change=receive_secret, channelidentifiers_to_channels=pair.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=next_block.block_number, ) current_state = iteration.new_state lock = payer_transfer.lock secrethash = lock.secrethash assert secrethash in payer_channel.partner_state.secrethashes_to_lockedlocks assert current_state.transfers_pair[0].payee_state == 'payee_expired' assert not channel.is_secret_known(payer_channel.partner_state, secrethash) safe_to_wait, _ = mediator.is_safe_to_wait( lock_expiration=lock.expiration, reveal_timeout=payer_channel.reveal_timeout, block_number=lock.expiration + 10, ) assert not safe_to_wait iteration = mediator.state_transition( mediator_state=current_state, state_change=next_block, channelidentifiers_to_channels=pair.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, ) msg = 'At the next block we should not get the same event' assert not must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg