def make_direct_transfer_from_channel( payment_network_identifier, from_channel, partner_channel, amount, pkey, ): """ Helper to create and register a direct transfer from `from_channel` to `partner_channel`.""" payment_identifier = channel.get_next_nonce(from_channel.our_state) pseudo_random_generator = random.Random() state_change = ActionTransferDirect( payment_network_identifier, from_channel.token_address, from_channel.partner_state.address, payment_identifier, amount, ) iteration = channel.handle_send_directtransfer( from_channel, state_change, pseudo_random_generator, ) assert isinstance(iteration.events[0], SendDirectTransfer) direct_transfer_message = DirectTransfer.from_event(iteration.events[0]) address = privatekey_to_address(pkey) sign_key = PrivateKey(pkey) direct_transfer_message.sign(sign_key, address) # if this fails it's not the right key for the current `from_channel` assert direct_transfer_message.sender == from_channel.our_state.address balance_proof = balanceproof_from_envelope(direct_transfer_message) message_identifier = random.randint(0, UINT64_MAX) receive_direct = ReceiveTransferDirect( payment_network_identifier, from_channel.token_address, message_identifier, payment_identifier, balance_proof, ) channel.handle_receive_directtransfer( partner_channel, receive_direct, ) return direct_transfer_message
def increase_transferred_amount( payment_network_identifier, from_channel, partner_channel, amount, pkey, ): # increasing the transferred amount by a value larger than distributable # would put one end of the channel in a negative balance, which is forbidden distributable_from_to = channel.get_distributable( from_channel.our_state, from_channel.partner_state, ) assert distributable_from_to >= amount, 'operation would end up in a incosistent state' message_identifier = random.randint(0, UINT64_MAX) payment_identifier = 1 registry_address = make_address() event = channel.send_directtransfer( registry_address, from_channel, amount, payment_identifier, message_identifier, ) direct_transfer_message = DirectTransfer.from_event(event) address = privatekey_to_address(pkey) sign_key = PrivateKey(pkey) direct_transfer_message.sign(sign_key, address) # if this fails it's not the right key for the current `from_channel` assert direct_transfer_message.sender == from_channel.our_state.address balance_proof = balanceproof_from_envelope(direct_transfer_message) receive_direct = ReceiveTransferDirect( payment_network_identifier, from_channel.token_address, message_identifier, payment_identifier, balance_proof, ) channel.handle_receive_directtransfer( partner_channel, receive_direct, ) return direct_transfer_message
def test_receive_directdtransfer_before_deposit(): """Regression test that ensures that we accept incoming direct transfers, even if we don't have any balance on the channel. """ our_model1, _ = create_model(0) # our deposit is 0 partner_model1, privkey2 = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) payment_network_identifier = factories.make_address() nonce = 1 transferred_amount = 30 receive_directtransfer = make_receive_transfer_direct( payment_network_identifier, channel_state, privkey2, nonce, transferred_amount, ) # this node partner has enough balance, the transfer must be accepted iteration = channel.handle_receive_directtransfer( channel_state, receive_directtransfer, ) assert must_contain_entry(iteration.events, EventTransferReceivedSuccess, {})
def test_channelstate_directtransfer_overspent(): """Receiving a direct transfer with an amount large than distributable must be ignored. """ our_model1, _ = create_model(70) partner_model1, privkey2 = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) distributable = channel.get_distributable(channel_state.partner_state, channel_state.our_state) nonce = 1 transferred_amount = distributable + 1 receive_lockedtransfer = make_receive_transfer_direct( channel_state, privkey2, nonce, transferred_amount, ) is_valid, _ = channel.is_valid_directtransfer( receive_lockedtransfer, channel_state, channel_state.partner_state, channel_state.our_state, ) assert not is_valid, 'message is invalid because it is spending more than the distributable' iteration = channel.handle_receive_directtransfer( channel_state, receive_lockedtransfer, ) assert must_contain_entry(iteration.events, EventTransferReceivedInvalidDirectTransfer, {}) assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model1) assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model1)
def test_channelstate_directtransfer_invalid_chainid(): """Receiving a direct transfer with a chain_id different than the channel's chain_id should be ignored """ our_model1, _ = create_model(70) partner_model1, privkey2 = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) distributable = channel.get_distributable(channel_state.partner_state, channel_state.our_state) nonce = 1 transferred_amount = distributable - 1 receive_lockedtransfer = make_receive_transfer_direct( channel_state=channel_state, privkey=privkey2, nonce=nonce, transferred_amount=transferred_amount, chain_id=UNIT_CHAIN_ID + 2, ) is_valid, _ = channel.is_valid_directtransfer( receive_lockedtransfer, channel_state, channel_state.partner_state, channel_state.our_state, ) assert not is_valid, ( 'message is invalid because it contains different chain id than the channel' ) iteration = channel.handle_receive_directtransfer( channel_state, receive_lockedtransfer, ) assert must_contain_entry(iteration.events, EventTransferReceivedInvalidDirectTransfer, {}) assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model1) assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model1)