def test_handle_onchain_secretreveal(): """ The target node must update the lock state when the secret is registered in the blockchain. """ setup = make_target_state( block_number=1, expiration=1 + factories.UNIT_REVEAL_TIMEOUT, ) assert factories.UNIT_SECRETHASH in setup.channel.partner_state.secrethashes_to_lockedlocks offchain_secret_reveal_iteration = target.state_transition( target_state=setup.new_state, state_change=ReceiveSecretReveal(UNIT_SECRET, setup.initiator), channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=setup.block_number, ) assert UNIT_SECRETHASH in setup.channel.partner_state.secrethashes_to_unlockedlocks assert UNIT_SECRETHASH not in setup.channel.partner_state.secrethashes_to_lockedlocks # Make sure that an emptyhash on chain reveal is rejected. block_number_prior_the_expiration = setup.expiration - 2 onchain_reveal = ContractReceiveSecretReveal( transaction_hash=factories.make_address(), secret_registry_address=factories.make_address(), secrethash=EMPTY_HASH_KECCAK, secret=EMPTY_HASH, block_number=block_number_prior_the_expiration, ) onchain_secret_reveal_iteration = target.state_transition( target_state=offchain_secret_reveal_iteration.new_state, state_change=onchain_reveal, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=block_number_prior_the_expiration, ) unlocked_onchain = setup.channel.partner_state.secrethashes_to_onchain_unlockedlocks assert EMPTY_HASH_KECCAK not in unlocked_onchain # now let's go for the actual secret onchain_reveal.secret = UNIT_SECRET onchain_reveal.secrethash = UNIT_SECRETHASH onchain_secret_reveal_iteration = target.state_transition( target_state=offchain_secret_reveal_iteration.new_state, state_change=onchain_reveal, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=block_number_prior_the_expiration, ) unlocked_onchain = setup.channel.partner_state.secrethashes_to_onchain_unlockedlocks assert UNIT_SECRETHASH in unlocked_onchain # Check that after we register a lock on-chain handling the block again will # not cause us to attempt an onchain re-register extra_block_handle_transition = target.handle_block( target_state=onchain_secret_reveal_iteration.new_state, channel_state=setup.channel, block_number=block_number_prior_the_expiration + 1, ) assert len(extra_block_handle_transition.events) == 0
def test_initiator_handle_contract_receive_secret_reveal_expired(): """ Initiator must *not* unlock off-chain if the secret is revealed on-chain *after* the lock expiration. """ setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=10) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration + 1, ) iteration = initiator_manager.handle_onchain_secretreveal( payment_state=setup.current_state, state_change=state_change, channelidentifiers_to_channels=setup.channel_map, pseudo_random_generator=setup.prng, ) assert events.must_contain_entry(iteration.events, SendBalanceProof, {}) is None
def test_initiator_handle_contract_receive_emptyhash_secret_reveal(): """ Initiator must not accept contract receive secret reveal with emptyhash """ setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=10) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=EMPTY_HASH, block_number=transfer.lock.expiration, ) iteration = initiator_manager.handle_onchain_secretreveal( payment_state=setup.current_state, state_change=state_change, channelidentifiers_to_channels=setup.channel_map, pseudo_random_generator=setup.prng, ) assert len(iteration.events) == 0 # make sure the original lock wasn't moved assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks
def test_initiator_handle_contract_receive_secret_reveal(): """ Initiator must unlock off-chain if the secret is revealed on-chain and the channel is open. """ setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=10) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration, ) message_identifier = message_identifier_from_prng(deepcopy(setup.prng)) iteration = initiator_manager.handle_onchain_secretreveal( payment_state=setup.current_state, state_change=state_change, channelidentifiers_to_channels=setup.channel_map, pseudo_random_generator=setup.prng, ) payment_identifier = setup.current_state.initiator.transfer_description.payment_identifier assert events.must_contain_entry( iteration.events, SendBalanceProof, { 'message_identifier': message_identifier, 'payment_identifier': payment_identifier, })
def test_initiator_handle_contract_receive_secret_reveal(): """ Initiator must unlock off-chain if the secret is revealed on-chain and the channel is open. """ amount = UNIT_TRANSFER_AMOUNT * 2 channel1 = factories.make_channel( our_balance=amount, token_address=UNIT_TOKEN_ADDRESS, token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS, ) pseudo_random_generator = random.Random() channel_map = { channel1.identifier: channel1, } available_routes = [ factories.route_from_channel(channel1), ] block_number = 10 current_state = make_initiator_manager_state( routes=available_routes, transfer_description=factories.UNIT_TRANSFER_DESCRIPTION, channel_map=channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) transfer = current_state.initiator.transfer assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration, ) message_identifier = message_identifier_from_prng( deepcopy(pseudo_random_generator)) iteration = initiator_manager.handle_onchain_secretreveal( payment_state=current_state, state_change=state_change, channelidentifiers_to_channels=channel_map, pseudo_random_generator=pseudo_random_generator, ) assert events.must_contain_entry( iteration.events, SendBalanceProof, { 'message_identifier': message_identifier, 'payment_identifier': current_state.initiator.transfer_description.payment_identifier, })
def test_handle_onchain_secretreveal(): """ The target node must update the lock state when the secret is registered in the blockchain. """ amount = 3 block_number = 1 expiration = block_number + factories.UNIT_REVEAL_TIMEOUT initiator = factories.HOP1 our_address = factories.ADDR secret = factories.UNIT_SECRET pseudo_random_generator = random.Random() channel_state, state = make_target_state( our_address, amount, block_number, initiator, expiration, ) assert factories.UNIT_SECRETHASH in channel_state.partner_state.secrethashes_to_lockedlocks offchain_secret_reveal_iteration = target.state_transition( state, ReceiveSecretReveal(secret, initiator), channel_state, pseudo_random_generator, block_number, ) assert factories.UNIT_SECRETHASH in channel_state.partner_state.secrethashes_to_unlockedlocks assert factories.UNIT_SECRETHASH not in channel_state.partner_state.secrethashes_to_lockedlocks block_number_prior_the_expiration = expiration - 2 onchain_secret_reveal_iteration = target.state_transition( offchain_secret_reveal_iteration.new_state, ContractReceiveSecretReveal( transaction_hash=factories.make_address(), secret_registry_address=factories.make_address(), secrethash=UNIT_SECRETHASH, secret=UNIT_SECRET, block_number=block_number_prior_the_expiration, ), channel_state, pseudo_random_generator, block_number_prior_the_expiration, ) unlocked_onchain = channel_state.partner_state.secrethashes_to_onchain_unlockedlocks assert factories.UNIT_SECRETHASH in unlocked_onchain # Check that after we register a lock on-chain handling the block again will # not cause us to attempt an onchain re-register extra_block_handle_transition = target.handle_block( onchain_secret_reveal_iteration.new_state, channel_state, block_number_prior_the_expiration + 1, ) assert len(extra_block_handle_transition.events) == 0
def handle_secret_revealed(raiden, event, current_block_number): secret_registry_address = event.originating_contract data = event.event_data registeredsecret_state_change = ContractReceiveSecretReveal( secret_registry_address, data['secrethash'], ) raiden.handle_state_change(registeredsecret_state_change, current_block_number)
def test_initiator_handle_contract_receive_secret_reveal(): """ Make sure the initiator handles ContractReceiveSecretReveal and checks the existence of the transfer's secrethash in secrethashes_to_lockedlocks and secrethashes_to_onchain_unlockedlocks. """ amount = UNIT_TRANSFER_AMOUNT * 2 block_number = 1 refund_pkey, refund_address = factories.make_privkey_address() pseudo_random_generator = random.Random() channel1 = factories.make_channel( our_balance=amount, token_address=UNIT_TOKEN_ADDRESS, token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS, ) pseudo_random_generator = random.Random() channel_map = { channel1.identifier: channel1, } available_routes = [ factories.route_from_channel(channel1), ] block_number = 10 current_state = make_initiator_manager_state( routes=available_routes, transfer_description=factories.UNIT_TRANSFER_DESCRIPTION, channel_map=channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) transfer = current_state.initiator.transfer assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, ) initiator_manager.handle_onchain_secretreveal( payment_state=current_state, state_change=state_change, channelidentifiers_to_channels=channel_map, pseudo_random_generator=pseudo_random_generator, ) assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_onchain_unlockedlocks
def test_initiator_handle_contract_receive_after_channel_closed(): """ Initiator must accept on-chain secret reveal if the channel is closed. However, the off-chain unlock must not be done! This will happen because secrets are registered after a channel is closed, during the settlement window. """ block_number = 10 setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=block_number) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks channel_closed = ContractReceiveChannelClosed( transaction_hash=factories.make_transaction_hash(), transaction_from=factories.make_address(), token_network_identifier=setup.channel.token_network_identifier, channel_identifier=setup.channel.identifier, block_number=block_number, ) channel_close_transition = channel.state_transition( channel_state=setup.channel, state_change=channel_closed, pseudo_random_generator=setup.prng, block_number=block_number, ) channel_state = channel_close_transition.new_state state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration, ) channel_map = { channel_state.identifier: channel_state, } iteration = initiator_manager.handle_onchain_secretreveal( payment_state=setup.current_state, state_change=state_change, channelidentifiers_to_channels=channel_map, pseudo_random_generator=setup.prng, ) secrethash = setup.current_state.initiator.transfer_description.secrethash assert secrethash in channel_state.our_state.secrethashes_to_onchain_unlockedlocks msg = 'The channel is closed already, the balance proof must not be sent off-chain' assert not events.must_contain_entry(iteration.events, SendBalanceProof, {}), msg
def contractreceivesecretreveal_from_event(event: DecodedEvent) -> ContractReceiveSecretReveal: secret_registry_address = event.originating_contract data = event.event_data args = data["args"] return ContractReceiveSecretReveal( secret_registry_address=SecretRegistryAddress(secret_registry_address), secrethash=args["secrethash"], secret=args["secret"], transaction_hash=event.transaction_hash, block_number=event.block_number, block_hash=event.block_hash, )
def handle_secret_revealed(raiden, event): secret_registry_address = event.originating_contract data = event.event_data transaction_hash = data['transactionHash'] assert transaction_hash, 'A mined transaction must have the hash field' registeredsecret_state_change = ContractReceiveSecretReveal( transaction_hash, secret_registry_address, data['secrethash'], data['secret'], ) raiden.handle_state_change(registeredsecret_state_change)
def handle_secret_revealed(raiden: RaidenService, event: Event): secret_registry_address = event.originating_contract data = event.event_data args = data['args'] transaction_hash = data['transaction_hash'] registeredsecret_state_change = ContractReceiveSecretReveal( transaction_hash=transaction_hash, secret_registry_address=secret_registry_address, secrethash=args['secrethash'], secret=args['secret'], block_number=data['block_number'], ) raiden.handle_state_change(registeredsecret_state_change)
def handle_secret_revealed(raiden, event, current_block_number): secret_registry_address = event.originating_contract data = event.event_data from_address = raiden.chain.client.get_transaction_from( event.event_data['transactionHash']) assert from_address, 'A mined transaction must have the from field' registeredsecret_state_change = ContractReceiveSecretReveal( from_address, secret_registry_address, data['secrethash'], data['secret'], ) raiden.handle_state_change(registeredsecret_state_change, current_block_number)
def handle_secret_revealed(raiden: "RaidenService", event: Event): secret_registry_address = event.originating_contract data = event.event_data args = data["args"] block_number = data["block_number"] block_hash = data["block_hash"] transaction_hash = data["transaction_hash"] registeredsecret_state_change = ContractReceiveSecretReveal( transaction_hash=transaction_hash, secret_registry_address=secret_registry_address, secrethash=args["secrethash"], secret=args["secret"], block_number=block_number, block_hash=block_hash, ) raiden.handle_and_track_state_change(registeredsecret_state_change)
def test_regression_onchain_secret_reveal_must_update_channel_state(): """ If a secret is learned off-chain and then on-chain, the state of the lock must be updated in the channel. """ pseudo_random_generator = random.Random() setup = factories.make_transfers_pair(2, block_number=10) mediator_state = MediatorTransferState( secrethash=UNIT_SECRETHASH, routes=setup.channels.get_routes(), ) mediator_state.transfers_pair = setup.transfers_pair secret = UNIT_SECRET secrethash = UNIT_SECRETHASH payer_channel = mediator.get_payer_channel(setup.channel_map, setup.transfers_pair[0]) payee_channel = mediator.get_payee_channel(setup.channel_map, setup.transfers_pair[0]) lock = payer_channel.partner_state.secrethashes_to_lockedlocks[secrethash] mediator.state_transition( mediator_state=mediator_state, state_change=ReceiveSecretReveal(secret, payee_channel.partner_state.address), channelidentifiers_to_channels=setup.channel_map, nodeaddresses_to_networkstates=setup.channels. nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=setup.block_number, block_hash=setup.block_hash, ) assert secrethash in payer_channel.partner_state.secrethashes_to_unlockedlocks secret_registry_address = factories.make_address() transaction_hash = factories.make_address() mediator.state_transition( mediator_state=mediator_state, state_change=ContractReceiveSecretReveal( transaction_hash=transaction_hash, secret_registry_address=secret_registry_address, secrethash=secrethash, secret=secret, block_number=setup.block_number, block_hash=setup.block_hash, ), channelidentifiers_to_channels=setup.channel_map, nodeaddresses_to_networkstates=setup.channels. nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=setup.block_number, block_hash=setup.block_hash, ) assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks # Creates a transfer as it was from the *partner* send_lock_expired, _ = channel.create_sendexpiredlock( sender_end_state=payer_channel.partner_state, locked_lock=lock, pseudo_random_generator=pseudo_random_generator, chain_id=payer_channel.chain_id, token_network_identifier=payer_channel.token_network_identifier, channel_identifier=payer_channel.identifier, recipient=payer_channel.our_state.address, ) assert send_lock_expired expired_message = message_from_sendevent(send_lock_expired, setup.channels.our_address(0)) expired_message.sign(LocalSigner(setup.channels.partner_privatekeys[0])) balance_proof = balanceproof_from_envelope(expired_message) message_identifier = message_identifier_from_prng(pseudo_random_generator) expired_block_number = channel.get_sender_expiration_threshold(lock) mediator.state_transition( mediator_state=mediator_state, state_change=ReceiveLockExpired( balance_proof=balance_proof, secrethash=secrethash, message_identifier=message_identifier, ), channelidentifiers_to_channels=setup.channel_map, nodeaddresses_to_networkstates=setup.channels. nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, block_hash=factories.make_block_hash(), ) assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks
def test_regression_onchain_secret_reveal_must_update_channel_state(): """ If a secret is learned off-chain and then on-chain, the state of the lock must be updated in the channel. """ amount = 10 block_number = 10 pseudo_random_generator = random.Random() channel_map, transfers_pair = factories.make_transfers_pair( [HOP2_KEY, HOP3_KEY], amount, block_number, ) mediator_state = MediatorTransferState(UNIT_SECRETHASH) mediator_state.transfers_pair = transfers_pair secret = UNIT_SECRET secrethash = UNIT_SECRETHASH payer_channelid = transfers_pair[ 0].payer_transfer.balance_proof.channel_identifier payee_channelid = transfers_pair[ 0].payee_transfer.balance_proof.channel_identifier payer_channel = channel_map[payer_channelid] payee_channel = channel_map[payee_channelid] lock = payer_channel.partner_state.secrethashes_to_lockedlocks[secrethash] mediator.state_transition( mediator_state=mediator_state, state_change=ReceiveSecretReveal(secret, payee_channel.partner_state.address), channelidentifiers_to_channels=channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert secrethash in payer_channel.partner_state.secrethashes_to_unlockedlocks secret_registry_address = factories.make_address() transaction_hash = factories.make_address() mediator.state_transition( mediator_state=mediator_state, state_change=ContractReceiveSecretReveal( transaction_hash, secret_registry_address, secrethash, secret, block_number, ), channelidentifiers_to_channels=channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks # Creates a transfer as it was from the *partner* send_lock_expired, _ = channel.create_sendexpiredlock( sender_end_state=payer_channel.partner_state, locked_lock=lock, pseudo_random_generator=pseudo_random_generator, chain_id=payer_channel.chain_id, token_network_identifier=payer_channel.token_network_identifier, channel_identifier=payer_channel.identifier, recipient=payer_channel.our_state.address, ) assert send_lock_expired lock_expired_message = message_from_sendevent(send_lock_expired, HOP1) lock_expired_message.sign(HOP2_KEY) balance_proof = balanceproof_from_envelope(lock_expired_message) message_identifier = message_identifier_from_prng(pseudo_random_generator) expired_block_number = lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2 mediator.state_transition( mediator_state=mediator_state, state_change=ReceiveLockExpired( balance_proof=balance_proof, secrethash=secrethash, message_identifier=message_identifier, ), channelidentifiers_to_channels=channel_map, pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, ) assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks