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_handle_offchain_secretreveal_after_lock_expired(): """Test that getting the secret revealed after lock expiration for the target does not end up continuously emitting EventUnlockClaimFailed Target part for https://github.com/raiden-network/raiden/issues/3086 """ setup = make_target_state() lock_expiration_block_number = channel.get_sender_expiration_threshold( setup.new_state.transfer.lock, ) lock_expiration_block = Block( block_number=lock_expiration_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=setup.new_state, state_change=lock_expiration_block, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number, ) state = iteration.new_state msg = 'At the expiration block we should get an EventUnlockClaimFailed' assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg iteration = target.state_transition( target_state=state, state_change=ReceiveSecretReveal(UNIT_SECRET, setup.initiator), channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number + 1, ) state = iteration.new_state next_block = Block( block_number=lock_expiration_block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=state, state_change=next_block, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number + 1, ) msg = 'At the next block we should not get the same event' assert not must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg
def test_target_reject_keccak_empty_hash(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) expiration = block_number + channels[0].settle_timeout - channels[0].reveal_timeout from_transfer = factories.make_signed_transfer_for( channels[0], factories.LockedTransferSignedStateProperties( transfer=factories.LockedTransferProperties( amount=lock_amount, target=channels.our_address(0), expiration=expiration, secret=EMPTY_HASH, ), ), allow_invalid=True, ) init = ActionInitTarget(route=channels.get_route(0), transfer=from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is None
def test_handle_block_lower_block_number(): """ Nothing changes. """ initiator = factories.HOP6 our_address = factories.ADDR amount = 3 block_number = 10 pseudo_random_generator = random.Random() from_channel, state = make_target_state( our_address, amount, block_number, initiator, ) new_block = Block(block_number - 1) iteration = target.state_transition( state, new_block, from_channel, pseudo_random_generator, new_block.block_number, ) assert iteration.new_state assert not iteration.events
def subdispatch_targettask( chain_state: ChainState, state_change: StateChange, token_network_identifier: TokenNetworkID, channel_identifier: ChannelID, secrethash: SecretHash, ) -> TransitionResult: block_number = chain_state.block_number sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) if not sub_task: is_valid_subtask = True target_state = None elif sub_task and isinstance(sub_task, TargetTask): is_valid_subtask = ( token_network_identifier == sub_task.token_network_identifier ) target_state = sub_task.target_state else: is_valid_subtask = False events = list() channel_state = None if is_valid_subtask: channel_state = views.get_channelstate_by_token_network_identifier( chain_state, token_network_identifier, channel_identifier, ) if channel_state: pseudo_random_generator = chain_state.pseudo_random_generator iteration = target.state_transition( target_state, state_change, channel_state, pseudo_random_generator, block_number, ) events = iteration.events if iteration.new_state: sub_task = TargetTask( token_network_identifier, channel_identifier, iteration.new_state, ) chain_state.payment_mapping.secrethashes_to_task[secrethash] = sub_task elif secrethash in chain_state.payment_mapping.secrethashes_to_task: del chain_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(chain_state, events)
def test_target_lock_is_expired_if_secret_is_not_registered_onchain(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) from_transfer = make_target_transfer(channels[0], amount=lock_amount, block_number=1) init = ActionInitTarget(channels.get_route(0), from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None secret_reveal_iteration = target.state_transition( target_state=init_transition.new_state, state_change=ReceiveSecretReveal(UNIT_SECRET, channels[0].partner_state.address), channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) expired_block_number = channel.get_receiver_expiration_threshold(from_transfer.lock) iteration = target.state_transition( target_state=secret_reveal_iteration.new_state, state_change=Block(expired_block_number, None, None), channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, ) assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {})
def test_handle_block_lower_block_number(): """ Nothing changes. """ setup = make_target_state(block_number=10) new_block = Block( block_number=setup.block_number - 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=setup.new_state, state_change=new_block, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=new_block.block_number, ) assert iteration.new_state assert not iteration.events
def test_handle_block_lower_block_number(): """ Nothing changes. """ initiator = factories.HOP6 our_address = factories.ADDR amount = 3 block_number = 1 expire = block_number + factories.UNIT_REVEAL_TIMEOUT state = make_target_state( our_address, amount, block_number, initiator, expire, ) new_block = Block(block_number - 1) iteration = target.state_transition(state, new_block) assert iteration.new_state.block_number == block_number
def test_handle_block(): """ Increase the block number. """ setup = make_target_state() new_block = Block( block_number=setup.block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=setup.new_state, state_change=new_block, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=new_block.block_number, ) assert iteration.new_state assert not iteration.events
def test_handle_block_lower_block_number(): """ Nothing changes. """ initiator = factories.HOP6 our_address = factories.ADDR amount = 3 block_number = 10 from_channel, state = make_target_state( our_address, amount, block_number, initiator, ) new_block = Block(block_number - 1) iteration = target.state_transition( state, new_block, from_channel, new_block.block_number, ) assert iteration.new_state assert not iteration.events
def test_handle_block(): """ Increase the block number. """ initiator = factories.HOP6 our_address = factories.ADDR amount = 3 block_number = 1 from_channel, state = make_target_state( our_address, amount, block_number, initiator, ) new_block = Block(block_number + 1) iteration = target.state_transition( state, new_block, from_channel, new_block.block_number, ) assert iteration.new_state assert not iteration.events
def test_state_transition(): """ Happy case testing. """ lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) from_transfer = make_target_transfer(channels[0], amount=lock_amount, initiator=initiator) init = ActionInitTarget(channels.get_route(0), from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == channels.get_route(0) assert init_transition.new_state.transfer == from_transfer first_new_block = Block( block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) first_block_iteration = target.state_transition( target_state=init_transition.new_state, state_change=first_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition( target_state=first_block_iteration.new_state, state_change=secret_reveal, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) assert reveal_iteration.events second_new_block = Block( block_number=block_number + 2, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=init_transition.new_state, state_change=second_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=second_new_block.block_number, ) assert not iteration.events balance_proof = create( BalanceProofSignedStateProperties( balance_proof=BalanceProofProperties( nonce=from_transfer.balance_proof.nonce + 1, transferred_amount=lock_amount, locked_amount=0, token_network_identifier=channels[0].token_network_identifier, channel_identifier=channels.get_route(0).channel_identifier, locksroot=EMPTY_MERKLE_ROOT, ), message_hash=b'\x00' * 32, # invalid )) balance_proof_state_change = ReceiveUnlock( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, balance_proof=balance_proof, ) proof_iteration = target.state_transition( target_state=init_transition.new_state, state_change=balance_proof_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number + 2, ) assert proof_iteration.new_state is None
def subdispatch_to_paymenttask(node_state, state_change, secrethash): block_number = node_state.block_number sub_task = node_state.payment_mapping.secrethashes_to_task.get(secrethash) events = list() if sub_task: if isinstance(sub_task, PaymentMappingState.InitiatorTask): payment_network_identifier = sub_task.payment_network_identifier token_address = sub_task.token_address token_network_state = get_token_network( node_state, payment_network_identifier, token_address, ) if token_network_state: sub_iteration = initiator_manager.state_transition( sub_task.manager_state, state_change, token_network_state.channelidentifiers_to_channels, block_number, ) events = sub_iteration.events elif isinstance(sub_task, PaymentMappingState.MediatorTask): payment_network_identifier = sub_task.payment_network_identifier token_address = sub_task.token_address token_network_state = get_token_network( node_state, payment_network_identifier, token_address, ) if token_network_state: sub_iteration = mediator.state_transition( sub_task.mediator_state, state_change, token_network_state.channelidentifiers_to_channels, block_number, ) events = sub_iteration.events elif isinstance(sub_task, PaymentMappingState.TargetTask): payment_network_identifier = sub_task.payment_network_identifier token_address = sub_task.token_address channel_identifier = sub_task.channel_identifier channel_state = views.get_channelstate_by_tokenaddress( node_state, payment_network_identifier, token_address, channel_identifier, ) if channel_state: sub_iteration = target.state_transition( sub_task.target_state, state_change, channel_state, block_number, ) events = sub_iteration.events return TransitionResult(node_state, events)
def test_state_transition(): """ Happy case testing. """ lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() our_balance = 100 our_address = factories.make_address() partner_balance = 130 from_channel = factories.make_channel( our_address=our_address, our_balance=our_balance, partner_address=UNIT_TRANSFER_SENDER, partner_balance=partner_balance, ) from_route = factories.route_from_channel(from_channel) expiration = block_number + from_channel.settle_timeout from_transfer = factories.make_signed_transfer_for( from_channel, lock_amount, initiator, our_address, expiration, UNIT_SECRET, ) init = ActionInitTarget( from_route, from_transfer, ) init_transition = target.state_transition( None, init, from_channel, pseudo_random_generator, block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == from_route assert init_transition.new_state.transfer == from_transfer first_new_block = Block(block_number + 1) first_block_iteration = target.state_transition( init_transition.new_state, first_new_block, from_channel, pseudo_random_generator, first_new_block.block_number, ) secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition( first_block_iteration.new_state, secret_reveal, from_channel, pseudo_random_generator, first_new_block, ) assert reveal_iteration.events second_new_block = Block(block_number + 2) iteration = target.state_transition( init_transition.new_state, second_new_block, from_channel, pseudo_random_generator, second_new_block.block_number, ) assert not iteration.events nonce = from_transfer.balance_proof.nonce + 1 transferred_amount = lock_amount locksroot = EMPTY_MERKLE_ROOT invalid_message_hash = b'\x00' * 32 locked_amount = 0 balance_proof = factories.make_signed_balance_proof( nonce, transferred_amount, locked_amount, from_channel.token_network_identifier, from_route.channel_identifier, locksroot, invalid_message_hash, UNIT_TRANSFER_PKEY, UNIT_TRANSFER_SENDER, ) balance_proof_state_change = ReceiveUnlock( random.randint(0, UINT64_MAX), UNIT_SECRET, balance_proof, ) proof_iteration = target.state_transition( init_transition.new_state, balance_proof_state_change, from_channel, pseudo_random_generator, block_number + 2, ) assert proof_iteration.new_state is None
def test_handle_offchain_secretreveal_after_lock_expired(): """Test that getting the secret revealed after lock expiration for the target does not end up continuously emitting EventUnlockClaimFailed Target part for https://github.com/raiden-network/raiden/issues/3086 """ 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, ) lock_expiration = state.transfer.lock.expiration lock_expiration_block_number = lock_expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2 lock_expiration_block = Block( block_number=lock_expiration_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=state, state_change=lock_expiration_block, channel_state=channel_state, pseudo_random_generator=pseudo_random_generator, block_number=lock_expiration_block_number, ) state = iteration.new_state msg = 'At the expiration block we should get an EventUnlockClaimFailed' assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg iteration = target.state_transition( target_state=state, state_change=ReceiveSecretReveal(secret, initiator), channel_state=channel_state, pseudo_random_generator=pseudo_random_generator, block_number=lock_expiration_block_number + 1, ) state = iteration.new_state next_block = Block( block_number=lock_expiration_block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=state, state_change=next_block, channel_state=channel_state, pseudo_random_generator=pseudo_random_generator, block_number=lock_expiration_block_number + 1, ) msg = 'At the next block we should not get the same event' assert not must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg
def test_target_receive_lock_expired(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) expiration = block_number + channels[0].settle_timeout - channels[0].reveal_timeout from_transfer = make_target_transfer( channels[0], amount=lock_amount, block_number=block_number, ) init = ActionInitTarget(channels.get_route(0), from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == channels.get_route(0) assert init_transition.new_state.transfer == from_transfer balance_proof = create(BalanceProofSignedStateProperties( balance_proof=BalanceProofProperties( nonce=2, transferred_amount=from_transfer.balance_proof.transferred_amount, locked_amount=0, token_network_identifier=from_transfer.balance_proof.token_network_identifier, channel_identifier=channels[0].identifier, ), message_hash=from_transfer.lock.secrethash, )) lock_expired_state_change = ReceiveLockExpired( balance_proof=balance_proof, secrethash=from_transfer.lock.secrethash, message_identifier=1, ) block_before_confirmed_expiration = expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS - 1 iteration = target.state_transition( target_state=init_transition.new_state, state_change=lock_expired_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_before_confirmed_expiration, ) assert not must_contain_entry(iteration.events, SendProcessed, {}) block_lock_expired = block_before_confirmed_expiration + 1 iteration = target.state_transition( target_state=init_transition.new_state, state_change=lock_expired_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_lock_expired, ) assert must_contain_entry(iteration.events, SendProcessed, {})
def subdispatch_to_paymenttask( chain_state: ChainState, state_change: StateChange, secrethash: SecretHash) -> TransitionResult[ChainState]: block_number = chain_state.block_number block_hash = chain_state.block_hash sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) events: List[Event] = list() if sub_task: pseudo_random_generator = chain_state.pseudo_random_generator sub_iteration: Union[TransitionResult[InitiatorPaymentState], TransitionResult[MediatorTransferState], TransitionResult[TargetTransferState], ] if isinstance(sub_task, InitiatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = get_token_network_by_address( chain_state, token_network_identifier) if token_network_state: sub_iteration = initiator_manager.state_transition( sub_task.manager_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events if sub_iteration.new_state is None: del chain_state.payment_mapping.secrethashes_to_task[ secrethash] elif isinstance(sub_task, MediatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = get_token_network_by_address( chain_state, token_network_identifier) if token_network_state: channelids_to_channels = token_network_state.channelidentifiers_to_channels sub_iteration = mediator.state_transition( mediator_state=sub_task.mediator_state, state_change=state_change, channelidentifiers_to_channels=channelids_to_channels, nodeaddresses_to_networkstates=chain_state. nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_number, block_hash=block_hash, ) events = sub_iteration.events if sub_iteration.new_state is None: del chain_state.payment_mapping.secrethashes_to_task[ secrethash] elif isinstance(sub_task, TargetTask): token_network_identifier = sub_task.token_network_identifier channel_identifier = sub_task.channel_identifier channel_state = views.get_channelstate_by_canonical_identifier( chain_state=chain_state, canonical_identifier=CanonicalIdentifier( chain_identifier=chain_state.chain_id, token_network_address=token_network_identifier, channel_identifier=channel_identifier, ), ) if channel_state: sub_iteration = target.state_transition( target_state=sub_task.target_state, state_change=state_change, channel_state=channel_state, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) events = sub_iteration.events if sub_iteration.new_state is None: del chain_state.payment_mapping.secrethashes_to_task[ secrethash] return TransitionResult(chain_state, events)
def test_state_transition(): """ Happy case testing. """ lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() our_balance = 100 our_address = factories.make_address() partner_balance = 130 from_channel = factories.make_channel( our_address=our_address, our_balance=our_balance, partner_address=UNIT_TRANSFER_SENDER, partner_balance=partner_balance, ) from_route = factories.route_from_channel(from_channel) expiration = block_number + from_channel.settle_timeout from_transfer = factories.make_signed_transfer_for( from_channel, lock_amount, initiator, our_address, expiration, UNIT_SECRET, ) init = ActionInitTarget( from_route, from_transfer, ) init_transition = target.state_transition( None, init, from_channel, pseudo_random_generator, block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == from_route assert init_transition.new_state.transfer == from_transfer first_new_block = Block(block_number + 1) first_block_iteration = target.state_transition( init_transition.new_state, first_new_block, from_channel, pseudo_random_generator, first_new_block.block_number, ) secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition( first_block_iteration.new_state, secret_reveal, from_channel, pseudo_random_generator, first_new_block, ) assert reveal_iteration.events second_new_block = Block(block_number + 2) iteration = target.state_transition( init_transition.new_state, second_new_block, from_channel, pseudo_random_generator, second_new_block.block_number, ) assert not iteration.events nonce = from_transfer.balance_proof.nonce + 1 transferred_amount = lock_amount locksroot = EMPTY_MERKLE_ROOT invalid_message_hash = b'\x00' * 32 locked_amount = 0 balance_proof = factories.make_signed_balance_proof( nonce, transferred_amount, locked_amount, from_channel.token_network_identifier, from_route.channel_identifier, locksroot, invalid_message_hash, UNIT_TRANSFER_PKEY, UNIT_TRANSFER_SENDER, ) balance_proof_state_change = ReceiveUnlock( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, balance_proof=balance_proof, ) proof_iteration = target.state_transition( init_transition.new_state, balance_proof_state_change, from_channel, pseudo_random_generator, block_number + 2, ) assert proof_iteration.new_state is None
def test_target_receive_lock_expired(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) expiration = block_number + channels[0].settle_timeout - channels[ 0].reveal_timeout from_transfer = make_target_transfer(channels[0], amount=lock_amount, block_number=block_number) init = ActionInitTarget( from_hop=channels.get_hop(0), transfer=from_transfer, balance_proof=from_transfer.balance_proof, sender=from_transfer.balance_proof.sender, # pylint: disable=no-member ) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.from_hop == channels.get_hop(0) assert init_transition.new_state.transfer == from_transfer balance_proof = create( BalanceProofSignedStateProperties( nonce=2, # pylint: disable=no-member transferred_amount=from_transfer.balance_proof.transferred_amount, locked_amount=0, canonical_identifier=channels[0].canonical_identifier, message_hash=from_transfer.lock.secrethash, )) lock_expired_state_change = ReceiveLockExpired( balance_proof=balance_proof, secrethash=from_transfer.lock.secrethash, message_identifier=1, sender=balance_proof.sender, # pylint: disable=no-member ) block_before_confirmed_expiration = expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS - 1 iteration = target.state_transition( target_state=init_transition.new_state, state_change=lock_expired_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_before_confirmed_expiration, ) assert not search_for_item(iteration.events, SendProcessed, {}) block_lock_expired = block_before_confirmed_expiration + 1 iteration = target.state_transition( target_state=init_transition.new_state, state_change=lock_expired_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_lock_expired, ) assert search_for_item(iteration.events, SendProcessed, {})
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 # Make sure that an emptyhash on chain reveal is rejected. block_number_prior_the_expiration = 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( offchain_secret_reveal_iteration.new_state, onchain_reveal, channel_state, pseudo_random_generator, block_number_prior_the_expiration, ) unlocked_onchain = channel_state.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 = secret onchain_reveal.secrethash = factories.UNIT_SECRETHASH onchain_secret_reveal_iteration = target.state_transition( offchain_secret_reveal_iteration.new_state, onchain_reveal, 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 subdispatch_to_paymenttask( chain_state: ChainState, state_change: StateChange, secrethash: SecretHash, ) -> TransitionResult[ChainState]: block_number = chain_state.block_number sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) events: List[Event] = list() sub_iteration = None if sub_task: pseudo_random_generator = chain_state.pseudo_random_generator if isinstance(sub_task, InitiatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) if token_network_state: sub_iteration = initiator_manager.state_transition( sub_task.manager_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, MediatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) if token_network_state: sub_iteration = mediator.state_transition( sub_task.mediator_state, state_change, token_network_state.channelidentifiers_to_channels, chain_state.nodeaddresses_to_networkstates, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, TargetTask): token_network_identifier = sub_task.token_network_identifier channel_identifier = sub_task.channel_identifier channel_state = views.get_channelstate_by_token_network_identifier( chain_state, token_network_identifier, channel_identifier, ) if channel_state: sub_iteration = target.state_transition( sub_task.target_state, state_change, channel_state, pseudo_random_generator, block_number, ) events = sub_iteration.events if sub_iteration and sub_iteration.new_state is None: del chain_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(chain_state, events)
def subdispatch_to_paymenttask( chain_state: ChainState, state_change: StateChange, secrethash: SecretHash, ) -> TransitionResult: block_number = chain_state.block_number sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash) events = list() sub_iteration = None if sub_task: pseudo_random_generator = chain_state.pseudo_random_generator if isinstance(sub_task, InitiatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) if token_network_state: sub_iteration = initiator_manager.state_transition( sub_task.manager_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, MediatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( chain_state, token_network_identifier, ) if token_network_state: sub_iteration = mediator.state_transition( sub_task.mediator_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, TargetTask): token_network_identifier = sub_task.token_network_identifier channel_identifier = sub_task.channel_identifier channel_state = views.get_channelstate_by_token_network_identifier( chain_state, token_network_identifier, channel_identifier, ) if channel_state: sub_iteration = target.state_transition( sub_task.target_state, state_change, channel_state, pseudo_random_generator, block_number, ) events = sub_iteration.events if sub_iteration and sub_iteration.new_state is None: del chain_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(chain_state, events)
def test_target_receive_lock_expired(): lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() our_balance = 100 our_address = factories.make_address() partner_balance = 130 from_channel = factories.make_channel( our_address=our_address, our_balance=our_balance, partner_address=UNIT_TRANSFER_SENDER, partner_balance=partner_balance, ) from_route = factories.route_from_channel(from_channel) expiration = block_number + from_channel.settle_timeout - from_channel.reveal_timeout from_transfer = factories.make_signed_transfer_for( channel_state=from_channel, amount=lock_amount, initiator=initiator, target=our_address, expiration=expiration, secret=UNIT_SECRET, ) init = ActionInitTarget( from_route, from_transfer, ) init_transition = target.state_transition( None, init, from_channel, pseudo_random_generator, block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == from_route assert init_transition.new_state.transfer == from_transfer balance_proof = factories.make_signed_balance_proof( 2, from_transfer.balance_proof.transferred_amount, 0, from_transfer.balance_proof.token_network_identifier, from_channel.identifier, EMPTY_MERKLE_ROOT, from_transfer.lock.secrethash, sender_address=UNIT_TRANSFER_SENDER, private_key=UNIT_TRANSFER_PKEY, ) lock_expired_state_change = ReceiveLockExpired( balance_proof=balance_proof, secrethash=from_transfer.lock.secrethash, message_identifier=1, ) block_before_confirmed_expiration = expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS - 1 iteration = target.state_transition( init_transition.new_state, lock_expired_state_change, from_channel, pseudo_random_generator, block_before_confirmed_expiration, ) assert not must_contain_entry(iteration.events, SendProcessed, {}) block_lock_expired = block_before_confirmed_expiration + 1 iteration = target.state_transition( init_transition.new_state, lock_expired_state_change, from_channel, pseudo_random_generator, block_lock_expired, ) assert must_contain_entry(iteration.events, SendProcessed, {})
def test_state_transition(): """ Happy case testing. """ amount = 7 block_number = 1 initiator = factories.HOP6 expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, factories.ADDR, expire, initiator, ) init = ActionInitTarget( factories.ADDR, from_route, from_transfer, block_number, ) init_transition = target.state_transition(None, init) assert init_transition.new_state is not None assert init_transition.new_state.from_route == from_route assert init_transition.new_state.from_transfer == from_transfer first_new_block = Block(block_number + 1) first_block_iteration = target.state_transition(init_transition.new_state, first_new_block) assert first_block_iteration.new_state.block_number == block_number + 1 secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition(first_block_iteration.new_state, secret_reveal) assert reveal_iteration.new_state.from_transfer.secret == factories.UNIT_SECRET second_new_block = Block(block_number + 2) second_block_iteration = target.state_transition(init_transition.new_state, second_new_block) assert second_block_iteration.new_state.block_number == block_number + 2 nonce = 11 transferred_amount = 13 locksroot = '' message_hash = '' signature = None balance_proof = BalanceProofState( nonce, transferred_amount, locksroot, from_route.channel_address, message_hash, signature, ) balance_proof_state_change = ReceiveBalanceProof( from_transfer.identifier, from_route.node_address, balance_proof, ) proof_iteration = target.state_transition( init_transition.new_state, balance_proof_state_change, ) assert proof_iteration.new_state is None
def test_target_receive_lock_expired(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) expiration = block_number + channels[0].settle_timeout - channels[ 0].reveal_timeout from_transfer = make_target_transfer( channels[0], amount=lock_amount, block_number=block_number, ) init = ActionInitTarget(channels.get_route(0), from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == channels.get_route(0) assert init_transition.new_state.transfer == from_transfer balance_proof = create( BalanceProofSignedStateProperties( balance_proof=BalanceProofProperties( nonce=2, transferred_amount=from_transfer.balance_proof. transferred_amount, locked_amount=0, token_network_identifier=from_transfer.balance_proof. token_network_identifier, channel_identifier=channels[0].identifier, ), message_hash=from_transfer.lock.secrethash, )) lock_expired_state_change = ReceiveLockExpired( balance_proof=balance_proof, secrethash=from_transfer.lock.secrethash, message_identifier=1, ) block_before_confirmed_expiration = expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS - 1 iteration = target.state_transition( target_state=init_transition.new_state, state_change=lock_expired_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_before_confirmed_expiration, ) assert not must_contain_entry(iteration.events, SendProcessed, {}) block_lock_expired = block_before_confirmed_expiration + 1 iteration = target.state_transition( target_state=init_transition.new_state, state_change=lock_expired_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_lock_expired, ) assert must_contain_entry(iteration.events, SendProcessed, {})
def test_state_transition(): """ Happy case testing. """ lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) from_transfer = make_target_transfer(channels[0], amount=lock_amount, initiator=initiator) init = ActionInitTarget(channels.get_route(0), from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == channels.get_route(0) assert init_transition.new_state.transfer == from_transfer first_new_block = Block( block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) first_block_iteration = target.state_transition( target_state=init_transition.new_state, state_change=first_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition( target_state=first_block_iteration.new_state, state_change=secret_reveal, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) assert reveal_iteration.events second_new_block = Block( block_number=block_number + 2, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=init_transition.new_state, state_change=second_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=second_new_block.block_number, ) assert not iteration.events balance_proof = create(BalanceProofSignedStateProperties( balance_proof=BalanceProofProperties( nonce=from_transfer.balance_proof.nonce + 1, transferred_amount=lock_amount, locked_amount=0, token_network_identifier=channels[0].token_network_identifier, channel_identifier=channels.get_route(0).channel_identifier, locksroot=EMPTY_MERKLE_ROOT, ), message_hash=b'\x00' * 32, # invalid )) balance_proof_state_change = ReceiveUnlock( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, balance_proof=balance_proof, ) proof_iteration = target.state_transition( target_state=init_transition.new_state, state_change=balance_proof_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number + 2, ) assert proof_iteration.new_state is None
def test_state_transition(): """ Happy case testing. """ amount = 7 block_number = 1 initiator = factories.HOP6 expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, factories.ADDR, expire, initiator, ) init = ActionInitTarget( factories.ADDR, from_route, from_transfer, block_number, ) init_transition = target.state_transition(None, init) assert init_transition.new_state is not None assert init_transition.new_state.from_route == from_route assert init_transition.new_state.from_transfer == from_transfer first_new_block = Block(block_number + 1) first_block_iteration = target.state_transition(init_transition.new_state, first_new_block) assert first_block_iteration.new_state.block_number == block_number + 1 secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition(first_block_iteration.new_state, secret_reveal) assert reveal_iteration.new_state.from_transfer.secret == factories.UNIT_SECRET second_new_block = Block(block_number + 2) second_block_iteration = target.state_transition(init_transition.new_state, second_new_block) assert second_block_iteration.new_state.block_number == block_number + 2 nonce = 11 transferred_amount = 13 locksroot = '' message_hash = '' signature = None balance_proof = BalanceProofState( nonce, transferred_amount, locksroot, from_route.channel_address, message_hash, signature, ) balance_proof_state_change = ReceiveBalanceProof( from_transfer.identifier, from_route.node_address, balance_proof, ) proof_iteration = target.state_transition( init_transition.new_state, balance_proof_state_change, ) assert proof_iteration.new_state is None
def test_state_transition(): """ Happy case testing. """ lock_amount = 7 block_number = 1 initiator = factories.make_address() pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) from_transfer = make_target_transfer(channels[0], amount=lock_amount, initiator=initiator) init = ActionInitTarget( from_hop=channels.get_hop(0), transfer=from_transfer, balance_proof=from_transfer.balance_proof, sender=from_transfer.balance_proof.sender, # pylint: disable=no-member ) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.from_hop == channels.get_hop(0) assert init_transition.new_state.transfer == from_transfer first_new_block = Block(block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash()) first_block_iteration = target.state_transition( target_state=init_transition.new_state, state_change=first_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) secret_reveal = ReceiveSecretReveal(secret=UNIT_SECRET, sender=initiator) reveal_iteration = target.state_transition( target_state=first_block_iteration.new_state, state_change=secret_reveal, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=first_new_block.block_number, ) assert reveal_iteration.events second_new_block = Block(block_number=block_number + 2, gas_limit=1, block_hash=factories.make_transaction_hash()) iteration = target.state_transition( target_state=init_transition.new_state, state_change=second_new_block, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=second_new_block.block_number, ) assert not iteration.events balance_proof = create( BalanceProofSignedStateProperties( nonce=from_transfer.balance_proof.nonce + 1, # pylint: disable=no-member transferred_amount=lock_amount, locked_amount=0, canonical_identifier=factories.make_canonical_identifier( token_network_address=channels[0].token_network_address, channel_identifier=channels.get_hop(0).channel_identifier, ), locksroot=LOCKSROOT_OF_NO_LOCKS, message_hash=b"\x00" * 32, # invalid )) balance_proof_state_change = ReceiveUnlock( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, balance_proof=balance_proof, sender=balance_proof.sender, # pylint: disable=no-member ) proof_iteration = target.state_transition( target_state=init_transition.new_state, state_change=balance_proof_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number + 2, ) assert proof_iteration.new_state is None
def subdispatch_to_paymenttask(node_state, state_change, secrethash): block_number = node_state.block_number sub_task = node_state.payment_mapping.secrethashes_to_task.get(secrethash) events = list() sub_iteration = None if sub_task: pseudo_random_generator = node_state.pseudo_random_generator if isinstance(sub_task, PaymentMappingState.InitiatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( node_state, token_network_identifier, ) if token_network_state: sub_iteration = initiator_manager.state_transition( sub_task.manager_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, PaymentMappingState.MediatorTask): token_network_identifier = sub_task.token_network_identifier token_network_state = views.get_token_network_by_identifier( node_state, token_network_identifier, ) if token_network_state: sub_iteration = mediator.state_transition( sub_task.mediator_state, state_change, token_network_state.channelidentifiers_to_channels, pseudo_random_generator, block_number, ) events = sub_iteration.events elif isinstance(sub_task, PaymentMappingState.TargetTask): token_network_identifier = sub_task.token_network_identifier channel_identifier = sub_task.channel_identifier token_network_state = views.get_token_network_by_identifier( node_state, token_network_identifier, ) channel_state = views.get_channelstate_by_token_network_identifier( node_state, token_network_identifier, channel_identifier, ) if channel_state: sub_iteration = target.state_transition( sub_task.target_state, state_change, channel_state, pseudo_random_generator, block_number, ) events = sub_iteration.events if sub_iteration and sub_iteration.new_state is None: del node_state.payment_mapping.secrethashes_to_task[secrethash] return TransitionResult(node_state, events)
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, block_hash=factories.make_block_hash(), ) 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, block_hash=factories.make_block_hash(), ) assert len(extra_block_handle_transition.events) == 0