def test_mediator_task_view(): """Same as above for mediator tasks.""" secret1 = factories.make_secret(1) locked_amount1 = 11 payee_transfer = factories.create( factories.LockedTransferUnsignedStateProperties(secret=secret1)) payer_transfer = factories.create( factories.LockedTransferSignedStateProperties( secret=secret1, payment_identifier=1, locked_amount=locked_amount1)) secrethash1 = payee_transfer.lock.secrethash initiator = payee_transfer.initiator initiator_channel = factories.create( factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( address=initiator, balance=100))) routes = [factories.make_route_from_channel(initiator_channel)] transfer_state1 = MediatorTransferState(secrethash=secrethash1, routes=routes) transfer_state1.transfers_pair.append( MediationPairState( payer_transfer=payer_transfer, payee_transfer=payee_transfer, payee_address=payee_transfer.target, )) task1 = MediatorTask( token_network_identifier=factories.UNIT_TOKEN_NETWORK_ADDRESS, mediator_state=transfer_state1, ) secret2 = factories.make_secret(2) locked_amount2 = 13 transfer2 = factories.create( factories.LockedTransferSignedStateProperties( secret=secret2, payment_identifier=2, locked_amount=locked_amount2)) secrethash2 = transfer2.lock.secrethash transfer_state2 = MediatorTransferState(secrethash=secrethash2, routes=routes) transfer_state2.waiting_transfer = WaitingTransferState(transfer=transfer2) task2 = MediatorTask( token_network_identifier=factories.UNIT_TOKEN_NETWORK_ADDRESS, mediator_state=transfer_state2, ) payment_mapping = {secrethash1: task1, secrethash2: task2} view = transfer_tasks_view(payment_mapping) assert len(view) == 2 if view[0].get("payment_identifier") == "1": pending_transfer, waiting_transfer = view else: waiting_transfer, pending_transfer = view assert pending_transfer.get("role") == waiting_transfer.get( "role") == "mediator" assert pending_transfer.get("payment_identifier") == "1" assert waiting_transfer.get("payment_identifier") == "2" assert pending_transfer.get("locked_amount") == str(locked_amount1) assert waiting_transfer.get("locked_amount") == str(locked_amount2)
def test_mediator_task_view(): """Same as above for mediator tasks.""" secret1 = factories.make_secret(1) locked_amount1 = TokenAmount(11) payee_transfer = factories.create( factories.LockedTransferUnsignedStateProperties(secret=secret1)) payer_transfer = factories.create( factories.LockedTransferSignedStateProperties( secret=secret1, payment_identifier=PaymentID(1), locked_amount=locked_amount1)) secrethash1 = payee_transfer.lock.secrethash route_state = RouteState(route=[payee_transfer.target]) transfer_state1 = MediatorTransferState(secrethash=secrethash1, routes=[route_state]) # pylint: disable=E1101 transfer_state1.transfers_pair.append( MediationPairState( payer_transfer=payer_transfer, payee_transfer=payee_transfer, payee_address=payee_transfer.target, )) task1 = MediatorTask( token_network_address=factories.UNIT_TOKEN_NETWORK_ADDRESS, mediator_state=transfer_state1) secret2 = factories.make_secret(2) locked_amount2 = TokenAmount(13) transfer2 = factories.create( factories.LockedTransferSignedStateProperties( secret=secret2, payment_identifier=PaymentID(2), locked_amount=locked_amount2)) secrethash2 = transfer2.lock.secrethash transfer_state2 = MediatorTransferState(secrethash=secrethash2, routes=[route_state]) transfer_state2.waiting_transfer = WaitingTransferState(transfer=transfer2) task2 = MediatorTask( token_network_address=factories.UNIT_TOKEN_NETWORK_ADDRESS, mediator_state=transfer_state2) payment_mapping = { secrethash1: cast(TransferTask, task1), secrethash2: cast(TransferTask, task2), } view = transfer_tasks_view(payment_mapping) assert len(view) == 2 if view[0].get("payment_identifier") == "1": pending_transfer, waiting_transfer = view else: waiting_transfer, pending_transfer = view assert pending_transfer.get("role") == waiting_transfer.get( "role") == "mediator" assert pending_transfer.get("payment_identifier") == "1" assert waiting_transfer.get("payment_identifier") == "2" assert pending_transfer.get("locked_amount") == str(locked_amount1) assert waiting_transfer.get("locked_amount") == str(locked_amount2)
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_target_task_view(): """Same as above for target tasks.""" secret = factories.make_secret() transfer = factories.create( factories.LockedTransferSignedStateProperties(secret=secret)) secrethash = transfer.lock.secrethash mediator = factories.make_address() mediator_channel = factories.create( factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( address=mediator, balance=TokenAmount(100)))) transfer_state = TargetTransferState( from_hop=HopState( channel_identifier=mediator_channel.canonical_identifier. channel_identifier, node_address=mediator, ), transfer=transfer, secret=secret, ) task = TargetTask( canonical_identifier=mediator_channel.canonical_identifier, target_state=transfer_state) payment_mapping = {secrethash: cast(TransferTask, task)} view = transfer_tasks_view(payment_mapping) assert len(view) == 1 pending_transfer = view[0] assert pending_transfer.get("role") == "target" # pylint: disable=no-member assert pending_transfer.get("locked_amount") == str( transfer.balance_proof.locked_amount) assert pending_transfer.get("payment_identifier") == str( transfer.payment_identifier)
def test_target_accept_keccak_empty_hash(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) expiration = block_number + channels[0].settle_timeout - channels[ 0].reveal_timeout from_transfer = factories.make_signed_transfer_for( channels[0], factories.LockedTransferSignedStateProperties( amount=lock_amount, target=channels.our_address(0), expiration=expiration, secret=EMPTY_SECRET, ), allow_invalid=True, ) init = ActionInitTarget( from_hop=channels.get_hop(0), transfer=from_transfer, balance_proof=from_transfer.balance_proof, sender=from_transfer.balance_proof.sender, # pylint: disable=no-member ) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state
def test_target_task_view(): """Same as above for target tasks.""" secret = factories.make_secret() transfer = factories.create( factories.LockedTransferSignedStateProperties(secret=secret)) secrethash = transfer.lock.secrethash mediator = factories.make_address() mediator_channel = factories.create( factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( address=mediator, balance=100))) transfer_state = TargetTransferState(route=None, transfer=transfer, secret=secret) task = TargetTask( canonical_identifier=mediator_channel.canonical_identifier, target_state=transfer_state) payment_mapping = {secrethash: task} view = transfer_tasks_view(payment_mapping) assert len(view) == 1 pending_transfer = view[0] assert pending_transfer.get("role") == "target" assert pending_transfer.get("locked_amount") == str( transfer.balance_proof.locked_amount) assert pending_transfer.get("payment_identifier") == str( transfer.payment_identifier)
def make_from_route_from_counter(counter): from_channel = factories.create( factories.NettingChannelStateProperties( canonical_identifier=factories.make_canonical_identifier(), token_address=factories.make_token_address(), partner_state=factories.NettingChannelEndStateProperties( balance=next(counter), address=factories.HOP1), )) from_hop = factories.make_hop_from_channel(from_channel) expiration = BlockExpiration(factories.UNIT_REVEAL_TIMEOUT + 1) from_transfer = factories.make_signed_transfer_for( from_channel, factories.LockedTransferSignedStateProperties( transferred_amount=TokenAmount(0), canonical_identifier=factories.make_canonical_identifier( token_network_address=from_channel.token_network_address), amount=TokenAmount(1), expiration=expiration, secret=sha3(factories.make_secret(next(counter))), initiator=factories.make_initiator_address(), target=factories.make_target_address(), payment_identifier=next(counter), sender=factories.HOP1, pkey=factories.HOP1_KEY, ), ) return from_hop, from_transfer
def make_signed_transfer_from_counter(counter): lock = Lock( amount=next(counter), expiration=next(counter), secrethash=factories.make_secret_hash(next(counter)), ) signed_transfer = factories.create( factories.LockedTransferSignedStateProperties( amount=next(counter), initiator=factories.make_initiator_address(), target=factories.make_target_address(), expiration=next(counter), secret=factories.make_secret(next(counter)), payment_identifier=next(counter), token=factories.make_token_address(), nonce=next(counter), transferred_amount=next(counter), locked_amount=next(counter), locksroot=sha3(lock.as_bytes), canonical_identifier=factories.make_canonical_identifier( token_network_address=factories.make_address(), channel_identifier=next(counter)), recipient=factories.make_address(), sender=factories.HOP1, pkey=factories.HOP1_KEY, )) return signed_transfer
def test_target_reject_keccak_empty_hash(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) expiration = block_number + channels[0].settle_timeout - channels[ 0].reveal_timeout from_transfer = factories.make_signed_transfer_for( channels[0], factories.LockedTransferSignedStateProperties( transfer=factories.LockedTransferProperties( amount=lock_amount, target=channels.our_address(0), expiration=expiration, secret=EMPTY_HASH, ), ), allow_invalid=True, ) init = ActionInitTarget(route=channels.get_route(0), transfer=from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is None
def test_invalid_instantiation_action_init_mediator_and_target(additional_args): hop_state = HopState( node_address=factories.make_address(), channel_identifier=factories.make_channel_identifier(), ) route_state = RouteState( route=[factories.make_address()], forward_channel_id=factories.make_channel_identifier() ) not_a_route_state = object() valid_transfer = factories.create(factories.LockedTransferSignedStateProperties()) wrong_type_transfer = factories.create(factories.TransferDescriptionProperties()) with pytest.raises(ValueError): ActionInitMediator( from_transfer=wrong_type_transfer, from_hop=hop_state, route_states=[route_state], **additional_args, ) with pytest.raises(ValueError): ActionInitMediator( from_transfer=valid_transfer, from_hop=not_a_route_state, route_states=[route_state], **additional_args, ) with pytest.raises(ValueError): ActionInitTarget(transfer=wrong_type_transfer, from_hop=hop_state, **additional_args) with pytest.raises(ValueError): ActionInitTarget(transfer=valid_transfer, from_hop=not_a_route_state, **additional_args)
def test_invalid_instantiation_locked_transfer_state(): valid_unsigned = factories.create( factories.LockedTransferUnsignedStateProperties()) valid_signed = factories.create( factories.LockedTransferSignedStateProperties()) # neither class can be instantiated with an empty locksroot for valid in (valid_unsigned, valid_signed): empty_balance_proof = replace(valid.balance_proof, locksroot=LOCKSROOT_OF_NO_LOCKS) with pytest.raises(ValueError): replace(valid, balance_proof=empty_balance_proof) # an unsigned locked transfer state cannot be instantiated with a signed balance proof with pytest.raises(ValueError): replace(valid_unsigned, balance_proof=valid_signed.balance_proof) # and vice versa with pytest.raises(ValueError): replace(valid_signed, balance_proof=valid_unsigned.balance_proof) # lock is typechecked wrong_type_lock = object() for valid in (valid_unsigned, valid_signed): with pytest.raises(ValueError): replace(valid, lock=wrong_type_lock)
def make_from_route_from_counter(counter): from_channel = factories.make_channel( partner_balance=next(counter), partner_address=factories.HOP1, token_address=factories.make_address(), channel_identifier=next(counter), ) from_route = factories.route_from_channel(from_channel) expiration = factories.UNIT_REVEAL_TIMEOUT + 1 from_transfer = factories.make_signed_transfer_for( from_channel, factories.LockedTransferSignedStateProperties( transfer=factories.LockedTransferProperties( balance_proof=factories.BalanceProofProperties( transferred_amount=0, token_network_identifier=from_channel. token_network_identifier, ), amount=1, expiration=expiration, secret=sha3(factories.make_secret(next(counter))), initiator=factories.make_address(), target=factories.make_address(), payment_identifier=next(counter), ), sender=factories.HOP1, pkey=factories.HOP1_KEY, ), ) return from_route, from_transfer
def test_target_task_view(): """Same as above for target tasks.""" secret = factories.make_secret() transfer = factories.create( factories.LockedTransferSignedStateProperties( transfer=factories.LockedTransferProperties(secret=secret), )) secrethash = transfer.lock.secrethash mediator = factories.make_address() mediator_channel = factories.create( factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( address=mediator, balance=100), )) transfer_state = TargetTransferState(route=None, transfer=transfer, secret=secret) task = TargetTask( token_network_identifier=factories.UNIT_TOKEN_NETWORK_ADDRESS, channel_identifier=mediator_channel.identifier, target_state=transfer_state, ) payment_mapping = {secrethash: task} view = transfer_tasks_view(payment_mapping) assert len(view) == 1 pending_transfer = view[0] assert pending_transfer.get('role') == 'target' assert pending_transfer.get('locked_amount') == str( transfer.balance_proof.locked_amount) assert pending_transfer.get('payment_identifier') == str( transfer.payment_identifier)
def _new_mediator_transfer( self, initiator_address, target_address, payment_id, amount, secret, our_address ) -> LockedTransferSignedState: initiator_pkey = self.address_to_privkey[initiator_address] balance_proof_data = self._update_balance_proof_data( initiator_address, amount, self.block_number + 10, secret, our_address ) self.secrethash_to_secret[sha256_secrethash(secret)] = secret return factories.create( factories.LockedTransferSignedStateProperties( **balance_proof_data.properties.__dict__, amount=amount, expiration=self.block_number + 10, payment_identifier=payment_id, secret=secret, initiator=initiator_address, target=target_address, token=self.token_id, sender=initiator_address, recipient=our_address, pkey=initiator_pkey, message_identifier=1, ) )
def test_subdispatch_to_paymenttask_target(chain_state, netting_channel_state): target_state = TargetTransferState( from_hop=HopState( node_address=netting_channel_state.partner_state.address, channel_identifier=netting_channel_state.canonical_identifier. channel_identifier, ), transfer=factories.create( factories.LockedTransferSignedStateProperties()), secret=UNIT_SECRET, ) subtask = TargetTask( canonical_identifier=netting_channel_state.canonical_identifier, target_state=target_state) chain_state.payment_mapping.secrethashes_to_task[UNIT_SECRETHASH] = subtask lock = factories.HashTimeLockState(amount=0, expiration=2, secrethash=UNIT_SECRETHASH) netting_channel_state.partner_state.secrethashes_to_lockedlocks[ UNIT_SECRETHASH] = lock netting_channel_state.partner_state.pending_locks = PendingLocksState( [bytes(lock.encoded)]) state_change = Block( block_number=chain_state.block_number, gas_limit=GAS_LIMIT, block_hash=chain_state.block_hash, ) transition_result = subdispatch_to_paymenttask(chain_state=chain_state, state_change=state_change, secrethash=UNIT_SECRETHASH) assert transition_result.events == [] assert transition_result.new_state == chain_state chain_state.block_number = 20 balance_proof: BalanceProofSignedState = factories.create( factories.BalanceProofSignedStateProperties( canonical_identifier=netting_channel_state.canonical_identifier, sender=netting_channel_state.partner_state.address, transferred_amount=0, pkey=factories.UNIT_TRANSFER_PKEY, locksroot=LOCKSROOT_OF_NO_LOCKS, )) state_change = ReceiveLockExpired( balance_proof=balance_proof, sender=netting_channel_state.partner_state.address, secrethash=UNIT_SECRETHASH, message_identifier=factories.make_message_identifier(), ) transition_result = subdispatch_to_paymenttask(chain_state=chain_state, state_change=state_change, secrethash=UNIT_SECRETHASH) msg = "ReceiveLockExpired should have cleared the task" assert UNIT_SECRETHASH not in chain_state.payment_mapping.secrethashes_to_task, msg assert len( transition_result.events), "ReceiveLockExpired should generate events" assert transition_result.new_state == chain_state
def test_invalid_instantiation_mediation_pair_state(): valid = MediationPairState( payer_transfer=factories.create(factories.LockedTransferSignedStateProperties()), payee_address=factories.make_address(), payee_transfer=factories.create(factories.LockedTransferUnsignedStateProperties()), ) unsigned_transfer = factories.create(factories.LockedTransferUnsignedStateProperties()) with pytest.raises(ValueError): replace(valid, payer_transfer=unsigned_transfer) signed_transfer = factories.create(factories.LockedTransferSignedStateProperties()) with pytest.raises(ValueError): replace(valid, payee_transfer=signed_transfer) hex_instead_of_binary = factories.make_checksum_address() with pytest.raises(ValueError): replace(valid, payee_address=hex_instead_of_binary)
def make_target_transfer(channel, amount=None, expiration=None, initiator=None, block_number=1): default_expiration = block_number + channel.settle_timeout - channel.reveal_timeout return factories.make_signed_transfer_for( channel, factories.LockedTransferSignedStateProperties( amount=amount or channel.partner_state.contract_balance, expiration=expiration or default_expiration, initiator=initiator or UNIT_TRANSFER_INITIATOR, target=channel.our_state.address, ), )
def test_regression_mediator_task_no_routes(): """ The mediator must only be cleared after the waiting transfer's lock has been handled. If a node receives a transfer to mediate, but there is no route available (because there is no sufficient capacity or the partner nodes are offline), and a refund is not possible, the mediator task must not be cleared, otherwise followup remove expired lock messages wont be processed and the nodes will get out of sync. """ pseudo_random_generator = random.Random() channels = make_channel_set([ NettingChannelStateProperties( our_state=NettingChannelEndStateProperties(balance=0), partner_state=NettingChannelEndStateProperties( balance=10, address=HOP2, privatekey=HOP2_KEY, ), ), ]) payer_transfer = factories.make_signed_transfer_for( channels[0], factories.LockedTransferSignedStateProperties( sender=HOP2, pkey=HOP2_KEY, transfer=factories.LockedTransferProperties(expiration=30), )) init_state_change = ActionInitMediator( channels.get_routes(), channels.get_route(0), payer_transfer, ) init_iteration = mediator.state_transition( mediator_state=None, state_change=init_state_change, channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=5, block_hash=factories.make_block_hash(), ) msg = 'The task must not be cleared, even if there is no route to forward the transfer' assert init_iteration.new_state is not None, msg assert init_iteration.new_state.waiting_transfer.transfer == payer_transfer assert search_for_item(init_iteration.events, SendLockedTransfer, {}) is None assert search_for_item(init_iteration.events, SendRefundTransfer, {}) is None secrethash = UNIT_SECRETHASH lock = channels[0].partner_state.secrethashes_to_lockedlocks[secrethash] # Creates a transfer as it was from the *partner* send_lock_expired, _ = channel.create_sendexpiredlock( sender_end_state=channels[0].partner_state, locked_lock=lock, pseudo_random_generator=pseudo_random_generator, chain_id=channels[0].chain_id, token_network_identifier=channels[0].token_network_identifier, channel_identifier=channels[0].identifier, recipient=channels[0].our_state.address, ) assert send_lock_expired lock_expired_message = message_from_sendevent(send_lock_expired, HOP1) lock_expired_message.sign(LocalSigner(channels.partner_privatekeys[0])) balance_proof = balanceproof_from_envelope(lock_expired_message) message_identifier = message_identifier_from_prng(pseudo_random_generator) # Regression: The mediator must still be able to process the block which # expires the lock expired_block_number = channel.get_sender_expiration_threshold(lock) block_hash = factories.make_block_hash() expire_block_iteration = mediator.state_transition( mediator_state=init_iteration.new_state, state_change=Block( block_number=expired_block_number, gas_limit=0, block_hash=block_hash, ), channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, block_hash=block_hash, ) assert expire_block_iteration.new_state is not None receive_expired_iteration = mediator.state_transition( mediator_state=expire_block_iteration.new_state, state_change=ReceiveLockExpired( balance_proof=balance_proof, secrethash=secrethash, message_identifier=message_identifier, ), channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, block_hash=block_hash, ) msg = 'The only used channel had the lock cleared, the task must be cleared' assert receive_expired_iteration.new_state is None, msg assert secrethash not in channels[ 0].partner_state.secrethashes_to_lockedlocks
def test_regression_send_refund(): """Regression test for discarded refund transfer. The handle_refundtransfer used to discard events from the channel state machine, which led to the state being updated but the message to the partner was never sent. Also, for issue: https://github.com/raiden-network/raiden/issues/3170 It was noticed that when receiving the same refund transfer twice, the mediator would detect an invalid refund and clear the mediator state. So the test also checks that mediator rejects the duplicate transfer and keeps the mediator state unchanged. """ pseudo_random_generator = random.Random() setup = factories.make_transfers_pair(3) mediator_state = MediatorTransferState( secrethash=UNIT_SECRETHASH, routes=setup.channels.get_routes() ) mediator_state.transfers_pair = setup.transfers_pair last_pair = setup.transfers_pair[-1] canonical_identifier = last_pair.payee_transfer.balance_proof.canonical_identifier lock_expiration = last_pair.payee_transfer.lock.expiration received_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=lock_expiration, payment_identifier=UNIT_TRANSFER_IDENTIFIER, canonical_identifier=canonical_identifier, sender=setup.channels.partner_address(2), pkey=setup.channels.partner_privatekeys[2], message_identifier=factories.make_message_identifier(), ) ) # All three channels have been used routes = [] refund_state_change = ReceiveTransferRefund(transfer=received_transfer, routes=routes) iteration = mediator.handle_refundtransfer( mediator_state=mediator_state, mediator_state_change=refund_state_change, channelidentifiers_to_channels=setup.channel_map, nodeaddresses_to_networkstates=setup.channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=setup.block_number, ) first_pair = setup.transfers_pair[0] first_payer_transfer = first_pair.payer_transfer payer_channel = mediator.get_payer_channel(setup.channel_map, first_pair) lock = channel.get_lock(end_state=payer_channel.partner_state, secrethash=UNIT_SECRETHASH) token_network_identifier = first_payer_transfer.balance_proof.token_network_identifier assert search_for_item( iteration.events, SendRefundTransfer, { "recipient": setup.channels.partner_address(0), "queue_identifier": { "recipient": setup.channels.partner_address(0), "channel_identifier": first_payer_transfer.balance_proof.channel_identifier, }, "transfer": { "payment_identifier": UNIT_TRANSFER_IDENTIFIER, "token": UNIT_TOKEN_ADDRESS, "balance_proof": { "transferred_amount": 0, "locked_amount": 10, "locksroot": lock.lockhash, "token_network_identifier": token_network_identifier, "channel_identifier": first_payer_transfer.balance_proof.channel_identifier, "chain_id": first_payer_transfer.balance_proof.chain_id, }, "lock": { "amount": lock.amount, "expiration": lock.expiration, "secrethash": lock.secrethash, }, "initiator": UNIT_TRANSFER_INITIATOR, "target": UNIT_TRANSFER_TARGET, }, }, ) duplicate_iteration = mediator.handle_refundtransfer( mediator_state=iteration.new_state, mediator_state_change=refund_state_change, channelidentifiers_to_channels=setup.channel_map, nodeaddresses_to_networkstates=setup.channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=setup.block_number, ) assert search_for_item(duplicate_iteration.events, SendRefundTransfer, {}) is None assert duplicate_iteration.new_state is not None assert duplicate_iteration.new_state == iteration.new_state
from raiden.transfer.mediated_transfer.state_change import ( ActionInitMediator, ReceiveLockExpired, ReceiveSecretReveal, ReceiveTransferRefund, ) from raiden.transfer.state import ( NODE_NETWORK_UNREACHABLE, balanceproof_from_envelope, message_identifier_from_prng, ) from raiden.transfer.state_change import Block, ContractReceiveSecretReveal from raiden.utils.signer import LocalSigner LONG_EXPIRATION = factories.create_properties( factories.LockedTransferSignedStateProperties( transfer=factories.LockedTransferProperties(expiration=30), )) 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()
SendRefundTransfer, ) from raiden.transfer.mediated_transfer.state import MediatorTransferState from raiden.transfer.mediated_transfer.state_change import ( ActionInitMediator, ReceiveLockExpired, ReceiveSecretReveal, ReceiveTransferRefund, ) from raiden.transfer.state import NetworkState, message_identifier_from_prng from raiden.transfer.state_change import Block, ContractReceiveSecretReveal from raiden.utils.signer import LocalSigner from raiden.utils.typing import BlockExpiration LONG_EXPIRATION = factories.create_properties( factories.LockedTransferSignedStateProperties( expiration=BlockExpiration(30))) 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()
def test_invalid_instantiation_action_init_initiator(): wrong_type_transfer = factories.create(factories.LockedTransferSignedStateProperties()) with pytest.raises(ValueError): ActionInitInitiator(transfer=wrong_type_transfer, routes=list())
def test_initiator_skips_used_routes(): defaults = factories.NettingChannelStateProperties( our_state=factories.NettingChannelEndStateProperties.OUR_STATE, partner_state=factories.NettingChannelEndStateProperties(balance=10), open_transaction=factories.TransactionExecutionStatusProperties( started_block_number=1, finished_block_number=2, result="success"), ) properties = [ factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( privatekey=factories.HOP1_KEY, address=factories.HOP1)) ] test_chain_state = factories.make_chain_state(number_of_channels=1, properties=properties, defaults=defaults) channels = test_chain_state.channel_set bob = channels.channels[0].partner_state.address routes = [[ factories.UNIT_OUR_ADDRESS, bob, factories.UNIT_TRANSFER_TARGET ]] transfer = factories.create( factories.TransferDescriptionProperties( initiator=factories.UNIT_OUR_ADDRESS, target=factories.UNIT_TRANSFER_TARGET)) init_action = factories.initiator_make_init_action( channels=channels, routes=routes, transfer=transfer, estimated_fee=FeeAmount(0)) transition_result = handle_action_init_initiator( chain_state=test_chain_state.chain_state, state_change=init_action) chain_state = transition_result.new_state assert transfer.secrethash in chain_state.payment_mapping.secrethashes_to_task initiator_task = chain_state.payment_mapping.secrethashes_to_task[ transfer.secrethash] initiator_state = initiator_task.manager_state assert len(initiator_state.routes) == 1, "Should have one route" assert len( initiator_state.routes[0].route) == 3, "Route should not be pruned" assert initiator_state.routes[0].route == routes[ 0], "Should have test route" events = transition_result.events assert isinstance(events[-1], SendLockedTransfer) locked_transfer = initiator_state.initiator_transfers[ transfer.secrethash].transfer received_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=locked_transfer.lock.expiration, payment_identifier=locked_transfer.payment_identifier, canonical_identifier=locked_transfer.balance_proof. canonical_identifier, initiator=factories.UNIT_OUR_ADDRESS, sender=bob, pkey=factories.HOP1_KEY, message_identifier=factories.make_message_identifier(), routes=[], secret=transfer.secret, )) role = views.get_transfer_role(chain_state=chain_state, secrethash=locked_transfer.lock.secrethash) assert role == "initiator", "Should keep initiator role" failed_route_state_change = ReceiveTransferCancelRoute( transfer=received_transfer, balance_proof=received_transfer.balance_proof, sender=received_transfer.balance_proof.sender, # pylint: disable=no-member ) state_transition(chain_state=chain_state, state_change=failed_route_state_change) reroute_state_change = ActionTransferReroute( transfer=received_transfer, balance_proof=received_transfer.balance_proof, sender=received_transfer.balance_proof.sender, # pylint: disable=no-member secret=factories.make_secret(), ) iteration = state_transition(chain_state=chain_state, state_change=reroute_state_change) assert search_for_item(iteration.events, SendLockedTransfer, {}) is None
def test_mediator_skips_used_routes(): prng = random.Random() block_number = 3 defaults = factories.NettingChannelStateProperties( our_state=factories.NettingChannelEndStateProperties.OUR_STATE, partner_state=factories.NettingChannelEndStateProperties( balance=UNIT_TRANSFER_AMOUNT), open_transaction=factories.TransactionExecutionStatusProperties( started_block_number=1, finished_block_number=2, result="success"), ) properties = [ factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( privatekey=factories.HOP1_KEY, address=factories.HOP1)), factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( privatekey=factories.HOP2_KEY, address=factories.HOP2)), factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( privatekey=factories.HOP3_KEY, address=factories.HOP3)), ] channels = factories.make_channel_set(properties=properties, number_of_channels=3, defaults=defaults) bob = channels.channels[1].partner_state.address charlie = channels.channels[2].partner_state.address dave = factories.make_address() eric = factories.make_address() locked_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=10, routes=[ [ factories.UNIT_OUR_ADDRESS, bob, dave, factories.UNIT_TRANSFER_TARGET ], [ factories.UNIT_OUR_ADDRESS, bob, eric, factories.UNIT_TRANSFER_TARGET ], [ factories.UNIT_OUR_ADDRESS, charlie, eric, factories.UNIT_TRANSFER_TARGET ], ], canonical_identifier=channels.channels[0].canonical_identifier, pkey=factories.HOP1_KEY, sender=factories.HOP1, )) init_action = factories.mediator_make_init_action(channels=channels, transfer=locked_transfer) nodeaddresses_to_networkstates = { channel.partner_state.address: NetworkState.REACHABLE for channel in channels.channels } transition_result = mediator.handle_init( state_change=init_action, channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=nodeaddresses_to_networkstates, pseudo_random_generator=prng, block_number=block_number, ) mediator_state = transition_result.new_state events = transition_result.events assert mediator_state is not None assert events assert len(mediator_state.routes) == 3 assert mediator_state.routes[0].route[1] == bob assert mediator_state.routes[1].route[1] == bob assert mediator_state.routes[2].route[1] == charlie # now we receive a refund from whoever we forwarded to (should be HOP2) assert isinstance(events[-1], SendLockedTransfer) assert events[-1].recipient == factories.HOP2 last_pair = mediator_state.transfers_pair[-1] canonical_identifier = last_pair.payee_transfer.balance_proof.canonical_identifier lock_expiration = last_pair.payee_transfer.lock.expiration payment_identifier = last_pair.payee_transfer.payment_identifier received_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=lock_expiration, payment_identifier=payment_identifier, canonical_identifier=canonical_identifier, sender=factories.HOP2, pkey=factories.HOP2_KEY, message_identifier=factories.make_message_identifier(), )) refund_state_change = ReceiveTransferRefund( transfer=received_transfer, balance_proof=received_transfer.balance_proof, sender=received_transfer.balance_proof.sender, # pylint: disable=no-member ) transition_result = mediator.handle_refundtransfer( mediator_state=mediator_state, mediator_state_change=refund_state_change, channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=nodeaddresses_to_networkstates, pseudo_random_generator=prng, block_number=block_number, ) mediator_state = transition_result.new_state events = transition_result.events assert mediator_state is not None assert events assert mediator_state.transfers_pair[-1].payee_address == charlie # now we should have a forward transfer to HOP3 assert isinstance(events[-1], SendLockedTransfer) assert events[-1].recipient == factories.HOP3 # now we will receive a refund from HOP3 last_pair = mediator_state.transfers_pair[-1] canonical_identifier = last_pair.payee_transfer.balance_proof.canonical_identifier lock_expiration = last_pair.payee_transfer.lock.expiration payment_identifier = last_pair.payee_transfer.payment_identifier received_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=lock_expiration, payment_identifier=payment_identifier, canonical_identifier=canonical_identifier, sender=factories.HOP3, pkey=factories.HOP3_KEY, message_identifier=factories.make_message_identifier(), )) refund_state_change = ReceiveTransferRefund( transfer=received_transfer, balance_proof=received_transfer.balance_proof, sender=received_transfer.balance_proof.sender, # pylint: disable=no-member ) transition_result = mediator.handle_refundtransfer( mediator_state=mediator_state, mediator_state_change=refund_state_change, channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=nodeaddresses_to_networkstates, pseudo_random_generator=prng, block_number=block_number, ) mediator_state = transition_result.new_state events = transition_result.events assert mediator_state is not None assert events # no other routes available, so refund HOP1 assert isinstance(events[-1], SendRefundTransfer) assert events[-1].recipient == factories.HOP1
SendLockedTransfer, SendLockExpired, SendRefundTransfer, ) from raiden.transfer.mediated_transfer.state import MediatorTransferState from raiden.transfer.mediated_transfer.state_change import ( ActionInitMediator, ReceiveLockExpired, ReceiveSecretReveal, ReceiveTransferRefund, ) from raiden.transfer.state import balanceproof_from_envelope, message_identifier_from_prng from raiden.transfer.state_change import Block, ContractReceiveSecretReveal LONG_EXPIRATION = factories.create_properties(factories.LockedTransferSignedStateProperties( transfer=factories.LockedTransferProperties(expiration=30), )) 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()