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)
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)
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)
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