Exemplo n.º 1
0
def handle_channel_withdraw(channel_state, state_change):
    hashlock = state_change.hashlock
    secret = state_change.secret

    our_withdraw = (state_change.receiver == channel_state.our_state.address
                    and is_locked(channel_state.partner_state, hashlock))
    # FIXME: must not remove the lock, otherwise a new unlock proof cannot be
    # made
    if our_withdraw:
        del_lock(channel_state.partner_state, hashlock)

    partner_withdraw = (state_change.receiver
                        == channel_state.partner_state.address
                        and is_locked(channel_state.our_state, hashlock))
    if partner_withdraw:
        del_lock(channel_state.our_state, hashlock)

    # Withdraw is required if there was a refund in this channel, and the
    # secret is learned from the withdraw event.
    events = []
    if is_locked(channel_state.our_state, hashlock):
        lock = get_lock(channel_state.our_state, hashlock)
        proof = compute_proof_for_lock(channel_state.our_state, secret, lock)
        withdraw = ContractSendChannelWithdraw(channel_state.identifier,
                                               [proof])
        events.append(withdraw)

    register_secret(channel_state, secret, hashlock)

    return TransitionResult(channel_state, events)
Exemplo n.º 2
0
def handle_channel_withdraw(channel_state, state_change):
    events = list()

    # Withdraw is allowed by the smart contract only on a closed channel.
    # Ignore the withdraw if the channel was not closed yet.
    if get_status(channel_state) == CHANNEL_STATE_CLOSED:
        our_state = channel_state.our_state
        partner_state = channel_state.partner_state

        secrethash = state_change.secrethash
        secret = state_change.secret

        our_withdraw = (state_change.receiver == our_state.address
                        and is_lock_pending(partner_state, secrethash))
        if our_withdraw:
            _del_lock(partner_state, secrethash)

        partner_withdraw = (state_change.receiver == partner_state.address
                            and is_lock_pending(our_state, secrethash))
        if partner_withdraw:
            _del_lock(our_state, secrethash)

        # Withdraw is required if there was a refund in this channel, and the
        # secret is learned from the withdraw event.
        if is_lock_pending(our_state, secrethash):
            lock = get_lock(our_state, secrethash)
            proof = compute_proof_for_lock(our_state, secret, lock)
            withdraw = ContractSendChannelWithdraw(channel_state.identifier,
                                                   [proof])
            events.append(withdraw)

        register_secret(channel_state, secret, secrethash)

    return TransitionResult(channel_state, events)
Exemplo n.º 3
0
def handle_channel_closed(channel_state, state_change):
    events = list()

    just_closed = (state_change.channel_identifier == channel_state.identifier
                   and get_status(channel_state)
                   in CHANNEL_STATES_PRIOR_TO_CLOSED)

    if just_closed:
        set_closed(channel_state, state_change.closed_block_number)

        balance_proof = channel_state.partner_state.balance_proof
        call_update = (
            state_change.closing_address != channel_state.our_state.address
            and balance_proof)
        if call_update:
            # The channel was closed by our partner, if there is a balance
            # proof available update this node half of the state
            update = ContractSendChannelUpdateTransfer(
                channel_state.identifier,
                balance_proof,
            )
            events.append(update)

        unlock_proofs = get_known_unlocks(channel_state.partner_state)
        if unlock_proofs:
            withdraw = ContractSendChannelWithdraw(
                channel_state.identifier,
                unlock_proofs,
            )
            events.append(withdraw)

    return TransitionResult(channel_state, events)
Exemplo n.º 4
0
def events_for_withdraw_if_closed(
        channelidentifiers_to_channels,
        transfers_pair,
        secret,
        secrethash):
    """ Withdraw on chain if the payer channel is closed and the secret is known.
    If a channel is closed because of another task a balance proof will not be
    received, so there is no reason to wait for the unsafe region before
    calling close.
    This may break the reverse reveal order:
        Path: A -- B -- C -- B -- D
        B learned the secret from D and has revealed to C.
        C has not confirmed yet.
        channel(A, B).closed is True.
        B will withdraw on channel(A, B) before C's confirmation.
        A may learn the secret faster than other nodes.
    """
    events = list()
    pending_transfers_pairs = get_pending_transfer_pairs(transfers_pair)

    for pair in pending_transfers_pairs:
        payer_channel = get_payer_channel(channelidentifiers_to_channels, pair)

        payer_channel_open = channel.get_status(payer_channel) == CHANNEL_STATE_OPENED

        # The withdraw is done by the channel
        if not payer_channel_open:
            pair.payer_state = 'payer_waiting_withdraw'

            partner_state = payer_channel.partner_state
            lock = channel.get_lock(partner_state, secrethash)
            unlock_proof = channel.compute_proof_for_lock(
                partner_state,
                secret,
                lock,
            )
            withdraw = ContractSendChannelWithdraw(
                payer_channel.identifier,
                [unlock_proof],
            )
            events.append(withdraw)

    return events