def events_for_unlock_lock( initiator_state: InitiatorTransferState, channel_state: NettingChannelState, secret: typing.Secret, secrethash: typing.SecretHash, pseudo_random_generator: random.Random, ): # next hop learned the secret, unlock the token locally and send the # lock claim message to next hop transfer_description = initiator_state.transfer_description message_identifier = message_identifier_from_prng(pseudo_random_generator) unlock_lock = channel.send_unlock( channel_state=channel_state, message_identifier=message_identifier, payment_identifier=transfer_description.payment_identifier, secret=secret, secrethash=secrethash, ) payment_sent_success = EventPaymentSentSuccess( payment_network_identifier=channel_state.payment_network_identifier, token_network_identifier=channel_state.token_network_identifier, identifier=transfer_description.payment_identifier, amount=transfer_description.amount, target=transfer_description.target, ) unlock_success = EventUnlockSuccess( transfer_description.payment_identifier, transfer_description.secrethash, ) return [unlock_lock, payment_sent_success, unlock_success]
def events_for_unlock_lock( initiator_state: InitiatorTransferState, channel_state: NettingChannelState, secret: Secret, secrethash: SecretHash, pseudo_random_generator: random.Random, ) -> List[Event]: """ Unlocks the lock offchain, and emits the events for the successful payment. """ # next hop learned the secret, unlock the token locally and send the # lock claim message to next hop transfer_description = initiator_state.transfer_description message_identifier = message_identifier_from_prng(pseudo_random_generator) unlock_lock = channel.send_unlock( channel_state=channel_state, message_identifier=message_identifier, payment_identifier=transfer_description.payment_identifier, secret=secret, secrethash=secrethash, ) base_events = events_for_unlock_base(initiator_state, channel_state, secret) events = list() events.extend(base_events) events.append(unlock_lock) return events
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 events_for_balanceproof( channelidentifiers_to_channels, transfers_pair, pseudo_random_generator, block_number, secret, secrethash, ): """ While it's safe do the off-chain unlock. """ events = list() for pair in reversed(transfers_pair): payee_knows_secret = pair.payee_state in STATE_SECRET_KNOWN payee_payed = pair.payee_state in STATE_TRANSFER_PAID payee_channel = get_payee_channel(channelidentifiers_to_channels, pair) payee_channel_open = channel.get_status( payee_channel) == CHANNEL_STATE_OPENED payer_channel = get_payer_channel(channelidentifiers_to_channels, pair) # The mediator must not send to the payee a balance proof if the lock # is in the danger zone, because the payer may not do the same and the # on-chain unlock may fail. If the lock is nearing it's expiration # block, then on-chain unlock should be done, and if successfull it can # be unlocked off-chain. is_safe_to_send_balanceproof, _ = is_safe_to_wait( pair.payer_transfer.lock.expiration, payer_channel.reveal_timeout, block_number, ) should_send_balanceproof_to_payee = (payee_channel_open and payee_knows_secret and not payee_payed and is_safe_to_send_balanceproof) if should_send_balanceproof_to_payee: pair.payee_state = 'payee_balance_proof' message_identifier = message_identifier_from_prng( pseudo_random_generator) unlock_lock = channel.send_unlock( payee_channel, pair.payee_transfer.payment_identifier, message_identifier, secret, secrethash, ) unlock_success = EventUnlockSuccess( pair.payer_transfer.payment_identifier, pair.payer_transfer.lock.secrethash, ) events.append(unlock_lock) events.append(unlock_success) return events
def handle_offchain_secretreveal_light( initiator_state: InitiatorTransferState, state_change: ReceiveSecretRevealLight, channel_state: NettingChannelState, pseudo_random_generator: random.Random ) -> TransitionResult[InitiatorTransferState]: """ Once the next hop proves it knows the secret, the initiator can unlock the mediated transfer. This will validate the secret, and if valid a new balance proof is sent to the next hop with the current lock removed from the merkle tree and the transferred amount updated. """ iteration: TransitionResult[InitiatorTransferState] valid_reveal = is_valid_secret_reveal( state_change=state_change, transfer_secrethash=initiator_state.transfer_description.secrethash, secret=state_change.secret, ) sent_by_partner = state_change.sender == channel_state.partner_state.address is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED if valid_reveal and is_channel_open and sent_by_partner: unlock_events = events_for_unlock_base( initiator_state=initiator_state, channel_state=channel_state, secret=state_change.secret, ) transfer_description = initiator_state.transfer_description message_identifier = message_identifier_from_prng(pseudo_random_generator) unlock_lock = channel.send_unlock( channel_state=channel_state, message_identifier=message_identifier, payment_identifier=transfer_description.payment_identifier, secret=state_change.secret, secrethash=state_change.secrethash, ) unlock_msg = Unlock.from_event(unlock_lock) store_received_secret_reveal_event = StoreMessageEvent(state_change.secret_reveal_message.message_identifier, transfer_description.payment_identifier, 9, state_change.secret_reveal_message, True) store_created_unlock_event = StoreMessageEvent(message_identifier, transfer_description.payment_identifier, 11, unlock_msg, False) events = list() events.append(store_received_secret_reveal_event) events.append(store_created_unlock_event) events.extend(unlock_events) iteration = TransitionResult(None, events) else: events = list() iteration = TransitionResult(initiator_state, events) return iteration
def handle_secretreveal( initiator_state: InitiatorTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, ) -> TransitionResult: """ Send a balance proof to the next hop with the current mediated transfer lock removed and the balance updated. """ is_valid_secret_reveal = ( state_change.sender == channel_state.partner_state.address and state_change.secrethash == initiator_state.transfer_description.secrethash) # If the channel is closed the balance proof must not be sent is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED if is_valid_secret_reveal and is_channel_open: # next hop learned the secret, unlock the token locally and send the # lock claim message to next hop transfer_description = initiator_state.transfer_description message_identifier = message_identifier_from_prng( pseudo_random_generator) unlock_lock = channel.send_unlock( channel_state, transfer_description.payment_identifier, message_identifier, state_change.secret, state_change.secrethash, ) # TODO: Emit these events after on-chain unlock payment_sent_success = EventPaymentSentSuccess( payment_network_identifier=channel_state. payment_network_identifier, token_network_identifier=channel_state.token_network_identifier, identifier=transfer_description.payment_identifier, amount=transfer_description.amount, target=transfer_description.target, ) unlock_success = EventUnlockSuccess( transfer_description.payment_identifier, transfer_description.secrethash, ) iteration = TransitionResult( None, [payment_sent_success, unlock_success, unlock_lock]) else: iteration = TransitionResult(initiator_state, list()) return iteration
def events_for_balanceproof( channelidentifiers_to_channels, transfers_pair, pseudo_random_generator, block_number, secret, secrethash, ): """ Send the balance proof to nodes that know the secret. """ events = list() for pair in reversed(transfers_pair): payee_knows_secret = pair.payee_state in STATE_SECRET_KNOWN payee_payed = pair.payee_state in STATE_TRANSFER_PAID payee_channel = get_payee_channel(channelidentifiers_to_channels, pair) payee_channel_open = channel.get_status( payee_channel) == CHANNEL_STATE_OPENED # XXX: All nodes must close the channel and unlock on-chain if the # lock is nearing it's expiration block, what should be the strategy # for sending a balance proof to a node that knowns the secret but has # not gone on-chain while near the expiration? (The problem is how to # define the unsafe region, since that is a local configuration) lock_valid = is_lock_valid(pair.payee_transfer.lock.expiration, block_number) if payee_channel_open and payee_knows_secret and not payee_payed and lock_valid: pair.payee_state = 'payee_balance_proof' message_identifier = message_identifier_from_prng( pseudo_random_generator) unlock_lock = channel.send_unlock( payee_channel, pair.payee_transfer.payment_identifier, message_identifier, secret, secrethash, ) unlock_success = EventUnlockSuccess( pair.payer_transfer.payment_identifier, pair.payer_transfer.lock.secrethash, ) events.append(unlock_lock) events.append(unlock_success) return events
def handle_secretreveal( initiator_state: InitiatorTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, ) -> TransitionResult: """ Send a balance proof to the next hop with the current mediated transfer lock removed and the balance updated. """ is_valid_secret_reveal = ( state_change.sender == channel_state.partner_state.address and state_change.secrethash == initiator_state.transfer_description.secrethash ) # If the channel is closed the balance proof must not be sent is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED if is_valid_secret_reveal and is_channel_open: # next hop learned the secret, unlock the token locally and send the # lock claim message to next hop transfer_description = initiator_state.transfer_description message_identifier = message_identifier_from_prng(pseudo_random_generator) unlock_lock = channel.send_unlock( channel_state, transfer_description.payment_identifier, message_identifier, state_change.secret, state_change.secrethash, ) # TODO: Emit these events after on-chain unlock transfer_success = EventTransferSentSuccess( transfer_description.payment_identifier, transfer_description.amount, transfer_description.target, ) unlock_success = EventUnlockSuccess( transfer_description.payment_identifier, transfer_description.secrethash, ) iteration = TransitionResult(None, [transfer_success, unlock_success, unlock_lock]) else: iteration = TransitionResult(initiator_state, list()) return iteration
def handle_secretreveal( initiator_state: InitiatorTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, ) -> TransitionResult: """ Send a balance proof to the next hop with the current mediated transfer lock removed and the balance updated. """ is_valid_secret_reveal = (state_change.sender == channel_state.partner_state.address and state_change.hashlock == initiator_state.transfer_description.hashlock) # If the channel is closed the balance proof must not be sent is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED if is_valid_secret_reveal and is_channel_open: # next hop learned the secret, unlock the token locally and send the # withdraw message to next hop transfer_description = initiator_state.transfer_description unlock_lock = channel.send_unlock( channel_state, transfer_description.identifier, state_change.secret, state_change.hashlock, ) # TODO: Emit these events after on-chain withdraw transfer_success = EventTransferSentSuccess( transfer_description.identifier, transfer_description.amount, transfer_description.target, ) unlock_success = EventUnlockSuccess( transfer_description.identifier, transfer_description.hashlock, ) iteration = TransitionResult( None, [transfer_success, unlock_success, unlock_lock]) else: iteration = TransitionResult(initiator_state, list()) return iteration
def events_for_balanceproof( channelidentifiers_to_channels, transfers_pair, pseudo_random_generator, block_number, secret, secrethash, ): """ Send the balance proof to nodes that know the secret. """ events = list() for pair in reversed(transfers_pair): payee_knows_secret = pair.payee_state in STATE_SECRET_KNOWN payee_payed = pair.payee_state in STATE_TRANSFER_PAID payee_channel = get_payee_channel(channelidentifiers_to_channels, pair) payee_channel_open = channel.get_status(payee_channel) == CHANNEL_STATE_OPENED # XXX: All nodes must close the channel and unlock on-chain if the # lock is nearing it's expiration block, what should be the strategy # for sending a balance proof to a node that knowns the secret but has # not gone on-chain while near the expiration? (The problem is how to # define the unsafe region, since that is a local configuration) lock_valid = is_lock_valid(pair.payee_transfer.lock.expiration, block_number) if payee_channel_open and payee_knows_secret and not payee_payed and lock_valid: pair.payee_state = 'payee_balance_proof' message_identifier = message_identifier_from_prng(pseudo_random_generator) unlock_lock = channel.send_unlock( payee_channel, pair.payee_transfer.payment_identifier, message_identifier, secret, secrethash, ) unlock_success = EventUnlockSuccess( pair.payer_transfer.payment_identifier, pair.payer_transfer.lock.secrethash, ) events.append(unlock_lock) events.append(unlock_success) return events
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 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( unlock_lock.balance_proof.chain_id, unlock_lock.message_identifier, unlock_lock.payment_identifier, unlock_lock.balance_proof.nonce, partner_channel.token_network_identifier, unlock_lock.balance_proof.channel_address, unlock_lock.balance_proof.transferred_amount, unlock_lock.balance_proof.locked_amount, unlock_lock.balance_proof.locksroot, 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 events_for_unlock_lock( initiator_state: InitiatorTransferState, channel_state: NettingChannelState, secret: Secret, secrethash: SecretHash, pseudo_random_generator: random.Random, block_number: BlockNumber, ) -> List[Event]: """ Unlocks the lock offchain, and emits the events for the successful payment. """ # next hop learned the secret, unlock the token locally and send the # lock claim message to next hop transfer_description = initiator_state.transfer_description message_identifier = message_identifier_from_prng(pseudo_random_generator) unlock_lock = channel.send_unlock( channel_state=channel_state, message_identifier=message_identifier, payment_identifier=transfer_description.payment_identifier, secret=secret, secrethash=secrethash, block_number=block_number, ) payment_sent_success = EventPaymentSentSuccess( token_network_registry_address=channel_state. token_network_registry_address, token_network_address=channel_state.token_network_address, identifier=transfer_description.payment_identifier, amount=transfer_description.amount, target=transfer_description.target, secret=secret, route=initiator_state.route.route, ) unlock_success = EventUnlockSuccess( transfer_description.payment_identifier, transfer_description.secrethash) return [unlock_lock, payment_sent_success, unlock_success]