def handle_message_lockexpired(raiden: "RaidenService", message: LockExpired) -> None: balance_proof = balanceproof_from_envelope(message) state_change = ReceiveLockExpired( sender=balance_proof.sender, balance_proof=balance_proof, secrethash=message.secrethash, message_identifier=message.message_identifier, ) raiden.handle_and_track_state_changes([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, sender=balance_proof.sender, ) raiden.handle_and_track_state_changes([state_change])
def handle_message_lockexpired( raiden: "RaidenService", message: LockExpired # pylint: disable=unused-argument ) -> List[StateChange]: balance_proof = balanceproof_from_envelope(message) lock_expired = ReceiveLockExpired( sender=balance_proof.sender, balance_proof=balance_proof, secrethash=message.secrethash, message_identifier=message.message_identifier, ) return [lock_expired]
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 make_receive_expired_lock( channel_state: NettingChannelState, privkey: bytes, nonce: Nonce, transferred_amount: TokenAmount, lock: HashTimeLockState, locked_amount: LockedAmount, pending_locks: PendingLocksState = None, chain_id: ChainID = None, ) -> ReceiveLockExpired: typecheck(lock, HashTimeLockState) signer = LocalSigner(privkey) address = signer.address if address not in (channel_state.our_state.address, channel_state.partner_state.address): raise ValueError("Private key does not match any of the participants.") if pending_locks is None: pending_locks = make_empty_pending_locks_state() else: assert lock.encoded not in pending_locks.locks locksroot = compute_locksroot(pending_locks) chain_id = chain_id or channel_state.chain_id lock_expired_msg = LockExpired( chain_id=chain_id, nonce=nonce, message_identifier=make_message_identifier(), transferred_amount=transferred_amount, locked_amount=TokenAmount(locked_amount), locksroot=locksroot, channel_identifier=channel_state.identifier, token_network_address=channel_state.token_network_address, recipient=channel_state.partner_state.address, secrethash=lock.secrethash, signature=EMPTY_SIGNATURE, ) lock_expired_msg.sign(signer) balance_proof = balanceproof_from_envelope(lock_expired_msg) receive_lockedtransfer = ReceiveLockExpired( balance_proof=balance_proof, secrethash=lock.secrethash, message_identifier=make_message_identifier(), sender=balance_proof.sender, ) return receive_lockedtransfer
def make_receive_transfer_mediated( channel_state: NettingChannelState, privkey: bytes, nonce: Nonce, transferred_amount: TokenAmount, lock: HashTimeLockState, pending_locks: PendingLocksState = None, locked_amount: Optional[PaymentWithFeeAmount] = None, chain_id: Optional[ChainID] = None, ) -> LockedTransferSignedState: typecheck(lock, HashTimeLockState) signer = LocalSigner(privkey) address = signer.address if address not in (channel_state.our_state.address, channel_state.partner_state.address): raise ValueError("Private key does not match any of the participants.") if pending_locks is None: locks = make_empty_pending_locks_state() locks.locks.append(lock.encoded) else: assert bytes(lock.encoded) in pending_locks.locks locks = pending_locks if locked_amount is None: locked_amount = lock.amount assert locked_amount >= lock.amount locksroot = compute_locksroot(locks) payment_identifier = PaymentID(nonce) transfer_target = make_target_address() transfer_initiator = make_initiator_address() chain_id = chain_id or channel_state.chain_id transfer_metadata = Metadata(routes=[ RouteMetadata( route=[channel_state.our_state.address, Address(transfer_target)]) ]) mediated_transfer_msg = LockedTransfer( chain_id=chain_id, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=nonce, token_network_address=channel_state.token_network_address, token=channel_state.token_address, channel_identifier=channel_state.identifier, transferred_amount=transferred_amount, locked_amount=TokenAmount(locked_amount), recipient=channel_state.partner_state.address, locksroot=locksroot, lock=Lock(amount=lock.amount, expiration=lock.expiration, secrethash=lock.secrethash), target=transfer_target, initiator=transfer_initiator, signature=EMPTY_SIGNATURE, fee=0, metadata=transfer_metadata, ) mediated_transfer_msg.sign(signer) receive_lockedtransfer = LockedTransferSignedState( payment_identifier=payment_identifier, token=channel_state.token_address, lock=lock, initiator=transfer_initiator, target=transfer_target, message_identifier=make_message_identifier(), balance_proof=balanceproof_from_envelope(mediated_transfer_msg), routes=[ route_metadata.route for route_metadata in transfer_metadata.routes ], ) return receive_lockedtransfer
def test_regression_onchain_secret_reveal_must_update_channel_state(): """ If a secret is learned off-chain and then on-chain, the state of the lock must be updated in the channel. """ pseudo_random_generator = random.Random() setup = factories.make_transfers_pair(2, block_number=10) mediator_state = MediatorTransferState(secrethash=UNIT_SECRETHASH, routes=setup.channels.get_routes()) mediator_state.transfers_pair = setup.transfers_pair secret = UNIT_SECRET secrethash = UNIT_SECRETHASH payer_channel = mediator.get_payer_channel(setup.channel_map, setup.transfers_pair[0]) payee_channel = mediator.get_payee_channel(setup.channel_map, setup.transfers_pair[0]) lock = payer_channel.partner_state.secrethashes_to_lockedlocks[secrethash] mediator.state_transition( mediator_state=mediator_state, state_change=ReceiveSecretReveal( secret=secret, sender=payee_channel.partner_state.address), 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, block_hash=setup.block_hash, ) assert secrethash in payer_channel.partner_state.secrethashes_to_unlockedlocks secret_registry_address = factories.make_address() transaction_hash = factories.make_address() mediator.state_transition( mediator_state=mediator_state, state_change=ContractReceiveSecretReveal( transaction_hash=transaction_hash, secret_registry_address=secret_registry_address, secrethash=secrethash, secret=secret, block_number=setup.block_number, block_hash=setup.block_hash, ), 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, block_hash=setup.block_hash, ) assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks # Creates a transfer as it was from the *partner* send_lock_expired, _ = channel.create_sendexpiredlock( sender_end_state=payer_channel.partner_state, locked_lock=lock, pseudo_random_generator=pseudo_random_generator, chain_id=payer_channel.chain_id, token_network_address=payer_channel.token_network_address, channel_identifier=payer_channel.identifier, recipient=payer_channel.our_state.address, ) assert send_lock_expired expired_message = message_from_sendevent(send_lock_expired) expired_message.sign(LocalSigner(setup.channels.partner_privatekeys[0])) balance_proof = balanceproof_from_envelope(expired_message) message_identifier = message_identifier_from_prng(pseudo_random_generator) expired_block_number = channel.get_sender_expiration_threshold( lock.expiration) mediator.state_transition( mediator_state=mediator_state, state_change=ReceiveLockExpired( sender=balance_proof.sender, # pylint: disable=no-member balance_proof=balance_proof, secrethash=secrethash, message_identifier=message_identifier, ), channelidentifiers_to_channels=setup.channel_map, nodeaddresses_to_networkstates=setup.channels. nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, block_hash=factories.make_block_hash(), ) assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks
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=UNIT_TRANSFER_AMOUNT, address=HOP2, privatekey=HOP2_KEY), ) ]) payer_transfer = factories.make_signed_transfer_for( channels[0], factories.LockedTransferSignedStateProperties(sender=HOP2, pkey=HOP2_KEY, expiration=30), ) init_state_change = ActionInitMediator( from_hop=channels.get_hop(0), route_states=channels.get_routes(), from_transfer=payer_transfer, balance_proof=payer_transfer.balance_proof, sender=payer_transfer.balance_proof.sender, # pylint: disable=no-member ) 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_address=channels[0].token_network_address, channel_identifier=channels[0].identifier, recipient=channels[0].our_state.address, ) assert send_lock_expired lock_expired_message = message_from_sendevent(send_lock_expired) 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.expiration) 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( sender=balance_proof.sender, # pylint: disable=no-member 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_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