def claim_lock(app_chain, identifier, token, secret): """ Unlock a pending transfer. """ secrethash = sha3(secret) for from_, to_ in zip(app_chain[:-1], app_chain[1:]): from_channel = get_channelstate(from_, to_, token) partner_channel = get_channelstate(to_, from_, token) unlock_lock = channel.send_unlock( from_channel, identifier, secret, secrethash, ) secret_message = Secret( unlock_lock.identifier, unlock_lock.balance_proof.nonce, unlock_lock.balance_proof.channel_address, unlock_lock.balance_proof.transferred_amount, unlock_lock.balance_proof.locksroot, unlock_lock.secret, ) from_.raiden.sign(secret_message) balance_proof = balanceproof_from_envelope(secret_message) receive_unlock = ReceiveUnlock( unlock_lock.secret, balance_proof, ) is_valid, msg = channel.handle_unlock( partner_channel, receive_unlock, ) assert is_valid, msg
def handle_message_secret(raiden: 'RaidenService', message: Secret): balance_proof = balanceproof_from_envelope(message) state_change = ReceiveUnlock( message.secret, balance_proof, ) raiden.handle_state_change(state_change)
def handle_message_secret(self, raiden: RaidenService, message: Secret): balance_proof = balanceproof_from_envelope(message) state_change = ReceiveUnlock( message_identifier=message.message_identifier, secret=message.secret, balance_proof=balance_proof, ) raiden.handle_state_change(state_change)
def handle_message_unlock(raiden: RaidenService, message: Unlock) -> None: balance_proof = balanceproof_from_envelope(message) state_change = ReceiveUnlock( message_identifier=message.message_identifier, secret=message.secret, balance_proof=balance_proof, ) raiden.handle_and_track_state_change(state_change)
def handle_message_unlock( raiden: "RaidenService", message: Unlock # pylint: disable=unused-argument ) -> List[StateChange]: balance_proof = balanceproof_from_envelope(message) unlock = ReceiveUnlock( message_identifier=message.message_identifier, secret=message.secret, balance_proof=balance_proof, sender=balance_proof.sender, ) return [unlock]
def send_unlock_to_receive_unlock( source: SendUnlockInNode, canonical_identifier: CanonicalIdentifier) -> ReceiveUnlock: mirrored_balance_proof = replace(source.event.balance_proof, canonical_identifier=canonical_identifier) signed_balance_proof = factories.make_signed_balance_proof_from_unsigned( unsigned=mirrored_balance_proof, signer=LocalSigner(source.private_key)) return ReceiveUnlock( sender=source.node, message_identifier=source.event.message_identifier, secret=source.event.secret, secrethash=source.event.secrethash, balance_proof=signed_balance_proof, )
def handle_message_unlock(raiden: RaidenService, message: Unlock, is_light_client=False) -> None: balance_proof = balanceproof_from_envelope(message) if is_light_client: state_change = ReceiveUnlockLight( message_identifier=message.message_identifier, secret=message.secret, balance_proof=balance_proof, signed_unlock=message) raiden.handle_and_track_state_change(state_change) else: state_change = ReceiveUnlock( message_identifier=message.message_identifier, secret=message.secret, balance_proof=balance_proof, ) raiden.handle_and_track_state_change(state_change)
def claim_lock(app_chain, payment_identifier, token_network_identifier, secret): """ Unlock a pending transfer. """ secrethash = sha3(secret) for from_, to_ in zip(app_chain[:-1], app_chain[1:]): from_channel = get_channelstate(from_, to_, token_network_identifier) partner_channel = get_channelstate(to_, from_, token_network_identifier) unlock_lock = channel.send_unlock( from_channel, random.randint(0, UINT64_MAX), payment_identifier, secret, secrethash, ) secret_message = Secret( chain_id=unlock_lock.balance_proof.chain_id, message_identifier=unlock_lock.message_identifier, payment_identifier=unlock_lock.payment_identifier, nonce=unlock_lock.balance_proof.nonce, token_network_address=partner_channel.token_network_identifier, channel_identifier=unlock_lock.balance_proof.channel_identifier, transferred_amount=unlock_lock.balance_proof.transferred_amount, locked_amount=unlock_lock.balance_proof.locked_amount, locksroot=unlock_lock.balance_proof.locksroot, secret=unlock_lock.secret, ) from_.raiden.sign(secret_message) balance_proof = balanceproof_from_envelope(secret_message) receive_unlock = ReceiveUnlock( message_identifier=random.randint(0, UINT64_MAX), secret=unlock_lock.secret, balance_proof=balance_proof, ) is_valid, _, msg = channel.handle_unlock( partner_channel, receive_unlock, ) assert is_valid, msg
def test_interwoven_transfers(): """Can keep doing transactions even if not all secrets have been released.""" number_of_transfers = 100 balance_for_all_transfers = 11 * number_of_transfers lock_amounts = cycle([1, 3, 5, 7, 11]) lock_secrets = [ format(i, '>032').encode() for i in range(number_of_transfers) ] our_model, _ = create_model(70) partner_model, privkey2 = create_model(balance_for_all_transfers) channel_state = create_channel_from_models(our_model, partner_model) block_number = 1000 nonce = 0 transferred_amount = 0 our_model_current = our_model partner_model_current = partner_model for i, (lock_amount, lock_secret) in enumerate(zip(lock_amounts, lock_secrets)): nonce += 1 block_number += 1 lock_expiration = block_number + channel_state.settle_timeout - 1 lock_secrethash = sha3(lock_secret) lock = HashTimeLockState( lock_amount, lock_expiration, lock_secrethash, ) merkletree_leaves = list(partner_model_current.merkletree_leaves) merkletree_leaves.append(lock.lockhash) partner_model_current = partner_model_current._replace( distributable=partner_model_current.distributable - lock_amount, amount_locked=partner_model_current.amount_locked + lock_amount, next_nonce=partner_model_current.next_nonce + 1, merkletree_leaves=merkletree_leaves, ) receive_lockedtransfer = make_receive_transfer_mediated( channel_state, privkey2, nonce, transferred_amount, lock, merkletree_leaves=merkletree_leaves, ) is_valid, msg = channel.handle_receive_lockedtransfer( channel_state, receive_lockedtransfer, ) assert is_valid, msg assert_partner_state( channel_state.our_state, channel_state.partner_state, our_model_current, ) assert_partner_state( channel_state.partner_state, channel_state.our_state, partner_model_current, ) # claim a transaction at every other iteration, leaving the current one # in place if i % 2: # Update our model: # - Increase nonce because the secret is a new balance proof # - The lock is removed from the merkle tree, the balance proof must be updated # - The locksroot must have unlocked lock removed # - The transferred amount must be increased by the lock amount # - This changes the balance for both participants: # - the sender balance and locked amount is decremented by the lock amount # - the receiver balance and distributable is incremented by the lock amount nonce += 1 transferred_amount += lock_amount merkletree_leaves = list(partner_model_current.merkletree_leaves) merkletree_leaves.remove(lock.lockhash) tree = compute_layers(merkletree_leaves) locksroot = tree[MERKLEROOT][0] partner_model_current = partner_model_current._replace( amount_locked=partner_model_current.amount_locked - lock_amount, balance=partner_model_current.balance - lock_amount, next_nonce=partner_model_current.next_nonce + 1, merkletree_leaves=merkletree_leaves, ) our_model_current = our_model_current._replace( balance=our_model_current.balance + lock_amount, distributable=our_model_current.distributable + lock_amount, ) message_identifier = random.randint(0, UINT64_MAX) secret_message = Secret( message_identifier=message_identifier, payment_identifier=nonce, nonce=nonce, channel=channel_state.identifier, transferred_amount=transferred_amount, locksroot=locksroot, secret=lock_secret, ) secret_message.sign(privkey2, channel_state.partner_state.address) balance_proof = balanceproof_from_envelope(secret_message) unlock_state_change = ReceiveUnlock( lock_secret, balance_proof, ) is_valid, msg = channel.handle_unlock(channel_state, unlock_state_change) assert is_valid, msg assert_partner_state( channel_state.our_state, channel_state.partner_state, our_model_current, ) assert_partner_state( channel_state.partner_state, channel_state.our_state, partner_model_current, )
def test_channelstate_receive_lockedtransfer(): """Tests receiving a mediated transfer. The transfer is done in three steps: - a mediated transfer including a lock in its balance proof is sent - the secret is revealed - the unlocked balance proof is sent updating the transferred_amount """ our_model1, _ = create_model(70) partner_model1, privkey2 = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) # Step 1: Simulate receiving a transfer # - The receiver end state doesnt change # - The lock must be registered with the sender end lock_amount = 30 lock_expiration = 10 lock_secret = sha3(b'test_end_state') lock_secrethash = sha3(lock_secret) lock = HashTimeLockState( lock_amount, lock_expiration, lock_secrethash, ) nonce = 1 transferred_amount = 0 receive_lockedtransfer = make_receive_transfer_mediated( channel_state, privkey2, nonce, transferred_amount, lock, ) is_valid, msg = channel.handle_receive_lockedtransfer( channel_state, receive_lockedtransfer, ) assert is_valid, msg our_model2 = our_model1 partner_model2 = partner_model1._replace( distributable=partner_model1.distributable - lock_amount, amount_locked=lock_amount, next_nonce=2, merkletree_leaves=[lock.lockhash], ) assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model2) assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model2) # Step 2: Simulate learning the secret # - Registers the secret, this must not change the balance/locked amount channel.register_secret(channel_state, lock_secret, lock_secrethash) assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model2) assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model2) # Step 3: Simulate unlocking the lock # - Update the balances transferred_amount = 0 message_identifier = random.randint(0, UINT64_MAX) secret_message = Secret( message_identifier=message_identifier, payment_identifier=1, nonce=2, channel=channel_state.identifier, transferred_amount=transferred_amount + lock_amount, locksroot=EMPTY_MERKLE_ROOT, secret=lock_secret, ) secret_message.sign(privkey2, channel_state.partner_state.address) balance_proof = balanceproof_from_envelope(secret_message) unlock_state_change = ReceiveUnlock( lock_secret, balance_proof, ) is_valid, msg = channel.handle_unlock(channel_state, unlock_state_change) assert is_valid, msg our_model3 = our_model2._replace( balance=our_model2.balance + lock_amount, distributable=our_model2.balance + lock_amount, ) partner_model3 = partner_model2._replace( balance=partner_model2.balance - lock_amount, amount_locked=0, next_nonce=3, merkletree_leaves=[], ) assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model3) assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model3)
def test_state_transition(): """ Happy case testing. """ lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) from_transfer = make_target_transfer(channels[0], amount=lock_amount, initiator=initiator) init = ActionInitTarget(channels.get_route(0), 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 not None assert init_transition.new_state.route == channels.get_route(0) assert init_transition.new_state.transfer == from_transfer first_new_block = Block( block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) first_block_iteration = target.state_transition( target_state=init_transition.new_state, state_change=first_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition( target_state=first_block_iteration.new_state, state_change=secret_reveal, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) assert reveal_iteration.events second_new_block = Block( block_number=block_number + 2, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=init_transition.new_state, state_change=second_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=second_new_block.block_number, ) assert not iteration.events balance_proof = create( BalanceProofSignedStateProperties( balance_proof=BalanceProofProperties( nonce=from_transfer.balance_proof.nonce + 1, transferred_amount=lock_amount, locked_amount=0, token_network_identifier=channels[0].token_network_identifier, channel_identifier=channels.get_route(0).channel_identifier, locksroot=EMPTY_MERKLE_ROOT, ), message_hash=b'\x00' * 32, # invalid )) balance_proof_state_change = ReceiveUnlock( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, balance_proof=balance_proof, ) proof_iteration = target.state_transition( target_state=init_transition.new_state, state_change=balance_proof_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number + 2, ) assert proof_iteration.new_state is None
def test_state_transition(): """ Happy case testing. """ lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() our_balance = 100 our_address = factories.make_address() partner_balance = 130 from_channel = factories.make_channel( our_address=our_address, our_balance=our_balance, partner_address=UNIT_TRANSFER_SENDER, partner_balance=partner_balance, ) from_route = factories.route_from_channel(from_channel) expiration = block_number + from_channel.settle_timeout from_transfer = factories.make_signed_transfer_for( from_channel, lock_amount, initiator, our_address, expiration, UNIT_SECRET, ) init = ActionInitTarget( from_route, from_transfer, ) init_transition = target.state_transition( None, init, from_channel, pseudo_random_generator, block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == from_route assert init_transition.new_state.transfer == from_transfer first_new_block = Block(block_number + 1) first_block_iteration = target.state_transition( init_transition.new_state, first_new_block, from_channel, pseudo_random_generator, first_new_block.block_number, ) secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition( first_block_iteration.new_state, secret_reveal, from_channel, pseudo_random_generator, first_new_block, ) assert reveal_iteration.events second_new_block = Block(block_number + 2) iteration = target.state_transition( init_transition.new_state, second_new_block, from_channel, pseudo_random_generator, second_new_block.block_number, ) assert not iteration.events nonce = from_transfer.balance_proof.nonce + 1 transferred_amount = lock_amount locksroot = EMPTY_MERKLE_ROOT invalid_message_hash = b'\x00' * 32 locked_amount = 0 balance_proof = factories.make_signed_balance_proof( nonce, transferred_amount, locked_amount, from_channel.token_network_identifier, from_route.channel_identifier, locksroot, invalid_message_hash, UNIT_TRANSFER_PKEY, UNIT_TRANSFER_SENDER, ) balance_proof_state_change = ReceiveUnlock( random.randint(0, UINT64_MAX), UNIT_SECRET, balance_proof, ) proof_iteration = target.state_transition( init_transition.new_state, balance_proof_state_change, from_channel, pseudo_random_generator, block_number + 2, ) assert proof_iteration.new_state is None
def test_message_handler(): """ Test for MessageHandler.on_message and the different methods it dispatches into. Each of them results in a call to a RaidenService method, which is checked with a Mock. """ our_address = factories.make_address() sender_privkey, sender = factories.make_privkey_address() signer = LocalSigner(sender_privkey) message_handler = MessageHandler() mock_raiden = Mock( address=our_address, default_secret_registry=Mock(is_secret_registered=lambda **_: False) ) properties = factories.LockedTransferProperties(sender=sender, pkey=sender_privkey) locked_transfer = factories.create(properties) message_handler.on_message(mock_raiden, locked_transfer) assert_method_call(mock_raiden, "mediate_mediated_transfer", locked_transfer) locked_transfer_for_us = factories.create(factories.replace(properties, target=our_address)) message_handler.on_message(mock_raiden, locked_transfer_for_us) assert_method_call(mock_raiden, "target_mediated_transfer", locked_transfer_for_us) mock_raiden.default_secret_registry.is_secret_registered = lambda **_: True message_handler.on_message(mock_raiden, locked_transfer) assert not mock_raiden.mediate_mediated_transfer.called assert not mock_raiden.target_mediated_transfer.called mock_raiden.default_secret_registry.is_secret_registered = lambda **_: False params = dict( payment_identifier=13, amount=14, expiration=15, secrethash=factories.UNIT_SECRETHASH ) secret_request = SecretRequest( message_identifier=16, signature=factories.EMPTY_SIGNATURE, **params ) secret_request.sign(signer) receive = ReceiveSecretRequest(sender=sender, **params) message_handler.on_message(mock_raiden, secret_request) assert_method_call(mock_raiden, "handle_and_track_state_changes", [receive]) secret = factories.make_secret() reveal_secret = RevealSecret( message_identifier=100, signature=factories.EMPTY_SIGNATURE, secret=secret ) reveal_secret.sign(signer) receive = ReceiveSecretReveal(sender=sender, secret=secret) message_handler.on_message(mock_raiden, reveal_secret) assert_method_call(mock_raiden, "handle_and_track_state_changes", [receive]) properties: factories.UnlockProperties = factories.create_properties( factories.UnlockProperties() ) unlock = factories.create(properties) unlock.sign(signer) balance_proof = factories.make_signed_balance_proof_from_unsigned( factories.create(properties.balance_proof), signer, unlock.message_hash ) receive = ReceiveUnlock( message_identifier=properties.message_identifier, secret=properties.secret, balance_proof=balance_proof, sender=sender, ) message_handler.on_message(mock_raiden, unlock) assert_method_call(mock_raiden, "handle_and_track_state_changes", [receive]) properties: factories.LockExpiredProperties = factories.create_properties( factories.LockExpiredProperties() ) lock_expired = factories.create(properties) lock_expired.sign(signer) balance_proof = factories.make_signed_balance_proof_from_unsigned( factories.create(properties.balance_proof), signer, lock_expired.message_hash ) receive = ReceiveLockExpired( balance_proof=balance_proof, message_identifier=properties.message_identifier, secrethash=properties.secrethash, # pylint: disable=no-member sender=sender, ) message_handler.on_message(mock_raiden, lock_expired) assert_method_call(mock_raiden, "handle_and_track_state_changes", [receive]) delivered = Delivered(delivered_message_identifier=1, signature=factories.EMPTY_SIGNATURE) delivered.sign(signer) receive = ReceiveDelivered(message_identifier=1, sender=sender) message_handler.on_message(mock_raiden, delivered) assert_method_call(mock_raiden, "handle_and_track_state_changes", [receive]) processed = Processed(message_identifier=42, signature=factories.EMPTY_SIGNATURE) processed.sign(signer) receive = ReceiveProcessed(message_identifier=42, sender=sender) message_handler.on_message(mock_raiden, processed) assert_method_call(mock_raiden, "handle_and_track_state_changes", [receive])
def test_state_transition(): """ Happy case testing. """ lock_amount = 7 block_number = 1 initiator = factories.make_address() pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) from_transfer = make_target_transfer(channels[0], amount=lock_amount, initiator=initiator) 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 is not None assert init_transition.new_state.from_hop == channels.get_hop(0) assert init_transition.new_state.transfer == from_transfer first_new_block = Block(block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash()) first_block_iteration = target.state_transition( target_state=init_transition.new_state, state_change=first_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) secret_reveal = ReceiveSecretReveal(secret=UNIT_SECRET, sender=initiator) reveal_iteration = target.state_transition( target_state=first_block_iteration.new_state, state_change=secret_reveal, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) assert reveal_iteration.events second_new_block = Block(block_number=block_number + 2, gas_limit=1, block_hash=factories.make_transaction_hash()) iteration = target.state_transition( target_state=init_transition.new_state, state_change=second_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=second_new_block.block_number, ) assert not iteration.events balance_proof = create( BalanceProofSignedStateProperties( nonce=from_transfer.balance_proof.nonce + 1, # pylint: disable=no-member transferred_amount=lock_amount, locked_amount=0, canonical_identifier=factories.make_canonical_identifier( token_network_address=channels[0].token_network_address, channel_identifier=channels.get_hop(0).channel_identifier, ), locksroot=LOCKSROOT_OF_NO_LOCKS, message_hash=b"\x00" * 32, # invalid )) balance_proof_state_change = ReceiveUnlock( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, balance_proof=balance_proof, sender=balance_proof.sender, # pylint: disable=no-member ) proof_iteration = target.state_transition( target_state=init_transition.new_state, state_change=balance_proof_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number + 2, ) assert proof_iteration.new_state is None
def test_get_state_change_with_balance_proof(): """ All state changes which contain a balance proof must be found by when querying the database. """ serializer = JSONSerializer storage = SerializedSQLiteStorage(":memory:", serializer) counter = itertools.count() lock_expired = ReceiveLockExpired( balance_proof=make_signed_balance_proof_from_counter(counter), secrethash=sha3(factories.make_secret(next(counter))), message_identifier=next(counter), ) unlock = ReceiveUnlock( message_identifier=next(counter), secret=sha3(factories.make_secret(next(counter))), balance_proof=make_signed_balance_proof_from_counter(counter), ) transfer_refund = ReceiveTransferRefund( transfer=make_signed_transfer_from_counter(counter), routes=list()) transfer_refund_cancel_route = ReceiveTransferRefundCancelRoute( routes=list(), transfer=make_signed_transfer_from_counter(counter), secret=sha3(factories.make_secret(next(counter))), ) mediator_from_route, mediator_signed_transfer = make_from_route_from_counter( counter) action_init_mediator = ActionInitMediator( routes=list(), from_route=mediator_from_route, from_transfer=mediator_signed_transfer) target_from_route, target_signed_transfer = make_from_route_from_counter( counter) action_init_target = ActionInitTarget(route=target_from_route, transfer=target_signed_transfer) statechanges_balanceproofs = [ (lock_expired, lock_expired.balance_proof), (unlock, unlock.balance_proof), (transfer_refund, transfer_refund.transfer.balance_proof), (transfer_refund_cancel_route, transfer_refund_cancel_route.transfer.balance_proof), (action_init_mediator, action_init_mediator.from_transfer.balance_proof), (action_init_target, action_init_target.transfer.balance_proof), ] timestamp = datetime.utcnow().isoformat(timespec="milliseconds") for state_change, _ in statechanges_balanceproofs: storage.write_state_change(state_change, timestamp) # Make sure state changes are returned in the correct order in which they were stored stored_statechanges = storage.get_statechanges_by_identifier(1, "latest") assert isinstance(stored_statechanges[0], ReceiveLockExpired) assert isinstance(stored_statechanges[1], ReceiveUnlock) assert isinstance(stored_statechanges[2], ReceiveTransferRefund) assert isinstance(stored_statechanges[3], ReceiveTransferRefundCancelRoute) assert isinstance(stored_statechanges[4], ActionInitMediator) assert isinstance(stored_statechanges[5], ActionInitTarget) # Make sure state changes are returned in the correct order in which they were stored stored_statechanges = storage.get_statechanges_by_identifier(1, 2) assert isinstance(stored_statechanges[0], ReceiveLockExpired) assert isinstance(stored_statechanges[1], ReceiveUnlock) for state_change, balance_proof in statechanges_balanceproofs: state_change_record = get_state_change_with_balance_proof_by_balance_hash( storage=storage, canonical_identifier=balance_proof.canonical_identifier, sender=balance_proof.sender, balance_hash=balance_proof.balance_hash, ) assert state_change_record.data == state_change
def test_get_state_change_with_balance_proof(): """ All state changes which contain a balance proof must be found by when querying the database. """ serializer = JSONSerializer storage = SQLiteStorage(':memory:', serializer) counter = itertools.count() lock_expired = ReceiveLockExpired( balance_proof=make_signed_balance_proof_from_counter(counter), secrethash=sha3(factories.make_secret(next(counter))), message_identifier=next(counter), ) unlock = ReceiveUnlock( message_identifier=next(counter), secret=sha3(factories.make_secret(next(counter))), balance_proof=make_signed_balance_proof_from_counter(counter), ) transfer_refund = ReceiveTransferRefund( transfer=make_signed_transfer_from_counter(counter), routes=list(), ) transfer_refund_cancel_route = ReceiveTransferRefundCancelRoute( routes=list(), transfer=make_signed_transfer_from_counter(counter), secret=sha3(factories.make_secret(next(counter))), ) mediator_from_route, mediator_signed_transfer = make_from_route_from_counter( counter) action_init_mediator = ActionInitMediator( routes=list(), from_route=mediator_from_route, from_transfer=mediator_signed_transfer, ) target_from_route, target_signed_transfer = make_from_route_from_counter( counter) action_init_target = ActionInitTarget( route=target_from_route, transfer=target_signed_transfer, ) statechanges_balanceproofs = [ (lock_expired, lock_expired.balance_proof), (unlock, unlock.balance_proof), (transfer_refund, transfer_refund.transfer.balance_proof), (transfer_refund_cancel_route, transfer_refund_cancel_route.transfer.balance_proof), (action_init_mediator, action_init_mediator.from_transfer.balance_proof), (action_init_target, action_init_target.transfer.balance_proof), ] timestamp = datetime.utcnow().isoformat(timespec='milliseconds') for state_change, _ in statechanges_balanceproofs: storage.write_state_change(state_change, timestamp) for state_change, balance_proof in statechanges_balanceproofs: state_change_record = get_state_change_with_balance_proof( storage=storage, chain_id=balance_proof.chain_id, token_network_identifier=balance_proof.token_network_identifier, channel_identifier=balance_proof.channel_identifier, sender=balance_proof.sender, balance_hash=balance_proof.balance_hash, ) assert state_change_record.data == state_change
def test_get_state_change_with_balance_proof(): """ All state changes which contain a balance proof must be found when querying the database. """ serializer = JSONSerializer() storage = SerializedSQLiteStorage(":memory:", serializer) counter = itertools.count() balance_proof = make_signed_balance_proof_from_counter(counter) lock_expired = ReceiveLockExpired( sender=balance_proof.sender, balance_proof=balance_proof, secrethash=factories.make_secret_hash(next(counter)), message_identifier=MessageID(next(counter)), ) received_balance_proof = make_signed_balance_proof_from_counter(counter) unlock = ReceiveUnlock( sender=received_balance_proof.sender, message_identifier=MessageID(next(counter)), secret=factories.make_secret(next(counter)), balance_proof=received_balance_proof, ) transfer = make_signed_transfer_from_counter(counter) transfer_refund = ReceiveTransferRefund( transfer=transfer, balance_proof=transfer.balance_proof, sender=transfer.balance_proof.sender, # pylint: disable=no-member ) transfer = make_signed_transfer_from_counter(counter) transfer_reroute = ActionTransferReroute( transfer=transfer, balance_proof=transfer.balance_proof, sender=transfer.balance_proof.sender, # pylint: disable=no-member secret=sha3(factories.make_secret(next(counter))), ) mediator_from_route, mediator_signed_transfer = make_from_route_from_counter( counter) action_init_mediator = ActionInitMediator( route_states=[ RouteState( route=[factories.make_address(), factories.make_address()], forward_channel_id=factories.make_channel_identifier(), ) ], from_hop=mediator_from_route, from_transfer=mediator_signed_transfer, balance_proof=mediator_signed_transfer.balance_proof, sender=mediator_signed_transfer.balance_proof.sender, # pylint: disable=no-member ) target_from_route, target_signed_transfer = make_from_route_from_counter( counter) action_init_target = ActionInitTarget( from_hop=target_from_route, transfer=target_signed_transfer, balance_proof=target_signed_transfer.balance_proof, sender=target_signed_transfer.balance_proof.sender, # pylint: disable=no-member ) statechanges_balanceproofs = [ (lock_expired, lock_expired.balance_proof), (unlock, unlock.balance_proof), (transfer_refund, transfer_refund.transfer.balance_proof), (transfer_reroute, transfer_reroute.transfer.balance_proof), (action_init_mediator, action_init_mediator.from_transfer.balance_proof), (action_init_target, action_init_target.transfer.balance_proof), ] assert storage.count_state_changes() == 0 state_change_ids = storage.write_state_changes( [state_change for state_change, _ in statechanges_balanceproofs]) assert storage.count_state_changes() == len(statechanges_balanceproofs) msg_in_order = "Querying must return state changes in order" stored_statechanges_records = storage.get_statechanges_records_by_range( RANGE_ALL_STATE_CHANGES) assert len(stored_statechanges_records) == 6, msg_in_order pair_elements = zip(statechanges_balanceproofs, state_change_ids, stored_statechanges_records) for statechange_balanceproof, statechange_id, record in pair_elements: assert record.data == statechange_balanceproof[0], msg_in_order assert record.state_change_identifier == statechange_id, msg_in_order # Make sure state changes are returned in the correct order in which they were stored stored_statechanges = storage.get_statechanges_by_range( Range( stored_statechanges_records[1].state_change_identifier, stored_statechanges_records[2].state_change_identifier, )) assert len(stored_statechanges) == 2 assert isinstance(stored_statechanges[0], ReceiveUnlock) assert isinstance(stored_statechanges[1], ReceiveTransferRefund) for state_change, balance_proof in statechanges_balanceproofs: state_change_record = get_state_change_with_balance_proof_by_balance_hash( storage=storage, canonical_identifier=balance_proof.canonical_identifier, sender=balance_proof.sender, balance_hash=balance_proof.balance_hash, ) assert state_change_record assert state_change_record.data == state_change state_change_record = get_state_change_with_balance_proof_by_locksroot( storage=storage, canonical_identifier=balance_proof.canonical_identifier, sender=balance_proof.sender, locksroot=balance_proof.locksroot, ) assert state_change_record assert state_change_record.data == state_change storage.close()
def test_pfs_send_unique_capacity_and_fee_updates_during_mediated_transfer( raiden_network): """ Tests that PFSCapacityUpdates and PFSFeeUpdates are being sent only once with the most recent state change in a batch. """ app0, app1 = raiden_network chain_state = views.state_from_app(app0) # There have been two PFSCapacityUpdates and two PFSFeeUpdates per channel per node assert len(get_messages(app0)) == 4 # The mediator has two channels assert len(get_messages(app1)) == 4 # Now we create two state_changes (Deposit) regarding the same channel # and trigger handle_state_changes() of node0. The expected outcome # is that only 1 PFSCapacityUpdate and 1 PFSFeeUpdate is being sent # not one per state change pfs_fee_update_1_of_app0 = get_messages(app0)[1] assert isinstance(pfs_fee_update_1_of_app0, PFSFeeUpdate) pfs_capacity_update_2_of_app0 = get_messages(app0)[2] assert isinstance(pfs_capacity_update_2_of_app0, PFSCapacityUpdate) canonical_identifier = pfs_fee_update_1_of_app0.canonical_identifier new_total_deposit_1 = pfs_capacity_update_2_of_app0.other_capacity * 2 deposit_transaction_1 = TransactionChannelDeposit( app1.raiden.address, TokenAmount(new_total_deposit_1), chain_state.block_number) channel_deposit_1 = ContractReceiveChannelDeposit( transaction_hash=make_transaction_hash(), canonical_identifier=canonical_identifier, deposit_transaction=deposit_transaction_1, block_number=chain_state.block_number, block_hash=chain_state.block_hash, fee_config=MediationFeeConfig(), ) new_total_deposit_2 = new_total_deposit_1 * 2 deposit_transaction_2 = TransactionChannelDeposit( app1.raiden.address, TokenAmount(new_total_deposit_2), chain_state.block_number) channel_deposit_2 = ContractReceiveChannelDeposit( transaction_hash=make_transaction_hash(), canonical_identifier=canonical_identifier, deposit_transaction=deposit_transaction_2, block_number=chain_state.block_number, block_hash=chain_state.block_hash, fee_config=MediationFeeConfig(), ) state_changes = [channel_deposit_1, channel_deposit_2] app0.raiden.handle_state_changes(state_changes=state_changes) # Now we should see that app0 send 2 new messages, # one PFSCapacityUpdate and one PFSFeeUpdate with # the updated amount of the initial amount * 4 # so sending should only be triggered by the second state change pfs_capacity_update_3_of_app0 = get_messages(app0)[4] assert isinstance(pfs_capacity_update_3_of_app0, PFSCapacityUpdate) assert len(get_messages(app0)) == 6 assert (pfs_capacity_update_3_of_app0.other_capacity == pfs_capacity_update_2_of_app0.updating_capacity * 4) # Now we want to test if this also works with a state_change # that triggers only a PFSCapacityUpdate and no PFSFeeUpdate. # So at the end we expect 1 more PFSCapacityUpdate in the room. lock_secret_1 = keccak(b"test_end_state") unlock_message_1 = Unlock( chain_id=chain_state.chain_id, message_identifier=MessageID(123132), payment_identifier=PaymentID(1), nonce=Nonce(2), token_network_address=canonical_identifier.token_network_address, channel_identifier=canonical_identifier.channel_identifier, transferred_amount=TokenAmount(400), locked_amount=LockedAmount(0), locksroot=Locksroot(keccak(b"")), secret=Secret(lock_secret_1), signature=Signature(bytes(65)), ) unlock_message_1.sign(app1.raiden.signer) balance_proof_1 = balanceproof_from_envelope(unlock_message_1) unlock_1 = ReceiveUnlock( message_identifier=MessageID(5135), secret=Secret(lock_secret_1), balance_proof=balance_proof_1, sender=balance_proof_1.sender, ) lock_secret_2 = keccak(b"test_end_state_again") unlock_message_2 = Unlock( chain_id=chain_state.chain_id, message_identifier=MessageID(223132), payment_identifier=PaymentID(2), nonce=Nonce(2), token_network_address=canonical_identifier.token_network_address, channel_identifier=canonical_identifier.channel_identifier, transferred_amount=TokenAmount(500), locked_amount=LockedAmount(0), locksroot=Locksroot(keccak(b"")), secret=Secret(lock_secret_2), signature=Signature(bytes(65)), ) unlock_message_2.sign(app1.raiden.signer) balance_proof_2 = balanceproof_from_envelope(unlock_message_2) unlock_2 = ReceiveUnlock( message_identifier=MessageID(5135), secret=Secret(lock_secret_2), balance_proof=balance_proof_2, sender=balance_proof_2.sender, ) state_changes_2 = [unlock_1, unlock_2] app0.raiden.handle_state_changes(state_changes=state_changes_2) assert len(get_messages(app0)) == 7 assert len([ x for x in get_messages(app0) if isinstance(x, PFSCapacityUpdate) ]) == 4