def test_events_for_onchain_secretreveal(): """ Secret must be registered on-chain when the unsafe region is reached and the secret is known. """ block_number = 10 expiration = block_number + 30 channels = make_channel_set([channel_properties]) from_transfer = make_target_transfer(channels[0], expiration=expiration) channel.handle_receive_lockedtransfer(channels[0], from_transfer) channel.register_offchain_secret(channels[0], UNIT_SECRET, UNIT_SECRETHASH) safe_to_wait = expiration - channels[0].reveal_timeout - 1 unsafe_to_wait = expiration - channels[0].reveal_timeout state = TargetTransferState(channels.get_route(0), from_transfer) events = target.events_for_onchain_secretreveal(state, channels[0], safe_to_wait) assert not events events = target.events_for_onchain_secretreveal(state, channels[0], unsafe_to_wait) msg = 'when its not safe to wait, the contract send must be emitted' assert must_contain_entry(events, ContractSendSecretReveal, {'secret': UNIT_SECRET}), msg msg = 'second call must not emit ContractSendSecretReveal again' assert not target.events_for_onchain_secretreveal(state, channels[0], unsafe_to_wait), msg
def make_mediated_transfer( from_channel, partner_channel, initiator, target, lock, pkey, secret=None, ): """ Helper to create and register a mediated transfer from `from_channel` to `partner_channel`.""" payment_identifier = channel.get_next_nonce(from_channel.our_state) message_identifier = random.randint(0, UINT64_MAX) lockedtransfer = channel.send_lockedtransfer( from_channel, initiator, target, lock.amount, message_identifier, payment_identifier, lock.expiration, lock.secrethash, ) mediated_transfer_msg = LockedTransfer.from_event(lockedtransfer) mediated_transfer_msg.sign(LocalSigner(pkey)) # compute the signature balance_proof = balanceproof_from_envelope(mediated_transfer_msg) lockedtransfer.balance_proof = balance_proof # if this fails it's not the right key for the current `from_channel` assert mediated_transfer_msg.sender == from_channel.our_state.address receive_lockedtransfer = lockedtransfersigned_from_message( mediated_transfer_msg) channel.handle_receive_lockedtransfer( partner_channel, receive_lockedtransfer, ) if secret is not None: secrethash = sha3(secret) channel.register_offchain_secret(from_channel, secret, secrethash) channel.register_offchain_secret(partner_channel, secret, secrethash) return mediated_transfer_msg
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 test_events_for_onchain_secretreveal(): """ Secret must be registered on-chain when the unsafe region is reached and the secret is known. """ amount = 3 block_number = 10 expiration = block_number + 30 initiator = HOP1 target_address = UNIT_TRANSFER_TARGET from_channel = factories.make_channel( our_address=target_address, partner_address=UNIT_TRANSFER_SENDER, partner_balance=amount, ) from_route = factories.route_from_channel(from_channel) from_transfer = factories.make_signed_transfer_for( from_channel, amount, initiator, target_address, expiration, UNIT_SECRET, ) channel.handle_receive_lockedtransfer( from_channel, from_transfer, ) channel.register_offchain_secret(from_channel, UNIT_SECRET, UNIT_SECRETHASH) safe_to_wait = expiration - from_channel.reveal_timeout - 1 unsafe_to_wait = expiration - from_channel.reveal_timeout state = TargetTransferState(from_route, from_transfer) events = target.events_for_onchain_secretreveal(state, from_channel, safe_to_wait) assert not events events = target.events_for_onchain_secretreveal(state, from_channel, unsafe_to_wait) assert events assert isinstance(events[0], ContractSendSecretReveal) assert events[0].secret == UNIT_SECRET
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 test_events_for_onchain_secretreveal(): """ Secret must be registered on-chain when the unsafe region is reached and the secret is known. """ block_number = 10 expiration = block_number + 30 channels = make_channel_set([channel_properties]) from_transfer = make_target_transfer(channels[0], expiration=expiration) channel.handle_receive_lockedtransfer(channels[0], from_transfer) channel.register_offchain_secret(channels[0], UNIT_SECRET, UNIT_SECRETHASH) safe_to_wait = expiration - channels[0].reveal_timeout - 1 unsafe_to_wait = expiration - channels[0].reveal_timeout state = TargetTransferState(channels.get_route(0), from_transfer) events = target.events_for_onchain_secretreveal( target_state=state, channel_state=channels[0], block_number=safe_to_wait, block_hash=factories.make_block_hash(), ) assert not events events = target.events_for_onchain_secretreveal( target_state=state, channel_state=channels[0], block_number=unsafe_to_wait, block_hash=factories.make_block_hash(), ) msg = "when its not safe to wait, the contract send must be emitted" assert search_for_item(events, ContractSendSecretReveal, {"secret": UNIT_SECRET}), msg msg = "second call must not emit ContractSendSecretReveal again" assert not target.events_for_onchain_secretreveal( target_state=state, channel_state=channels[0], block_number=unsafe_to_wait, block_hash=factories.make_block_hash(), ), msg
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 set_offchain_secret( state: MediatorTransferState, channelidentifiers_to_channels: typing.ChannelMap, secret: typing.Secret, secrethash: typing.SecretHash, ) -> typing.List[Event]: """ Set the secret to all mediated transfers. """ state.secret = secret for pair in state.transfers_pair: payer_channel = channelidentifiers_to_channels[ pair.payer_transfer.balance_proof.channel_identifier ] channel.register_offchain_secret( payer_channel, secret, secrethash, ) payee_channel = channelidentifiers_to_channels[ pair.payee_transfer.balance_proof.channel_identifier ] channel.register_offchain_secret( payee_channel, secret, secrethash, ) # The secret should never be revealed if `waiting_transfer` is not None. # For this to happen this node must have received a transfer, which it did # *not* mediate, and neverthless the secret was revealed. # # This can only be possible if the initiator reveals the secret without the # target's secret request, or if the node which sent the `waiting_transfer` # has sent another transfer which reached the target (meaning someone along # the path will lose tokens). if state.waiting_transfer: payer_channel = channelidentifiers_to_channels[ state.waiting_transfer.transfer.balance_proof.channel_identifier ] channel.register_offchain_secret( payer_channel, secret, secrethash, ) unexpected_reveal = EventUnexpectedSecretReveal( secrethash=secrethash, reason='The mediator has a waiting transfer.', ) return [unexpected_reveal] return list()
def test_secret_revealed(raiden_chain, deposit, settle_timeout, token_addresses): app0, app1, app2 = raiden_chain registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) hold_event_handler = HoldOffChainSecretRequest() app2.raiden.raiden_event_handler = hold_event_handler amount = 10 identifier = 1 target = app2.raiden.address secret = sha3(target) secrethash = sha3(secret) hold_event_handler.hold_secretrequest_for(secret) app0.raiden.start_mediated_transfer_with_secret( token_network_identifier, amount, target, identifier, secret, ) gevent.sleep(.1) # wait for the messages # The secret hasn't been revealed yet channel_state2_1 = get_channelstate(app2, app1, token_network_identifier) assert len(channel_state2_1.our_state.secrethashes_to_lockedlocks) == 1 channel.register_offchain_secret(channel_state2_1, secret, secrethash) # Close the channel # This needs to register the secrets on chain netting_channel_proxy = app2.raiden.chain.payment_channel( token_network_identifier, channel_state2_1.identifier, ) netting_channel_proxy.channel_close( registry_address, channel_state2_1.partner_state.balance_proof, ) settle_expiration = ( app0.raiden.chain.block_number() + settle_timeout + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS ) wait_until_block(app0.raiden.chain, settle_expiration) assert_synced_channel_state( token_address, app1, deposit - amount, [], app2, deposit + amount, [], ) assert_synced_channel_state( token_address, app0, deposit - amount, [], app1, deposit + amount, [], )