def events_for_onchain_secretreveal( target_state: TargetTransferState, channel_state: NettingChannelState, block_number: typing.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, ) if not safe_to_wait and secret_known_offchain: 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 events_for_onchain_secretreveal(target_state, channel_state, block_number): """ Emits the event for revealing the secret on-chain if the transfer cannot to be settled off-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: secret = channel.get_secret( channel_state.partner_state, transfer.lock.secrethash, ) return secret_registry.events_for_onchain_secretreveal( channel_state, block_number, secret, ) 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 events_for_onchain_secretreveal(target_state, channel_state, block_number): """ Emits the event for revealing the secret on-chain if the transfer cannot to be settled off-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: secret = channel.get_secret( channel_state.partner_state, transfer.lock.secrethash, ) return secret_registry.events_for_onchain_secretreveal( channel_state, block_number, secret, ) return list()
def test_events_for_onchain_secretreveal_with_unfit_channels(): settle = factories.TransactionExecutionStatusProperties() settled = factories.create( factories.NettingChannelStateProperties(settle_transaction=settle)) secret = factories.UNIT_SECRET block_hash = factories.make_block_hash() events = events_for_onchain_secretreveal(settled, secret, 10, block_hash) assert not events, "Secret reveal event should not be generated for settled channel" settle = factories.replace(settle, result=TransactionExecutionStatus.FAILURE) unusable = factories.create( factories.NettingChannelStateProperties(settle_transaction=settle)) events = events_for_onchain_secretreveal(unusable, secret, 10, block_hash) assert not events, "Secret reveal event should not be generated for unusable channel."
def events_for_onchain_secretreveal_if_closed( channelmap: typing.ChannelMap, transfers_pair: typing.List[MediationPairState], secret: typing.Secret, secrethash: typing.SecretHash, ) -> typing.List[ContractSendSecretReveal]: """ Register the secret on-chain if the payer channel is already closed and the mediator learned the secret off-chain. Balance proofs are not exchanged for closed channels, so there is no reason to wait for the unsafe region to register secret. Note: If the secret is learned before the channel is closed, then the channel will register the secrets in bulk, not the transfer. """ events = list() all_payer_channels = [ get_payer_channel(channelmap, pair) for pair in transfers_pair ] transaction_sent = has_secret_registration_started( all_payer_channels, transfers_pair, secrethash, ) # Just like the case for entering the danger zone, this will only consider # the transfers which have a pair. for pending_pair in get_pending_transfer_pairs(transfers_pair): payer_channel = get_payer_channel(channelmap, pending_pair) # Don't register the secret on-chain if the channel is open or settled if channel.get_status(payer_channel) == CHANNEL_STATE_CLOSED: pending_pair.payer_state = 'payer_waiting_secret_reveal' if not transaction_sent: partner_state = payer_channel.partner_state lock = channel.get_lock(partner_state, secrethash) reveal_events = secret_registry.events_for_onchain_secretreveal( payer_channel, secret, lock.expiration, ) events.extend(reveal_events) transaction_sent = True return events
def events_for_onchain_secretreveal( channelidentifiers_to_channels, transfers_pair, block_number, ): """ Reveal the secret if a locks is in the unsafe region. """ events = list() pending_transfers_pairs = get_pending_transfer_pairs(transfers_pair) for pair in reversed(pending_transfers_pairs): payer_channel = get_payer_channel(channelidentifiers_to_channels, pair) expiration = pair.payer_transfer.lock.expiration safe_to_wait, _ = is_safe_to_wait( expiration, payer_channel.reveal_timeout, block_number, ) # We check if the secret is already known by receiving a ReceiveSecretReveal state change secret_known = channel.is_secret_known( payer_channel.partner_state, pair.payer_transfer.lock.secrethash, ) if not safe_to_wait and secret_known: secret = channel.get_secret( payer_channel.partner_state, pair.payer_transfer.lock.secrethash, ) reveal_events = secret_registry.events_for_onchain_secretreveal( payer_channel, secret, expiration, ) # short circuit because the secret needs to be revealed on-chain # only once return reveal_events return events
def events_for_onchain_secretreveal( channelidentifiers_to_channels, transfers_pair, block_number, ): """ Reveal secrets for transfer locks that are in the unsafe region. """ events = list() pending_transfers_pairs = get_pending_transfer_pairs(transfers_pair) for pair in reversed(pending_transfers_pairs): payer_channel = get_payer_channel(channelidentifiers_to_channels, pair) safe_to_wait = is_safe_to_wait( pair.payer_transfer.lock.expiration, payer_channel.reveal_timeout, block_number, ) # We check if the secret is already known by receiving a ReceiveSecretReveal state change secret_known = channel.is_secret_known( payer_channel.partner_state, pair.payer_transfer.lock.secrethash, ) if not safe_to_wait and secret_known: secret = channel.get_secret( payer_channel.partner_state, pair.payer_transfer.lock.secrethash, ) reveal_events = secret_registry.events_for_onchain_secretreveal( payer_channel, block_number, secret, ) events.extend(reveal_events) return events
def events_for_onchain_secretreveal( channelidentifiers_to_channels, transfers_pair, block_number, ): """ Reveal secrets for transfer locks that are in the unsafe region. """ events = list() pending_transfers_pairs = get_pending_transfer_pairs(transfers_pair) for pair in reversed(pending_transfers_pairs): payer_channel = get_payer_channel(channelidentifiers_to_channels, pair) safe_to_wait = is_safe_to_wait( pair.payer_transfer.lock.expiration, payer_channel.reveal_timeout, block_number, ) # We check if the secret is already known by receiving a ReceiveSecretReveal state change secret_known = channel.is_secret_known( payer_channel.partner_state, pair.payer_transfer.lock.secrethash, ) if not safe_to_wait and secret_known: secret = channel.get_secret( payer_channel.partner_state, pair.payer_transfer.lock.secrethash, ) reveal_events = secret_registry.events_for_onchain_secretreveal( payer_channel, block_number, secret, ) events.extend(reveal_events) return 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 test_events_for_onchain_secretreveal_typechecks_secret(): channel = factories.create(factories.NettingChannelStateProperties()) block_hash = factories.make_block_hash() with pytest.raises(ValueError): events_for_onchain_secretreveal(channel, "This is an invalid secret", 10, block_hash)
def events_for_onchain_secretreveal_if_dangerzone( channelmap: typing.ChannelMap, secrethash: typing.SecretHash, transfers_pair: typing.List[MediationPairState], block_number: typing.BlockNumber, ) -> typing.List[Event]: """ Reveal the secret on-chain if the lock enters the unsafe region and the secret is not yet on-chain. """ events = list() all_payer_channels = [ get_payer_channel(channelmap, pair) for pair in transfers_pair ] transaction_sent = has_secret_registration_started( all_payer_channels, transfers_pair, secrethash, ) # Only consider the transfers which have a pair. This means if we have a # waiting transfer and for some reason the node knows the secret, it will # not try to register it. Otherwise it would be possible for an attacker to # reveal the secret late, just to force the node to send an unecessary # transaction. for pair in get_pending_transfer_pairs(transfers_pair): payer_channel = get_payer_channel(channelmap, pair) lock = pair.payer_transfer.lock safe_to_wait, _ = is_safe_to_wait( lock.expiration, payer_channel.reveal_timeout, block_number, ) secret_known = channel.is_secret_known( payer_channel.partner_state, pair.payer_transfer.lock.secrethash, ) if not safe_to_wait and secret_known: pair.payer_state = 'payer_waiting_secret_reveal' if not transaction_sent: secret = channel.get_secret( payer_channel.partner_state, lock.secrethash, ) reveal_events = secret_registry.events_for_onchain_secretreveal( payer_channel, secret, lock.expiration, ) events.extend(reveal_events) transaction_sent = True return events