def handle_action_transfer_direct( token_network_state, state_change, pseudo_random_generator, block_number, ): receiver_address = state_change.receiver_address channel_state = token_network_state.partneraddresses_to_channels.get(receiver_address) if channel_state: iteration = channel.state_transition( channel_state, state_change, pseudo_random_generator, block_number, ) events = iteration.events else: failure = EventTransferSentFailed( state_change.identifier, 'Unknown partner channel', ) events = [failure] return TransitionResult(token_network_state, events)
def subdispatch_to_channel_by_id( token_network_state, state_change, pseudo_random_generator, block_number, ): events = list() ids_to_channels = token_network_state.channelidentifiers_to_channels channel_state = ids_to_channels.get(state_change.channel_identifier) if channel_state: result = channel.state_transition( channel_state, state_change, pseudo_random_generator, block_number, ) if result.new_state is None: del ids_to_channels[state_change.channel_identifier] else: ids_to_channels[state_change.channel_identifier] = result.new_state events.extend(result.events) return TransitionResult(token_network_state, events)
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 handle_batch_unlock( token_network_state, state_change, pseudo_random_generator, block_number, ): participant1 = state_change.participant participant2 = state_change.partner events = list() for channel_state in list(token_network_state.channelidentifiers_to_channels.values()): are_addresses_valid1 = ( channel_state.our_state.address == participant1 and channel_state.partner_state.address == participant2 ) are_addresses_valid2 = ( channel_state.our_state.address == participant2 and channel_state.partner_state.address == participant1 ) is_valid_locksroot = True is_valid_channel = ( (are_addresses_valid1 or are_addresses_valid2) and is_valid_locksroot ) if is_valid_channel: sub_iteration = channel.state_transition( channel_state, state_change, pseudo_random_generator, block_number, ) events.extend(sub_iteration.events) if sub_iteration.new_state is None: token_network_state.partneraddresses_to_channelidentifiers[ channel_state.partner_state.address ].remove(channel_state.identifier) del token_network_state.channelidentifiers_to_channels[ channel_state.identifier ] return TransitionResult(token_network_state, events)
def test_channelstate_repeated_contract_balance(): """Handling the same blockchain event multiple times must change the balance only once. """ deposit_block_number = 10 block_number = deposit_block_number + DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK + 1 our_model1, _ = create_model(70) partner_model1, _ = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) deposit_amount = 10 balance1_new = our_model1.balance + deposit_amount deposit_transaction = TransactionChannelNewBalance( our_model1.participant_address, balance1_new, deposit_block_number, ) state_change = ContractReceiveChannelNewBalance( channel_state.token_network_identifier, channel_state.identifier, deposit_transaction, ) our_model2 = our_model1._replace( balance=balance1_new, distributable=balance1_new, contract_balance=balance1_new, ) partner_model2 = partner_model1 pseudo_random_generator = random.Random() for _ in range(10): iteration = channel.state_transition( deepcopy(channel_state), state_change, pseudo_random_generator, block_number, ) new_state = iteration.new_state assert_partner_state(new_state.our_state, new_state.partner_state, our_model2) assert_partner_state(new_state.partner_state, new_state.our_state, partner_model2)
def subdispatch_to_all_channels( chain_state: ChainState, state_change: StateChange, block_number: typing.BlockNumber, ) -> TransitionResult: events = list() for payment_network in chain_state.identifiers_to_paymentnetworks.values(): for token_network_state in payment_network.tokenidentifiers_to_tokennetworks.values(): for channel_state in token_network_state.channelidentifiers_to_channels.values(): result = channel.state_transition( channel_state, state_change, chain_state.pseudo_random_generator, block_number, ) events.extend(result.events) return TransitionResult(chain_state, events)
def subdispatch_to_all_channels( chain_state: ChainState, state_change: StateChange, block_number: BlockNumber, ) -> TransitionResult: events = list() for payment_network in chain_state.identifiers_to_paymentnetworks.values(): for token_network_state in payment_network.tokenidentifiers_to_tokennetworks.values(): for channel_state in token_network_state.channelidentifiers_to_channels.values(): result = channel.state_transition( channel_state, state_change, chain_state.pseudo_random_generator, block_number, ) events.extend(result.events) return TransitionResult(chain_state, events)
def test_channelstate_update_contract_balance(): """A blockchain event for a new balance must increase the respective participants balance. """ deposit_block_number = 10 block_number = deposit_block_number + DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK + 1 our_model1, _ = create_model(70) partner_model1, _ = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) deposit_amount = 10 balance1_new = our_model1.balance + deposit_amount deposit_transaction = TransactionChannelNewBalance( our_model1.participant_address, balance1_new, deposit_block_number, ) state_change = ContractReceiveChannelNewBalance( channel_state.token_network_identifier, channel_state.identifier, deposit_transaction, ) pseudo_random_generator = random.Random() iteration = channel.state_transition( deepcopy(channel_state), state_change, pseudo_random_generator, block_number, ) new_state = iteration.new_state our_model2 = our_model1._replace( balance=balance1_new, distributable=balance1_new, contract_balance=balance1_new, ) partner_model2 = partner_model1 assert_partner_state(new_state.our_state, new_state.partner_state, our_model2) assert_partner_state(new_state.partner_state, new_state.our_state, partner_model2)
def handle_batch_unlock( token_network_state: TokenNetworkState, state_change: ContractReceiveChannelBatchUnlock, pseudo_random_generator: random.Random, block_number: BlockNumber, block_hash: BlockHash, ): participant1 = state_change.participant participant2 = state_change.partner events = list() for channel_state in list( token_network_state.channelidentifiers_to_channels.values()): are_addresses_valid1 = (channel_state.our_state.address == participant1 and channel_state.partner_state.address == participant2) are_addresses_valid2 = (channel_state.our_state.address == participant2 and channel_state.partner_state.address == participant1) is_valid_locksroot = True is_valid_channel = ((are_addresses_valid1 or are_addresses_valid2) and is_valid_locksroot) if is_valid_channel: sub_iteration = channel.state_transition( channel_state=channel_state, state_change=state_change, block_number=block_number, block_hash=block_hash, ) events.extend(sub_iteration.events) if sub_iteration.new_state is None: token_network_state.partneraddresses_to_channelidentifiers[ channel_state.partner_state.address].remove( channel_state.identifier) del token_network_state.channelidentifiers_to_channels[ channel_state.identifier] return TransitionResult(token_network_state, events)
def test_channelstate_decreasing_contract_balance(): """A blockchain event for a new balance that decrease the balance must be ignored. """ deposit_block_number = 10 block_number = deposit_block_number + DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK + 1 our_model1, _ = create_model(70) partner_model1, _ = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) payment_network_identifier = factories.make_address() token_address = factories.make_address() amount = 10 balance1_new = our_model1.balance - amount deposit_transaction = TransactionChannelNewBalance( our_model1.participant_address, balance1_new, deposit_block_number, ) state_change = ContractReceiveChannelNewBalance( payment_network_identifier, token_address, channel_state.identifier, deposit_transaction, ) pseudo_random_generator = random.Random() iteration = channel.state_transition( deepcopy(channel_state), state_change, pseudo_random_generator, block_number, ) new_state = iteration.new_state assert_partner_state(new_state.our_state, new_state.partner_state, our_model1) assert_partner_state(new_state.partner_state, new_state.our_state, partner_model1)
def handle_batch_unlock( token_network_state, state_change, pseudo_random_generator, block_number, ): participant1 = state_change.participant participant2 = state_change.partner events = list() for channel_state in list( token_network_state.channelidentifiers_to_channels.values()): are_addresses_valid1 = (channel_state.our_state.address == participant1 and channel_state.partner_state.address == participant2) are_addresses_valid2 = (channel_state.our_state.address == participant2 and channel_state.partner_state.address == participant1) is_valid_locksroot = True is_valid_channel = ((are_addresses_valid1 or are_addresses_valid2) and is_valid_locksroot) if is_valid_channel: sub_iteration = channel.state_transition( channel_state, state_change, pseudo_random_generator, block_number, ) events.extend(sub_iteration.events) if sub_iteration.new_state is None: del token_network_state.partneraddresses_to_channels[ channel_state.partner_state.address][ channel_state.identifier] del token_network_state.channelidentifiers_to_channels[ channel_state.identifier] return TransitionResult(token_network_state, events)
def handle_receive_transfer_refund( token_network_state, state_change, pseudo_random_generator, block_number, ): events = list() channel_id = state_change.balance_proof.channel_identifier channel_state = token_network_state.channelidentifiers_to_channels.get(channel_id) if channel_state: result = channel.state_transition( channel_state, state_change, pseudo_random_generator, block_number, ) events.extend(result.events) return TransitionResult(token_network_state, events)
def subdispatch_to_channel_by_id( token_network_state, state_change, pseudo_random_generator, block_number, ): events = list() ids_to_channels = token_network_state.channelidentifiers_to_channels channel_state = ids_to_channels.get(state_change.channel_identifier) if channel_state: result = channel.state_transition( channel_state, state_change, pseudo_random_generator, block_number, ) events.extend(result.events) return TransitionResult(token_network_state, events)
def handle_receive_transfer_refund( token_network_state, state_change, pseudo_random_generator, block_number, ): events = list() channel_id = state_change.balance_proof.channel_address channel_state = token_network_state.channelidentifiers_to_channels.get(channel_id) if channel_state: result = channel.state_transition( channel_state, state_change, pseudo_random_generator, block_number, ) events.extend(result.events) return TransitionResult(token_network_state, events)
def test_initiator_lock_expired_must_not_be_sent_if_channel_is_closed(): """ If the channel is closed there is no rason to send balance proofs off-chain, so a remove expired lock must not be sent when the channel is closed. """ block_number = 10 setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=block_number) 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 expiration_block_number = setup.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2 block = Block( block_number=expiration_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) channel_map = {channel_state.identifier: channel_state} iteration = initiator_manager.state_transition( setup.current_state, block, channel_map, setup.prng, expiration_block_number, ) assert events.must_contain_entry(iteration.events, SendLockExpired, {}) is None
def subdispatch_to_all_channels( chain_state: ChainState, state_change: StateChange, block_number: BlockNumber, block_hash: BlockHash, ) -> TransitionResult[ChainState]: events = list() for payment_network in chain_state.identifiers_to_paymentnetworks.values(): for token_network_state in payment_network.tokenidentifiers_to_tokennetworks.values( ): for channel_state in token_network_state.channelidentifiers_to_channels.values( ): result = channel.state_transition( channel_state=channel_state, state_change=state_change, block_number=block_number, block_hash=block_hash, ) events.extend(result.events) return TransitionResult(chain_state, events)
def test_initiator_lock_expired_must_not_be_sent_if_channel_is_closed(): """ If the channel is closed there is no rason to send balance proofs off-chain, so a remove expired lock must not be sent when the channel is closed. """ block_number = 10 setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=block_number) 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 expiration_block_number = channel.get_sender_expiration_threshold(setup.lock) block = Block( block_number=expiration_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) channel_map = {channel_state.identifier: channel_state} iteration = initiator_manager.state_transition( setup.current_state, block, channel_map, setup.prng, expiration_block_number, ) assert events.must_contain_entry(iteration.events, SendLockExpired, {}) is None
def subdispatch_to_all_channels( chain_state: ChainState, state_change: StateChange, block_number: BlockNumber, block_hash: BlockHash, ) -> TransitionResult[ChainState]: events = list() for token_network_registry in chain_state.identifiers_to_tokennetworkregistries.values(): for ( token_network_state ) in token_network_registry.tokennetworkaddresses_to_tokennetworks.values(): for channel_state in token_network_state.channelidentifiers_to_channels.values(): result = channel.state_transition( channel_state=channel_state, state_change=state_change, block_number=block_number, block_hash=block_hash, pseudo_random_generator=chain_state.pseudo_random_generator, ) events.extend(result.events) return TransitionResult(chain_state, events)
def test_channelstate_repeated_contract_balance(): """Handling the same blockchain event multiple times must change the balance only once. """ block_number = 10 our_model1, _ = create_model(70) partner_model1, _ = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) deposit_amount = 10 balance1_new = our_model1.balance + deposit_amount state_change = ContractReceiveChannelNewBalance( channel_state.identifier, our_model1.participant_address, balance1_new, ) our_model2 = our_model1._replace( balance=balance1_new, distributable=balance1_new, contract_balance=balance1_new, ) partner_model2 = partner_model1 for _ in range(10): iteration = channel.state_transition( deepcopy(channel_state), state_change, block_number, ) new_state = iteration.new_state assert_partner_state(new_state.our_state, new_state.partner_state, our_model2) assert_partner_state(new_state.partner_state, new_state.our_state, partner_model2)
def handle_action_transfer_direct( payment_network_identifier, token_network_state, state_change, pseudo_random_generator, block_number, ): receiver_address = state_change.receiver_address channels = [ token_network_state.channelidentifiers_to_channels[channel_id] for channel_id in token_network_state. partneraddresses_to_channelidentifiers[receiver_address] ] channel_states = views.filter_channels_by_status( channels, [CHANNEL_STATE_UNUSABLE], ) if channel_states: iteration = channel.state_transition( channel_states[-1], state_change, pseudo_random_generator, block_number, ) events = iteration.events else: failure = EventPaymentSentFailed( payment_network_identifier, state_change.token_network_identifier, state_change.identifier, receiver_address, 'Unknown partner channel', ) events = [failure] return TransitionResult(token_network_state, events)
def test_channelstate_update_contract_balance(): """A blockchain event for a new balance must increase the respective participants balance. """ block_number = 10 our_model1, _ = create_model(70) partner_model1, _ = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) deposit_amount = 10 balance1_new = our_model1.balance + deposit_amount state_change = ContractReceiveChannelNewBalance( channel_state.identifier, our_model1.participant_address, balance1_new, ) iteration = channel.state_transition( deepcopy(channel_state), state_change, block_number, ) new_state = iteration.new_state our_model2 = our_model1._replace( balance=balance1_new, distributable=balance1_new, contract_balance=balance1_new, ) partner_model2 = partner_model1 assert_partner_state(new_state.our_state, new_state.partner_state, our_model2) assert_partner_state(new_state.partner_state, new_state.our_state, partner_model2)
def test_deposit_must_wait_for_confirmation(): block_number = 10 confirmed_deposit_block_number = block_number + DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK + 1 our_model1, _ = create_model(0) partner_model1, _ = create_model(0) channel_state = create_channel_from_models(our_model1, partner_model1) payment_network_identifier = factories.make_address() token_address = factories.make_address() deposit_amount = 10 balance1_new = our_model1.balance + deposit_amount our_model2 = our_model1._replace( balance=balance1_new, distributable=balance1_new, contract_balance=balance1_new, ) partner_model2 = partner_model1 assert channel_state.our_state.contract_balance == 0 assert channel_state.partner_state.contract_balance == 0 deposit_transaction = TransactionChannelNewBalance( channel_state.our_state.address, deposit_amount, block_number, ) new_balance = ContractReceiveChannelNewBalance( payment_network_identifier, token_address, channel_state.identifier, deposit_transaction, ) pseudo_random_generator = random.Random() iteration = channel.state_transition( deepcopy(channel_state), new_balance, pseudo_random_generator, block_number, ) unconfirmed_state = iteration.new_state for block_number in range(block_number, confirmed_deposit_block_number): unconfirmed_block = Block(block_number) iteration = channel.state_transition( deepcopy(unconfirmed_state), unconfirmed_block, pseudo_random_generator, block_number, ) unconfirmed_state = iteration.new_state assert_partner_state( unconfirmed_state.our_state, unconfirmed_state.partner_state, our_model1, ) assert_partner_state( unconfirmed_state.partner_state, unconfirmed_state.our_state, partner_model1, ) confirmed_block = Block(confirmed_deposit_block_number) iteration = channel.state_transition( deepcopy(unconfirmed_state), confirmed_block, pseudo_random_generator, confirmed_deposit_block_number, ) confirmed_state = iteration.new_state assert_partner_state(confirmed_state.our_state, confirmed_state.partner_state, our_model2) assert_partner_state(confirmed_state.partner_state, confirmed_state.our_state, partner_model2)
def test_channel_cleared_after_two_unlocks(): our_model, _ = create_model(balance=700, merkletree_width=1) partner_model, partner_key1 = create_model(balance=700, merkletree_width=1) channel_state = create_channel_from_models(our_model, partner_model, partner_key1) block_number = 1 block_hash = make_block_hash() def make_unlock(unlock_end, partner_end): batch_unlock = ContractReceiveChannelBatchUnlock( transaction_hash=make_transaction_hash(), canonical_identifier=channel_state.canonical_identifier, participant=partner_end.address, partner=unlock_end.address, locksroot=unlock_end.balance_proof.locksroot, unlocked_amount=10, returned_tokens=0, block_number=block_number, block_hash=block_hash, ) return batch_unlock settle_channel = ContractReceiveChannelSettled( transaction_hash=make_transaction_hash(), canonical_identifier=channel_state.canonical_identifier, our_onchain_locksroot=merkleroot(channel_state.our_state.merkletree), partner_onchain_locksroot=merkleroot(channel_state.partner_state.merkletree), block_number=1, block_hash=make_block_hash(), ) iteration = channel.state_transition(channel_state, settle_channel, block_number, block_hash) msg = "both participants have pending locks, merkleroot must not be empty" assert iteration.new_state.our_state.onchain_locksroot is not EMPTY_MERKLE_ROOT, msg assert iteration.new_state.partner_state.onchain_locksroot is not EMPTY_MERKLE_ROOT, msg batch_unlock = make_unlock(channel_state.our_state, channel_state.partner_state) iteration = channel.state_transition( iteration.new_state, batch_unlock, block_number, block_hash ) msg = "all of our locks has been unlocked, onchain state must be updated" assert iteration.new_state.our_state.onchain_locksroot is EMPTY_MERKLE_ROOT, msg msg = "partner has pending locks, the merkleroot must not be cleared" assert iteration.new_state.partner_state.onchain_locksroot is not EMPTY_MERKLE_ROOT, msg msg = "partner locksroot is not unlocked, channel should not have been cleaned" assert iteration.new_state is not None, msg # processing the same unlock twice must not count iteration = channel.state_transition( iteration.new_state, batch_unlock, block_number, block_hash ) msg = "partner has pending locks, the merkleroot must not be cleared" assert iteration.new_state.partner_state.onchain_locksroot is not EMPTY_MERKLE_ROOT, msg msg = "partner locksroot is not unlocked, channel should not have been cleaned" assert iteration.new_state is not None, msg iteration = channel.state_transition( iteration.new_state, make_unlock(channel_state.partner_state, channel_state.our_state), block_number, block_hash, ) msg = "all unlocks have been done, channel must be cleared" assert iteration.new_state is None, msg
def test_withdraw_lock_with_a_large_expiration( tester_registry_address, deposit, tester_channels, tester_chain, tester_token, settle_timeout, ): """ Withdraw must accept a lock that expires after the settlement period. """ pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) pseudo_random_generator = random.Random() initial_balance0 = tester_token.balanceOf(address0, sender=pkey0) initial_balance1 = tester_token.balanceOf(address1, sender=pkey0) # use a really large expiration lock_expiration = tester_chain.block.number + settle_timeout * 5 # work around for the python expiration validation bad_block_number = lock_expiration - 10 channel.state_transition( channel0, Block(bad_block_number), pseudo_random_generator, bad_block_number, ) lock_amount = 29 secret = sha3(b'test_withdraw_lock_with_a_large_expiration') lock_secrethash = sha3(secret) lock = Lock( amount=lock_amount, expiration=lock_expiration, secrethash=lock_secrethash, ) mediated0 = make_mediated_transfer( tester_registry_address, channel0, channel1, address0, address1, lock, pkey0, secret, ) nettingchannel.close(sender=pkey0) mediated0_hash = sha3(mediated0.packed().data[:-65]) nettingchannel.updateTransfer( mediated0.nonce, mediated0.transferred_amount, mediated0.locksroot, mediated0_hash, mediated0.signature, sender=pkey1, ) unlock_proofs = channel.get_known_unlocks(channel1.partner_state) proof = unlock_proofs[0] nettingchannel.withdraw( proof.lock_encoded, b''.join(proof.merkle_proof), proof.secret, sender=pkey1, ) tester_chain.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey0) balance0 = initial_balance0 + deposit - lock_amount balance1 = initial_balance1 + deposit + lock_amount assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey0) == balance1 assert tester_token.balanceOf(nettingchannel.address, sender=pkey0) == 0
def test_withdraw( tester_registry_address, deposit, settle_timeout, reveal_timeout, tester_channels, tester_chain, tester_token, ): pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] pseudo_random_generator = random.Random() address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial_balance0 = tester_token.balanceOf(address0, sender=pkey0) initial_balance1 = tester_token.balanceOf(address1, sender=pkey0) lock_amount = 31 lock_expiration = tester_chain.block.number + reveal_timeout + 5 secret = b'secretsecretsecretsecretsecretse' secrethash = sha3(secret) new_block = Block(tester_chain.block.number) channel.state_transition( channel0, new_block, pseudo_random_generator, new_block.block_number, ) channel.state_transition( channel1, new_block, pseudo_random_generator, new_block.block_number, ) lock0 = Lock(lock_amount, lock_expiration, secrethash) mediated0 = make_mediated_transfer( tester_registry_address, channel0, channel1, address0, address1, lock0, pkey0, secret, ) # withdraw the pending transfer sent to us by our partner lock_state = lockstate_from_lock(mediated0.lock) proof = channel.compute_proof_for_lock( channel1.partner_state, secret, lock_state, ) mediated0_hash = sha3(mediated0.packed().data[:-65]) nettingchannel.close( mediated0.nonce, mediated0.transferred_amount, mediated0.locksroot, mediated0_hash, mediated0.signature, sender=pkey1, ) tester_chain.mine(number_of_blocks=1) nettingchannel.withdraw( proof.lock_encoded, b''.join(proof.merkle_proof), proof.secret, sender=pkey1, ) tester_chain.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey0) balance0 = initial_balance0 + deposit - lock0.amount balance1 = initial_balance1 + deposit + lock0.amount assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey0) == balance1 assert tester_token.balanceOf(nettingchannel.address, sender=pkey0) == 0
def test_withdraw_both_participants( tester_registry_address, deposit, settle_timeout, reveal_timeout, tester_channels, tester_chain, tester_token, ): pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] pseudo_random_generator = random.Random() address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial_balance0 = tester_token.balanceOf(address0, sender=pkey0) initial_balance1 = tester_token.balanceOf(address1, sender=pkey0) secret = b'secretsecretsecretsecretsecretse' secrethash = sha3(secret) lock_amount = 31 lock01_expiration = tester_chain.block.number + settle_timeout - 1 * reveal_timeout lock10_expiration = tester_chain.block.number + settle_timeout - 2 * reveal_timeout new_block = Block(tester_chain.block.number) channel.state_transition( channel0, new_block, pseudo_random_generator, new_block.block_number, ) channel.state_transition( channel1, new_block, pseudo_random_generator, new_block.block_number, ) # using the same secrethash and amount is intentional lock01 = Lock(lock_amount, lock01_expiration, secrethash) lock10 = Lock(lock_amount, lock10_expiration, secrethash) mediated01 = make_mediated_transfer( tester_registry_address, channel0, channel1, address0, address1, lock01, pkey0, secret, ) mediated10 = make_mediated_transfer( tester_registry_address, channel1, channel0, address1, address0, lock10, pkey1, secret, ) mediated01_hash = sha3(mediated01.packed().data[:-65]) nettingchannel.close( mediated01.nonce, mediated01.transferred_amount, mediated01.locksroot, mediated01_hash, mediated01.signature, sender=pkey1, ) tester_chain.mine(number_of_blocks=1) mediated10_hash = sha3(mediated10.packed().data[:-65]) nettingchannel.updateTransfer( mediated10.nonce, mediated10.transferred_amount, mediated10.locksroot, mediated10_hash, mediated10.signature, sender=pkey0, ) tester_chain.mine(number_of_blocks=1) lock_state01 = lockstate_from_lock(mediated01.lock) proof01 = channel.compute_proof_for_lock( channel1.partner_state, secret, lock_state01, ) nettingchannel.withdraw( proof01.lock_encoded, b''.join(proof01.merkle_proof), proof01.secret, sender=pkey1, ) lock_state10 = lockstate_from_lock(mediated10.lock) proof10 = channel.compute_proof_for_lock( channel0.partner_state, secret, lock_state10, ) nettingchannel.withdraw( proof10.lock_encoded, b''.join(proof10.merkle_proof), proof10.secret, sender=pkey0, ) tester_chain.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey0) balance0 = initial_balance0 + deposit - lock01.amount + lock10.amount balance1 = initial_balance1 + deposit + lock01.amount - lock10.amount assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey0) == balance1 assert tester_token.balanceOf(nettingchannel.address, sender=pkey0) == 0
def test_withdraw_expired_lock( tester_registry_address, reveal_timeout, tester_channels, tester_chain, ): pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] pseudo_random_generator = random.Random() lock_timeout = reveal_timeout + 5 lock_expiration = tester_chain.block.number + lock_timeout secret = b'expiredlockexpiredlockexpiredloc' secrethash = sha3(secret) new_block = Block(tester_chain.block.number) channel.state_transition( channel0, new_block, pseudo_random_generator, new_block.block_number, ) channel.state_transition( channel1, new_block, pseudo_random_generator, new_block.block_number, ) lock1 = Lock(amount=31, expiration=lock_expiration, secrethash=secrethash) mediated0 = make_mediated_transfer( tester_registry_address, channel1, channel0, privatekey_to_address(pkey0), privatekey_to_address(pkey1), lock1, pkey1, secret, ) mediated0_hash = sha3(mediated0.packed().data[:-65]) nettingchannel.close( mediated0.nonce, mediated0.transferred_amount, mediated0.locksroot, mediated0_hash, mediated0.signature, sender=pkey0, ) # expire the lock tester_chain.mine(number_of_blocks=lock_timeout + 1) unlock_proofs = channel.get_known_unlocks(channel0.partner_state) proof = unlock_proofs[0] with pytest.raises(TransactionFailed): nettingchannel.withdraw( proof.lock_encoded, b''.join(proof.merkle_proof), proof.secret, sender=pkey0, )
def test_settle_with_locked_mediated_transfer_for_closing_party( deposit, settle_timeout, reveal_timeout, tester_chain, tester_channels, tester_token): """ Test settle with a locked mediated transfer for the closing address. """ pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] payment_network_identifier = factories.make_address() pseudo_random_generator = random.Random() address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial0 = tester_token.balanceOf(address0, sender=pkey0) initial1 = tester_token.balanceOf(address1, sender=pkey0) transferred_amount0 = 30 increase_transferred_amount( payment_network_identifier, channel0, channel1, transferred_amount0, pkey0, ) expiration0 = tester_chain.block.number + reveal_timeout + 5 new_block = Block(tester_chain.block.number) channel.state_transition( channel0, new_block, pseudo_random_generator, new_block.block_number, ) channel.state_transition( channel1, new_block, pseudo_random_generator, new_block.block_number, ) lock0 = Lock(amount=29, expiration=expiration0, secrethash=sha3(b'lock1')) mediated0 = make_mediated_transfer( channel0, channel1, address0, address1, lock0, pkey0, ) mediated0_hash = sha3(mediated0.packed().data[:-65]) nettingchannel.close( mediated0.nonce, mediated0.transferred_amount, mediated0.locksroot, mediated0_hash, mediated0.signature, sender=pkey1, ) tester_chain.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey1) # the balances only change by transferred_amount because the lock was /not/ unlocked balance0 = initial0 + deposit - transferred_amount0 balance1 = initial1 + transferred_amount0 assert tester_token.balanceOf(nettingchannel.address, sender=pkey0) == 0 assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey0) == balance1
def test_channel_cleared_after_two_unlocks(): our_model, _ = create_model(balance=700, num_pending_locks=1) partner_model, partner_key1 = create_model(balance=700, num_pending_locks=1) channel_state = create_channel_from_models(our_model, partner_model, partner_key1) block_number = 1 block_hash = make_block_hash() pseudo_random_generator = random.Random() def make_unlock(unlock_end, partner_end): batch_unlock = ContractReceiveChannelBatchUnlock( transaction_hash=make_transaction_hash(), canonical_identifier=channel_state.canonical_identifier, receiver=partner_end.address, sender=unlock_end.address, locksroot=unlock_end.balance_proof.locksroot, unlocked_amount=10, returned_tokens=0, block_number=block_number, block_hash=block_hash, ) return batch_unlock settle_channel = ContractReceiveChannelSettled( transaction_hash=make_transaction_hash(), canonical_identifier=channel_state.canonical_identifier, our_onchain_locksroot=compute_locksroot( channel_state.our_state.pending_locks), partner_onchain_locksroot=compute_locksroot( channel_state.partner_state.pending_locks), block_number=1, block_hash=make_block_hash(), ) iteration = channel.state_transition( channel_state=channel_state, state_change=settle_channel, block_number=block_number, block_hash=block_hash, pseudo_random_generator=pseudo_random_generator, ) msg = "both participants have pending locks, locksroot must not represent the empty list" assert iteration.new_state.our_state.onchain_locksroot != LOCKSROOT_OF_NO_LOCKS, msg assert iteration.new_state.partner_state.onchain_locksroot != LOCKSROOT_OF_NO_LOCKS, msg batch_unlock = make_unlock(channel_state.our_state, channel_state.partner_state) iteration = channel.state_transition( channel_state=iteration.new_state, state_change=batch_unlock, block_number=block_number, block_hash=block_hash, pseudo_random_generator=pseudo_random_generator, ) msg = "all of our locks has been unlocked, onchain state must be updated" assert iteration.new_state.our_state.onchain_locksroot is LOCKSROOT_OF_NO_LOCKS, msg msg = "partner has pending locks, the locksroot must not represent the empty list" assert iteration.new_state.partner_state.onchain_locksroot is not LOCKSROOT_OF_NO_LOCKS, msg msg = "partner locksroot is not unlocked, channel should not have been cleaned" assert iteration.new_state is not None, msg # processing the same unlock twice must not count iteration = channel.state_transition( channel_state=iteration.new_state, state_change=batch_unlock, block_number=block_number, block_hash=block_hash, pseudo_random_generator=pseudo_random_generator, ) msg = "partner has pending locks, the locksroot must not represent the empty list" assert iteration.new_state.partner_state.onchain_locksroot is not LOCKSROOT_OF_NO_LOCKS, msg msg = "partner locksroot is not unlocked, channel should not have been cleaned" assert iteration.new_state is not None, msg iteration = channel.state_transition( channel_state=iteration.new_state, state_change=make_unlock(channel_state.partner_state, channel_state.our_state), block_number=block_number, block_hash=block_hash, pseudo_random_generator=pseudo_random_generator, ) msg = "all unlocks have been done, channel must be cleared" assert iteration.new_state is None, msg
def test_mediated_after_direct_transfer( reveal_timeout, settle_timeout, deposit, tester_chain, tester_channels, tester_token, ): """ The transfer types must not change the behavior of the dispute. """ pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] payment_network_identifier = factories.make_address() pseudo_random_generator = random.Random() address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial_balance0 = tester_token.balanceOf(address0, sender=pkey0) initial_balance1 = tester_token.balanceOf(address1, sender=pkey0) first_amount0 = 90 make_direct_transfer_from_channel( payment_network_identifier, channel0, channel1, first_amount0, pkey0, ) lock_expiration = tester_chain.block.number + reveal_timeout + 5 new_block = Block(tester_chain.block.number) channel.state_transition( channel0, new_block, pseudo_random_generator, new_block.block_number, ) channel.state_transition( channel1, new_block, pseudo_random_generator, new_block.block_number, ) lock1 = Lock(amount=31, expiration=lock_expiration, secrethash=sha3(b'lock2')) second_mediated0 = make_mediated_transfer( payment_network_identifier, channel0, channel1, address0, address1, lock1, pkey0, ) nettingchannel.close(sender=pkey0) second_mediated0_hash = sha3(second_mediated0.packed().data[:-65]) nettingchannel.updateTransfer( second_mediated0.nonce, second_mediated0.transferred_amount, second_mediated0.locksroot, second_mediated0_hash, second_mediated0.signature, sender=pkey1, ) tester_chain.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey0) # the balances only change by transferred_amount because the lock was /not/ unlocked balance0 = initial_balance0 + deposit - first_amount0 balance1 = initial_balance1 + deposit + first_amount0 assert tester_token.balanceOf(nettingchannel.address, sender=pkey1) == 0 assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey1) == balance1
def test_settle_two_locked_mediated_transfer_messages( deposit, settle_timeout, reveal_timeout, tester_chain, tester_channels, tester_token, ): pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] payment_network_identifier = factories.make_address() pseudo_random_generator = random.Random() address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial_balance0 = tester_token.balanceOf(address0, sender=pkey0) initial_balance1 = tester_token.balanceOf(address1, sender=pkey1) transferred_amount0 = 30 increase_transferred_amount( payment_network_identifier, channel0, channel1, transferred_amount0, pkey0, ) transferred_amount1 = 70 increase_transferred_amount( payment_network_identifier, channel1, channel0, transferred_amount1, pkey1, ) expiration0 = tester_chain.block.number + reveal_timeout + 5 new_block = Block(tester_chain.block.number) channel.state_transition( channel0, new_block, pseudo_random_generator, new_block.block_number, ) channel.state_transition( channel1, new_block, pseudo_random_generator, new_block.block_number, ) lock0 = Lock(amount=29, expiration=expiration0, secrethash=sha3(b'lock1')) mediated0 = make_mediated_transfer( payment_network_identifier, channel0, channel1, address0, address1, lock0, pkey0, ) lock_expiration1 = tester_chain.block.number + reveal_timeout + 5 lock1 = Lock(amount=31, expiration=lock_expiration1, secrethash=sha3(b'lock2')) mediated1 = make_mediated_transfer( payment_network_identifier, channel1, channel0, address1, address0, lock1, pkey1, ) mediated0_hash = sha3(mediated0.packed().data[:-65]) nettingchannel.close( mediated0.nonce, mediated0.transferred_amount, mediated0.locksroot, mediated0_hash, mediated0.signature, sender=pkey1, ) mediated1_hash = sha3(mediated1.packed().data[:-65]) nettingchannel.updateTransfer( mediated1.nonce, mediated1.transferred_amount, mediated1.locksroot, mediated1_hash, mediated1.signature, sender=pkey0, ) tester_chain.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey0) # the balances only change by transferred_amount because the lock was /not/ unlocked balance0 = initial_balance0 + deposit - transferred_amount0 + transferred_amount1 balance1 = initial_balance1 + deposit + transferred_amount0 - transferred_amount1 assert tester_token.balanceOf(nettingchannel.address, sender=pkey1) == 0 assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey1) == balance1