def handle_contract_send_channelsettle( self, raiden: RaidenService, channel_settle_event: ContractSendChannelSettle, ): chain_id = raiden.chain.network_id token_network_identifier = channel_settle_event.token_network_identifier channel_identifier = channel_settle_event.channel_identifier payment_channel: PaymentChannel = raiden.chain.payment_channel( token_network_address=channel_settle_event.token_network_identifier, channel_id=channel_settle_event.channel_identifier, ) token_network_proxy: TokenNetwork = payment_channel.token_network participants_details = token_network_proxy.detail_participants( participant1=payment_channel.participant1, participant2=payment_channel.participant2, channel_identifier=channel_settle_event.channel_identifier, ) our_details = participants_details.our_details partner_details = participants_details.partner_details log_details = { 'chain_id': chain_id, 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'node': pex(raiden.address), 'partner': to_checksum_address(partner_details.address), 'our_deposit': our_details.deposit, 'our_withdrawn': our_details.withdrawn, 'our_is_closer': our_details.is_closer, 'our_balance_hash': to_hex(our_details.balance_hash), 'our_nonce': our_details.nonce, 'our_locksroot': to_hex(our_details.locksroot), 'our_locked_amount': our_details.locked_amount, 'partner_deposit': partner_details.deposit, 'partner_withdrawn': partner_details.withdrawn, 'partner_is_closer': partner_details.is_closer, 'partner_balance_hash': to_hex(partner_details.balance_hash), 'partner_nonce': partner_details.nonce, 'partner_locksroot': to_hex(partner_details.locksroot), 'partner_locked_amount': partner_details.locked_amount, } if our_details.balance_hash != EMPTY_HASH: event_record = get_event_with_balance_proof( storage=raiden.wal.storage, chain_id=chain_id, token_network_identifier=token_network_identifier, channel_identifier=channel_identifier, balance_hash=our_details.balance_hash, ) if event_record.data is None: log.critical( 'our balance proof not found', **log_details, ) raise RaidenUnrecoverableError( 'Our balance proof could not be found in the database', ) our_balance_proof = event_record.data.balance_proof our_transferred_amount = our_balance_proof.transferred_amount our_locked_amount = our_balance_proof.locked_amount our_locksroot = our_balance_proof.locksroot else: our_transferred_amount = 0 our_locked_amount = 0 our_locksroot = EMPTY_HASH if partner_details.balance_hash != EMPTY_HASH: state_change_record = get_state_change_with_balance_proof( storage=raiden.wal.storage, chain_id=chain_id, token_network_identifier=token_network_identifier, channel_identifier=channel_identifier, balance_hash=partner_details.balance_hash, sender=participants_details.partner_details.address, ) if state_change_record.data is None: log.critical( 'partner balance proof not found', **log_details, ) raise RaidenUnrecoverableError( 'Partner balance proof could not be found in the database', ) partner_balance_proof = state_change_record.data.balance_proof partner_transferred_amount = partner_balance_proof.transferred_amount partner_locked_amount = partner_balance_proof.locked_amount partner_locksroot = partner_balance_proof.locksroot else: partner_transferred_amount = 0 partner_locked_amount = 0 partner_locksroot = EMPTY_HASH payment_channel.settle( our_transferred_amount, our_locked_amount, our_locksroot, partner_transferred_amount, partner_locked_amount, partner_locksroot, )
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 handle_contract_send_channelunlock( self, raiden: RaidenService, channel_unlock_event: ContractSendChannelBatchUnlock, ): token_network_identifier = channel_unlock_event.token_network_identifier channel_identifier = channel_unlock_event.channel_identifier participant = channel_unlock_event.participant token_address = channel_unlock_event.token_address payment_channel: PaymentChannel = raiden.chain.payment_channel( token_network_address=token_network_identifier, channel_id=channel_identifier, ) token_network: TokenNetwork = payment_channel.token_network participants_details = token_network.detail_participants( participant1=raiden.address, participant2=participant, channel_identifier=channel_identifier, ) our_details = participants_details.our_details our_locksroot = our_details.locksroot partner_details = participants_details.partner_details partner_locksroot = partner_details.locksroot is_partner_unlock = ( partner_details.address == participant and partner_locksroot != EMPTY_HASH ) is_our_unlock = ( our_details.address == participant and our_locksroot != EMPTY_HASH ) if is_partner_unlock: state_change_record = get_state_change_with_balance_proof( storage=raiden.wal.storage, chain_id=raiden.chain.network_id, token_network_identifier=token_network_identifier, channel_identifier=channel_identifier, balance_hash=partner_details.balance_hash, sender=participants_details.partner_details.address, ) state_change_identifier = state_change_record.state_change_identifier elif is_our_unlock: event_record = get_event_with_balance_proof( storage=raiden.wal.storage, chain_id=raiden.chain.network_id, token_network_identifier=token_network_identifier, channel_identifier=channel_identifier, balance_hash=our_details.balance_hash, ) state_change_identifier = event_record.state_change_identifier else: state_change_identifier = 0 if not state_change_identifier: raise RaidenUnrecoverableError( f'Failed to find state/event that match current channel locksroots. ' f'token:{to_checksum_address(token_address)} ' f'token_network:{to_checksum_address(token_network_identifier)} ' f'channel:{channel_identifier} ' f'participant:{to_checksum_address(participant)} ' f'our_locksroot:{to_hex(our_locksroot)} ' f'partner_locksroot:{to_hex(partner_locksroot)} ', ) # Replay state changes until a channel state is reached where # this channel state has the participants balance hash. restored_channel_state = channel_state_until_state_change( raiden=raiden, payment_network_identifier=raiden.default_registry.address, token_address=token_address, channel_identifier=channel_identifier, state_change_identifier=state_change_identifier, ) our_state = restored_channel_state.our_state partner_state = restored_channel_state.partner_state if partner_state.address == participant: merkle_tree_leaves = get_batch_unlock(partner_state) elif our_state.address == participant: merkle_tree_leaves = get_batch_unlock(our_state) try: payment_channel.unlock(merkle_tree_leaves) except ChannelOutdatedError as e: log.error( str(e), node=pex(raiden.address), )