def events_for_close( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: typing.BlockNumber, ): """ Emits the event for closing the netting channel if the transfer needs to be settled on-chain. """ transfer = target_state.transfer safe_to_wait, _ = is_safe_to_wait( transfer.lock.expiration, channel_state.reveal_timeout, block_number, ) secret_known = channel.is_secret_known( channel_state.partner_state, transfer.lock.secrethash, ) if not safe_to_wait and secret_known: target_state.state = 'waiting_close' return channel.events_for_close(channel_state, block_number) return list()
def events_for_onchain_secretreveal( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: BlockNumber, block_hash: BlockHash, ) -> List[Event]: """ Emits the event for revealing the secret on-chain if the transfer can not be settled off-chain. """ transfer = target_state.transfer expiration = transfer.lock.expiration safe_to_wait = is_safe_to_wait(expiration, channel_state.reveal_timeout, block_number) secret_known_offchain = channel.is_secret_known_offchain( channel_state.partner_state, transfer.lock.secrethash ) has_onchain_reveal_started = target_state.state == TargetTransferState.ONCHAIN_SECRET_REVEAL if not safe_to_wait and secret_known_offchain and not has_onchain_reveal_started: target_state.state = TargetTransferState.ONCHAIN_SECRET_REVEAL secret = channel.get_secret(channel_state.partner_state, transfer.lock.secrethash) assert secret, "secret should be known at this point" return secret_registry.events_for_onchain_secretreveal( channel_state=channel_state, secret=secret, expiration=expiration, block_hash=block_hash, ) return list()
def handle_block( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: typing.BlockNumber, ): """ After Raiden learns about a new block this function must be called to handle expiration of the hash time lock. """ transfer = target_state.transfer events = list() secret_known = channel.is_secret_known( channel_state.partner_state, transfer.lock.secrethash, ) is_lock_expired = (not secret_known and block_number > transfer.lock.expiration) if secret_known: events = events_for_onchain_secretreveal( target_state, channel_state, block_number, ) elif is_lock_expired and target_state.state != 'expired': failed = EventUnlockClaimFailed( identifier=transfer.payment_identifier, secrethash=transfer.lock.secrethash, reason='lock expired', ) target_state.state = 'expired' events = [failed] return TransitionResult(target_state, events)
def handle_block( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: typing.BlockNumber, pseudo_random_generator: random.Random, ): """ After Raiden learns about a new block this function must be called to handle expiration of the hash time lock. """ transfer = target_state.transfer secret_known = channel.is_secret_known( channel_state.partner_state, transfer.lock.secrethash, ) if not secret_known and block_number > transfer.lock.expiration: if target_state.state != 'expired': failed = EventUnlockClaimFailed( identifier=transfer.payment_identifier, secrethash=transfer.lock.secrethash, reason='lock expired', ) target_state.state = 'expired' events = [failed] else: events = list() elif target_state.state != 'waiting_close': # only emit the close event once events = events_for_onchain_secretreveal(target_state, channel_state, block_number) else: events = list() iteration = TransitionResult(target_state, events) return iteration
def handle_secretreveal( target_state: TargetTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, ): """ Validates and handles a ReceiveSecretReveal state change. """ valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash waiting_for_secret = target_state.state == 'secret_request' if valid_secret and waiting_for_secret: if isinstance(state_change, ReceiveSecretReveal): channel.register_secret( channel_state, state_change.secret, state_change.secrethash, ) elif isinstance(state_change, ContractReceiveSecretReveal): channel.register_onchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, secret_reveal_block_number=state_change.block_number, ) else: assert False, 'Got unexpected StateChange' route = target_state.route message_identifier = message_identifier_from_prng( pseudo_random_generator) target_state.state = 'reveal_secret' target_state.secret = state_change.secret recipient = route.node_address # Send the secret reveal message only once, delivery is guaranteed by # the transport and not by the state machine reveal = SendSecretReveal( recipient=recipient, channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE, message_identifier=message_identifier, secret=target_state.secret, ) iteration = TransitionResult(target_state, [reveal]) else: # TODO: event for byzantine behavior iteration = TransitionResult(target_state, list()) return iteration
def handle_offchain_secretreveal( target_state: TargetTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, block_number: BlockNumber, ): """ Validates and handles a ReceiveSecretReveal state change. """ valid_secret = is_valid_secret_reveal( state_change=state_change, transfer_secrethash=target_state.transfer.lock.secrethash, secret=state_change.secret, ) has_transfer_expired = channel.transfer_expired( transfer=target_state.transfer, affected_channel=channel_state, block_number=block_number, ) if valid_secret and not has_transfer_expired: channel.register_offchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, ) route = target_state.route message_identifier = message_identifier_from_prng( pseudo_random_generator) target_state.state = TargetTransferState.OFFCHAIN_SECRET_REVEAL target_state.secret = state_change.secret recipient = route.node_address reveal = SendSecretReveal( recipient=recipient, channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE, message_identifier=message_identifier, secret=target_state.secret, ) iteration = TransitionResult(target_state, [reveal]) else: # TODO: event for byzantine behavior iteration = TransitionResult(target_state, list()) return iteration
def handle_offchain_secretreveal( target_state: TargetTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, block_number: BlockNumber, ): """ Validates and handles a ReceiveSecretReveal state change. """ valid_secret = is_valid_secret_reveal( state_change=state_change, transfer_secrethash=target_state.transfer.lock.secrethash, secret=state_change.secret, ) has_transfer_expired = channel.transfer_expired( transfer=target_state.transfer, affected_channel=channel_state, block_number=block_number, ) if valid_secret and not has_transfer_expired: channel.register_offchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, ) route = target_state.route message_identifier = message_identifier_from_prng(pseudo_random_generator) target_state.state = TargetTransferState.OFFCHAIN_SECRET_REVEAL target_state.secret = state_change.secret recipient = route.node_address reveal = SendSecretReveal( recipient=recipient, channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE, message_identifier=message_identifier, secret=target_state.secret, ) iteration = TransitionResult(target_state, [reveal]) else: # TODO: event for byzantine behavior iteration = TransitionResult(target_state, list()) return iteration
def handle_block( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: BlockNumber, block_hash: BlockHash, ) -> TransitionResult[TargetTransferState]: """ After Raiden learns about a new block this function must be called to handle expiration of the hash time lock. """ transfer = target_state.transfer events = list() lock = transfer.lock secret_known = channel.is_secret_known( channel_state.partner_state, lock.secrethash, ) lock_has_expired, _ = channel.is_lock_expired( end_state=channel_state.our_state, lock=lock, block_number=block_number, lock_expiration_threshold=channel.get_receiver_expiration_threshold( lock), ) if lock_has_expired and target_state.state != 'expired': failed = EventUnlockClaimFailed( identifier=transfer.payment_identifier, secrethash=transfer.lock.secrethash, reason=f'lock expired', ) target_state.state = TargetTransferState.EXPIRED events = [failed] elif secret_known: events = events_for_onchain_secretreveal( target_state=target_state, channel_state=channel_state, block_number=block_number, block_hash=block_hash, ) return TransitionResult(target_state, events)
def handle_onchain_secretreveal( target_state: TargetTransferState, state_change: ContractReceiveSecretReveal, channel_state: NettingChannelState, ): """ Validates and handles a ContractReceiveSecretReveal state change. """ valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash if valid_secret: channel.register_onchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, secret_reveal_block_number=state_change.block_number, ) target_state.state = 'reveal_secret' target_state.secret = state_change.secret return TransitionResult(target_state, list())
def handle_block( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: typing.BlockNumber, ): """ After Raiden learns about a new block this function must be called to handle expiration of the hash time lock. """ transfer = target_state.transfer events = list() lock = transfer.lock secret_known = channel.is_secret_known( channel_state.partner_state, lock.secrethash, ) lock_has_expired, _ = channel.is_lock_expired( end_state=channel_state.our_state, lock=lock, block_number=block_number, lock_expiration_threshold=typing.BlockNumber( lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, ), ) if lock_has_expired and target_state.state != 'expired': failed = EventUnlockClaimFailed( identifier=transfer.payment_identifier, secrethash=transfer.lock.secrethash, reason=f'lock expired', ) target_state.state = 'expired' events = [failed] elif secret_known: events = events_for_onchain_secretreveal( target_state, channel_state, block_number, ) return TransitionResult(target_state, events)
def handle_block( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: BlockNumber, ): """ After Raiden learns about a new block this function must be called to handle expiration of the hash time lock. """ transfer = target_state.transfer events = list() lock = transfer.lock secret_known = channel.is_secret_known( channel_state.partner_state, lock.secrethash, ) lock_has_expired, _ = channel.is_lock_expired( end_state=channel_state.our_state, lock=lock, block_number=block_number, lock_expiration_threshold=channel.get_receiver_expiration_threshold(lock), ) if lock_has_expired and target_state.state != 'expired': failed = EventUnlockClaimFailed( identifier=transfer.payment_identifier, secrethash=transfer.lock.secrethash, reason=f'lock expired', ) target_state.state = TargetTransferState.EXPIRED events = [failed] elif secret_known: events = events_for_onchain_secretreveal( target_state, channel_state, block_number, ) return TransitionResult(target_state, events)
def events_for_onchain_secretreveal( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: BlockNumber, ): """ Emits the event for revealing the secret on-chain if the transfer can not be settled off-chain. """ transfer = target_state.transfer expiration = transfer.lock.expiration safe_to_wait, _ = is_safe_to_wait( expiration, channel_state.reveal_timeout, block_number, ) secret_known_offchain = channel.is_secret_known_offchain( channel_state.partner_state, transfer.lock.secrethash, ) has_onchain_reveal_started = ( target_state.state == TargetTransferState.ONCHAIN_SECRET_REVEAL ) if not safe_to_wait and secret_known_offchain and not has_onchain_reveal_started: target_state.state = TargetTransferState.ONCHAIN_SECRET_REVEAL secret = channel.get_secret( channel_state.partner_state, transfer.lock.secrethash, ) return secret_registry.events_for_onchain_secretreveal( channel_state, secret, expiration, ) return list()
def handle_offchain_secretreveal( target_state: TargetTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, ): """ Validates and handles a ReceiveSecretReveal state change. """ valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash if valid_secret: channel.register_offchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, ) route = target_state.route message_identifier = message_identifier_from_prng( pseudo_random_generator) target_state.state = 'reveal_secret' target_state.secret = state_change.secret recipient = route.node_address reveal = SendSecretReveal( recipient=recipient, channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE, message_identifier=message_identifier, secret=target_state.secret, ) iteration = TransitionResult(target_state, [reveal]) else: # TODO: event for byzantine behavior iteration = TransitionResult(target_state, list()) return iteration
def events_for_onchain_secretreveal( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: BlockNumber, ): """ Emits the event for revealing the secret on-chain if the transfer can not be settled off-chain. """ transfer = target_state.transfer expiration = transfer.lock.expiration safe_to_wait, _ = is_safe_to_wait( expiration, channel_state.reveal_timeout, block_number, ) secret_known_offchain = channel.is_secret_known_offchain( channel_state.partner_state, transfer.lock.secrethash, ) has_onchain_reveal_started = ( target_state.state == TargetTransferState.ONCHAIN_SECRET_REVEAL) if not safe_to_wait and secret_known_offchain and not has_onchain_reveal_started: target_state.state = TargetTransferState.ONCHAIN_SECRET_REVEAL secret = channel.get_secret( channel_state.partner_state, transfer.lock.secrethash, ) return secret_registry.events_for_onchain_secretreveal( channel_state, secret, expiration, ) return list()
def handle_onchain_secretreveal( target_state: TargetTransferState, state_change: ContractReceiveSecretReveal, channel_state: NettingChannelState, ): """ Validates and handles a ContractReceiveSecretReveal state change. """ valid_secret = is_valid_secret_reveal( state_change=state_change, transfer_secrethash=target_state.transfer.lock.secrethash, secret=state_change.secret, ) if valid_secret: channel.register_onchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, secret_reveal_block_number=state_change.block_number, ) target_state.state = TargetTransferState.ONCHAIN_UNLOCK target_state.secret = state_change.secret return TransitionResult(target_state, list())
def handle_offchain_secretreveal_light( target_state: TargetTransferState, state_change: ReceiveSecretRevealLight, channel_state: NettingChannelState, pseudo_random_generator: random.Random, block_number: BlockNumber, ) -> TransitionResult[TargetTransferState]: """ Validates and handles a ReceiveSecretReveal state change. """ valid_secret = is_valid_secret_reveal( state_change=state_change, transfer_secrethash=target_state.transfer.lock.secrethash, secret=state_change.secret, ) has_transfer_expired = channel.is_transfer_expired( transfer=target_state.transfer, affected_channel=channel_state, block_number=block_number ) if valid_secret and not has_transfer_expired: # TODO mmarcosmartinez7 this cannot be done without LC interaction # channel.register_offchain_secret( # channel_state=channel_state, # secret=state_change.secret, # secrethash=state_change.secrethash, # ) route = target_state.route message_identifier = message_identifier_from_prng(pseudo_random_generator) target_state.state = TargetTransferState.OFFCHAIN_SECRET_REVEAL target_state.secret = state_change.secret recipient = route.node_address # Store reveal secret 7, create reveal secret 9 and store it for LC signing. received_reveal_secret = state_change.secret_reveal_message reveal_secret_to_send_event = SendSecretReveal( recipient=recipient, channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE, message_identifier=message_identifier, secret=target_state.secret, ) reveal_secret_to_send_msg = message_from_sendevent(reveal_secret_to_send_event) store_received_reveal = StoreMessageEvent( received_reveal_secret.message_identifier, target_state.transfer.payment_identifier, 7, received_reveal_secret, True ) store_reveal_to_send = StoreMessageEvent( message_identifier, target_state.transfer.payment_identifier, 9, reveal_secret_to_send_msg, False ) iteration = TransitionResult(target_state, [store_received_reveal, store_reveal_to_send]) else: # TODO: event for byzantine behavior iteration = TransitionResult(target_state, list()) return iteration