def test_channelstate_send_lockedtransfer(): """Sending a mediated transfer must update the participant state. This tests only the state of the sending node, without synchronisation. """ our_model1, _ = create_model(70) partner_model1, _ = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) lock_amount = 30 lock_expiration = 10 lock_secret = sha3(b'test_end_state') lock_secrethash = sha3(lock_secret) lock = HashTimeLockState( lock_amount, lock_expiration, lock_secrethash, ) payment_identifier = 1 message_identifier = random.randint(0, UINT64_MAX) transfer_target = factories.make_address() transfer_initiator = factories.make_address() registry_address = factories.make_address() channel.send_lockedtransfer( registry_address, channel_state, transfer_initiator, transfer_target, lock_amount, message_identifier, payment_identifier, lock_expiration, lock_secrethash, ) our_model2 = our_model1._replace( distributable=our_model1.distributable - lock_amount, amount_locked=lock_amount, next_nonce=2, merkletree_leaves=[lock.lockhash], ) partner_model2 = partner_model1 assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model2) assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model2)
def send_lockedtransfer( transfer_description: TransferDescriptionWithSecretState, channel_state: NettingChannelState, message_identifier: MessageID, block_number: BlockNumber, ) -> SendLockedTransfer: """ Create a mediated transfer using channel. """ assert channel_state.token_network_identifier == transfer_description.token_network_identifier lock_expiration = get_initial_lock_expiration( block_number, channel_state.reveal_timeout, ) lockedtransfer_event = channel.send_lockedtransfer( channel_state, transfer_description.initiator, transfer_description.target, cast( PaymentAmount, transfer_description.amount, ), message_identifier, transfer_description.payment_identifier, lock_expiration, transfer_description.secrethash, ) return lockedtransfer_event
def send_lockedtransfer( transfer_description: TransferDescriptionWithSecretState, channel_state: NettingChannelState, message_identifier: typing.MessageID, block_number: typing.BlockNumber, ) -> SendLockedTransfer: """ Create a mediated transfer using channel. Raises: AssertionError: If the channel does not have enough capacity. """ assert channel_state.token_network_identifier == transfer_description.token_network_identifier lock_expiration = get_initial_lock_expiration( block_number, channel_state.reveal_timeout, ) lockedtransfer_event = channel.send_lockedtransfer( channel_state, transfer_description.initiator, transfer_description.target, transfer_description.amount, message_identifier, transfer_description.payment_identifier, lock_expiration, transfer_description.secrethash, ) return lockedtransfer_event
def send_lockedtransfer( initiator_state: InitiatorTransferState, channel_state: NettingChannelState, message_identifier, block_number: typing.BlockNumber, ) -> SendLockedTransfer: """ Create a mediated transfer using channel. Raises: AssertionError: If the channel does not have enough capacity. """ transfer_token_address = initiator_state.transfer_description.token_network_identifier assert channel_state.token_network_identifier == transfer_token_address transfer_description = initiator_state.transfer_description lock_expiration = get_initial_lock_expiration( block_number, channel_state.settle_timeout, ) lockedtransfer_event = channel.send_lockedtransfer( channel_state, transfer_description.initiator, transfer_description.target, transfer_description.amount, message_identifier, transfer_description.payment_identifier, lock_expiration, transfer_description.secrethash, ) assert lockedtransfer_event initiator_state.transfer = lockedtransfer_event.transfer return lockedtransfer_event
def send_lockedtransfer( transfer_description: TransferDescriptionWithSecretState, channel_state: NettingChannelState, message_identifier: MessageID, block_number: BlockNumber, route_state: RouteState, route_states: List[RouteState], ) -> SendLockedTransfer: """ Create a mediated transfer using channel. """ assert channel_state.token_network_address == transfer_description.token_network_address lock_expiration = channel.get_safe_initial_expiration( block_number, channel_state.reveal_timeout, transfer_description.lock_timeout) # The payment amount and the fee amount must be included in the locked # amount, as a guarantee to the mediator that the fee will be claimable # on-chain. total_amount = calculate_safe_amount_with_fee( payment_amount=transfer_description.amount, estimated_fee=route_state.estimated_fee) lockedtransfer_event = channel.send_lockedtransfer( channel_state=channel_state, initiator=transfer_description.initiator, target=transfer_description.target, amount=total_amount, message_identifier=message_identifier, payment_identifier=transfer_description.payment_identifier, expiration=lock_expiration, secrethash=transfer_description.secrethash, route_states=routes.prune_route_table(route_states=route_states, selected_route=route_state), ) return lockedtransfer_event
def send_lockedtransfer( transfer_description: TransferDescriptionWithSecretState, channel_state: NettingChannelState, message_identifier: MessageID, block_number: BlockNumber, ) -> SendLockedTransfer: """ Create a mediated transfer using channel. """ assert channel_state.token_network_identifier == transfer_description.token_network_identifier lock_expiration = get_initial_lock_expiration(block_number, channel_state.reveal_timeout) # The payment amount and the fee amount must be included in the locked # amount, as a guarantee to the mediator that the fee will be claimable # on-chain. total_amount = PaymentWithFeeAmount( transfer_description.amount + transfer_description.allocated_fee ) lockedtransfer_event = channel.send_lockedtransfer( channel_state=channel_state, initiator=transfer_description.initiator, target=transfer_description.target, amount=total_amount, message_identifier=message_identifier, payment_identifier=transfer_description.payment_identifier, payment_hash_invoice=transfer_description.payment_hash_invoice, expiration=lock_expiration, secrethash=transfer_description.secrethash, ) return lockedtransfer_event
def send_lockedtransfer( initiator_state: InitiatorTransferState, channel_state: NettingChannelState, message_identifier, block_number: typing.BlockNumber, ) -> SendLockedTransfer: """ Create a mediated transfer using channel. Raises: AssertionError: If the channel does not have enough capacity. """ transfer_token_address = initiator_state.transfer_description.token_network_identifier assert channel_state.token_network_identifier == transfer_token_address transfer_description = initiator_state.transfer_description lock_expiration = get_initial_lock_expiration( block_number, channel_state.settle_timeout, ) lockedtransfer_event = channel.send_lockedtransfer( channel_state, transfer_description.initiator, transfer_description.target, transfer_description.amount, message_identifier, transfer_description.payment_identifier, lock_expiration, transfer_description.secrethash, ) assert lockedtransfer_event initiator_state.transfer = lockedtransfer_event.transfer return lockedtransfer_event
def next_transfer_pair( payer_transfer: LockedTransferSignedState, available_routes: List['RouteState'], channelidentifiers_to_channels: Dict, pseudo_random_generator: random.Random, block_number: typing.BlockNumber, ): """ Given a payer transfer tries a new route to proceed with the mediation. Args: payer_transfer: The transfer received from the payer_channel. available_routes: Current available routes that may be used, it's assumed that the routes list is ordered from best to worst. channelidentifiers_to_channels: All the channels available for this transfer. pseudo_random_generator: Number generator to generate a message id. block_number: The current block number. """ transfer_pair = None mediated_events = list() lock_timeout = payer_transfer.lock.expiration - block_number payee_channel = next_channel_from_routes( available_routes, channelidentifiers_to_channels, payer_transfer.lock.amount, lock_timeout, ) if payee_channel: assert payee_channel.settle_timeout >= lock_timeout assert payee_channel.token_address == payer_transfer.token message_identifier = message_identifier_from_prng( pseudo_random_generator) lockedtransfer_event = channel.send_lockedtransfer( payee_channel, payer_transfer.initiator, payer_transfer.target, payer_transfer.lock.amount, message_identifier, payer_transfer.payment_identifier, payer_transfer.lock.expiration, payer_transfer.lock.secrethash, ) assert lockedtransfer_event transfer_pair = MediationPairState( payer_transfer, payee_channel.partner_state.address, lockedtransfer_event.transfer, ) mediated_events = [lockedtransfer_event] return ( transfer_pair, mediated_events, )
def next_transfer_pair(registry_address: typing.Address, payer_transfer: LockedTransferSignedState, available_routes: List['RouteState'], channelidentifiers_to_channels: Dict, pseudo_random_generator: random.Random, timeout_blocks: int, block_number: int): """ Given a payer transfer tries a new route to proceed with the mediation. Args: payer_transfer: The transfer received from the payer_channel. routes: Current available routes that may be used, it's assumed that the routes list is ordered from best to worst. timeout_blocks: Base number of available blocks used to compute the lock timeout. block_number: The current block number. """ assert timeout_blocks > 0 assert timeout_blocks <= payer_transfer.lock.expiration - block_number transfer_pair = None mediated_events = list() payee_channel = next_channel_from_routes( available_routes, channelidentifiers_to_channels, payer_transfer.lock.amount, timeout_blocks, ) if payee_channel: assert payee_channel.reveal_timeout < timeout_blocks assert payee_channel.token_address == payer_transfer.token lock_timeout = timeout_blocks - payee_channel.reveal_timeout lock_expiration = lock_timeout + block_number message_identifier = message_identifier_from_prng( pseudo_random_generator) lockedtransfer_event = channel.send_lockedtransfer( registry_address, payee_channel, payer_transfer.initiator, payer_transfer.target, payer_transfer.lock.amount, message_identifier, payer_transfer.payment_identifier, lock_expiration, payer_transfer.lock.secrethash) assert lockedtransfer_event transfer_pair = MediationPairState( payer_transfer, payee_channel.partner_state.address, lockedtransfer_event.transfer, ) mediated_events = [lockedtransfer_event] return ( transfer_pair, mediated_events, )
def make_mediated_transfer(registry_address, from_channel, partner_channel, initiator, target, lock, pkey, secret=None): """ Helper to create and register a mediated transfer from `from_channel` to `partner_channel`.""" payment_identifier = channel.get_next_nonce(from_channel.our_state) message_identifier = random.randint(0, UINT64_MAX) lockedtransfer = channel.send_lockedtransfer( registry_address, from_channel, initiator, target, lock.amount, message_identifier, payment_identifier, lock.expiration, lock.secrethash, ) mediated_transfer_msg = LockedTransfer.from_event(lockedtransfer) address = privatekey_to_address(pkey) sign_key = PrivateKey(pkey) mediated_transfer_msg.sign(sign_key, address) # compute the signature balance_proof = balanceproof_from_envelope(mediated_transfer_msg) lockedtransfer.balance_proof = balance_proof # if this fails it's not the right key for the current `from_channel` assert mediated_transfer_msg.sender == from_channel.our_state.address receive_lockedtransfer = lockedtransfersigned_from_message( mediated_transfer_msg) channel.handle_receive_lockedtransfer( partner_channel, receive_lockedtransfer, ) if secret is not None: random_sender = make_address() from_secretreveal = ReceiveSecretReveal(secret, random_sender) channel.handle_receive_secretreveal(from_channel, from_secretreveal) partner_secretreveal = ReceiveSecretReveal(secret, random_sender) channel.handle_receive_secretreveal(partner_channel, partner_secretreveal) return mediated_transfer_msg
def make_mediated_transfer( from_channel, partner_channel, initiator, target, lock, pkey, secret=None, ): """ Helper to create and register a mediated transfer from `from_channel` to `partner_channel`.""" payment_identifier = channel.get_next_nonce(from_channel.our_state) message_identifier = random.randint(0, UINT64_MAX) lockedtransfer = channel.send_lockedtransfer( from_channel, initiator, target, lock.amount, message_identifier, payment_identifier, lock.expiration, lock.secrethash, ) mediated_transfer_msg = LockedTransfer.from_event(lockedtransfer) sign_key = PrivateKey(pkey) mediated_transfer_msg.sign(sign_key, NETWORKNAME_TO_ID[TESTS]) # compute the signature balance_proof = balanceproof_from_envelope(mediated_transfer_msg) lockedtransfer.balance_proof = balance_proof # if this fails it's not the right key for the current `from_channel` assert mediated_transfer_msg.sender == from_channel.our_state.address receive_lockedtransfer = lockedtransfersigned_from_message(mediated_transfer_msg) channel.handle_receive_lockedtransfer( partner_channel, receive_lockedtransfer, ) if secret is not None: secrethash = sha3(secret) channel.register_secret(from_channel, secret, secrethash) channel.register_secret(partner_channel, secret, secrethash) return mediated_transfer_msg
def make_mediated_transfer( from_channel, partner_channel, initiator, target, lock, pkey, secret=None, ): """ Helper to create and register a mediated transfer from `from_channel` to `partner_channel`.""" payment_identifier = channel.get_next_nonce(from_channel.our_state) message_identifier = random.randint(0, UINT64_MAX) lockedtransfer = channel.send_lockedtransfer( from_channel, initiator, target, lock.amount, message_identifier, payment_identifier, lock.expiration, lock.secrethash, ) mediated_transfer_msg = LockedTransfer.from_event(lockedtransfer) sign_key = PrivateKey(pkey) mediated_transfer_msg.sign(sign_key) # compute the signature balance_proof = balanceproof_from_envelope(mediated_transfer_msg) lockedtransfer.balance_proof = balance_proof # if this fails it's not the right key for the current `from_channel` assert mediated_transfer_msg.sender == from_channel.our_state.address receive_lockedtransfer = lockedtransfersigned_from_message(mediated_transfer_msg) channel.handle_receive_lockedtransfer( partner_channel, receive_lockedtransfer, ) if secret is not None: secrethash = sha3(secret) channel.register_secret(from_channel, secret, secrethash) channel.register_secret(partner_channel, secret, secrethash) return mediated_transfer_msg
def make_transfers_pair(number_of_channels: int, amount: int = UNIT_TRANSFER_AMOUNT, block_number: int = 5) -> MediatorTransfersPair: deposit = 5 * amount defaults = create_properties( NettingChannelStateProperties( our_state=NettingChannelEndStateProperties(balance=deposit), partner_state=NettingChannelEndStateProperties(balance=deposit), open_transaction=TransactionExecutionStatusProperties( finished_block_number=10), )) properties_list = [ NettingChannelStateProperties( canonical_identifier=make_canonical_identifier( channel_identifier=i), our_state=NettingChannelEndStateProperties( address=ChannelSet.ADDRESSES[0], privatekey=ChannelSet.PKEYS[0]), partner_state=NettingChannelEndStateProperties( address=ChannelSet.ADDRESSES[i + 1], privatekey=ChannelSet.PKEYS[i + 1]), ) for i in range(number_of_channels) ] channels = make_channel_set(properties_list, defaults) lock_expiration = block_number + UNIT_REVEAL_TIMEOUT * 2 pseudo_random_generator = random.Random() transfers_pairs = list() for payer_index in range(number_of_channels - 1): payee_index = payer_index + 1 receiver_channel = channels[payer_index] received_transfer = create( LockedTransferSignedStateProperties( amount=amount, expiration=lock_expiration, payment_identifier=UNIT_TRANSFER_IDENTIFIER, canonical_identifier=receiver_channel.canonical_identifier, sender=channels.partner_address(payer_index), pkey=channels.partner_privatekeys[payer_index], )) is_valid, _, msg = channel.handle_receive_lockedtransfer( receiver_channel, received_transfer) assert is_valid, msg message_identifier = message_identifier_from_prng( pseudo_random_generator) lockedtransfer_event = channel.send_lockedtransfer( channel_state=channels[payee_index], initiator=UNIT_TRANSFER_INITIATOR, target=UNIT_TRANSFER_TARGET, amount=amount, message_identifier=message_identifier, payment_identifier=UNIT_TRANSFER_IDENTIFIER, expiration=lock_expiration, secrethash=UNIT_SECRETHASH, ) assert lockedtransfer_event lock_timeout = lock_expiration - block_number assert mediator.is_channel_usable( candidate_channel_state=channels[payee_index], transfer_amount=amount, lock_timeout=lock_timeout, ) sent_transfer = lockedtransfer_event.transfer pair = MediationPairState(received_transfer, lockedtransfer_event.recipient, sent_transfer) transfers_pairs.append(pair) return MediatorTransfersPair( channels=channels, transfers_pair=transfers_pairs, amount=amount, block_number=block_number, block_hash=make_block_hash(), )
def make_transfers_pair(privatekeys, amount, block_number): transfers_pair = list() channel_map = dict() pseudo_random_generator = random.Random() addresses = list() for pkey in privatekeys: pubkey = pkey.public_key.format(compressed=False) address = publickey_to_address(pubkey) addresses.append(address) key_address = list(zip(privatekeys, addresses)) deposit_amount = amount * 5 channels_state = { address: make_channel( our_address=HOP1, our_balance=deposit_amount, partner_balance=deposit_amount, partner_address=address, token_address=UNIT_TOKEN_ADDRESS, token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS, ) for address in addresses } lock_expiration = block_number + UNIT_REVEAL_TIMEOUT * 2 for (payer_key, payer_address), payee_address in zip(key_address[:-1], addresses[1:]): pay_channel = channels_state[payee_address] receive_channel = channels_state[payer_address] received_transfer = make_signed_transfer( amount=amount, initiator=UNIT_TRANSFER_INITIATOR, target=UNIT_TRANSFER_TARGET, expiration=lock_expiration, secret=UNIT_SECRET, payment_identifier=UNIT_TRANSFER_IDENTIFIER, channel_identifier=receive_channel.identifier, pkey=payer_key, sender=payer_address, ) is_valid, _, msg = channel.handle_receive_lockedtransfer( receive_channel, received_transfer, ) assert is_valid, msg message_identifier = message_identifier_from_prng( pseudo_random_generator) lockedtransfer_event = channel.send_lockedtransfer( channel_state=pay_channel, initiator=UNIT_TRANSFER_INITIATOR, target=UNIT_TRANSFER_TARGET, amount=amount, message_identifier=message_identifier, payment_identifier=UNIT_TRANSFER_IDENTIFIER, expiration=lock_expiration, secrethash=UNIT_SECRETHASH, ) assert lockedtransfer_event lock_timeout = lock_expiration - block_number assert mediator.is_channel_usable( candidate_channel_state=pay_channel, transfer_amount=amount, lock_timeout=lock_timeout, ) sent_transfer = lockedtransfer_event.transfer pair = MediationPairState( received_transfer, lockedtransfer_event.recipient, sent_transfer, ) transfers_pair.append(pair) channel_map[receive_channel.identifier] = receive_channel channel_map[pay_channel.identifier] = pay_channel assert channel.is_lock_locked(receive_channel.partner_state, UNIT_SECRETHASH) assert channel.is_lock_locked(pay_channel.our_state, UNIT_SECRETHASH) return channel_map, transfers_pair
def make_transfers_pair( number_of_channels: int, amount: int = UNIT_TRANSFER_AMOUNT, block_number: int = 5, ) -> MediatorTransfersPair: deposit = 5 * amount defaults = create_properties(NettingChannelStateProperties( our_state=NettingChannelEndStateProperties(balance=deposit), partner_state=NettingChannelEndStateProperties(balance=deposit), open_transaction=TransactionExecutionStatusProperties(finished_block_number=10), )) properties_list = [ NettingChannelStateProperties( identifier=i, our_state=NettingChannelEndStateProperties( address=ChannelSet.ADDRESSES[0], privatekey=ChannelSet.PKEYS[0], ), partner_state=NettingChannelEndStateProperties( address=ChannelSet.ADDRESSES[i + 1], privatekey=ChannelSet.PKEYS[i + 1], ), ) for i in range(number_of_channels) ] channels = make_channel_set(properties_list, defaults) lock_expiration = block_number + UNIT_REVEAL_TIMEOUT * 2 pseudo_random_generator = random.Random() transfers_pairs = list() for payer_index in range(number_of_channels - 1): payee_index = payer_index + 1 receiver_channel = channels[payer_index] received_transfer = make_signed_transfer( amount=amount, initiator=UNIT_TRANSFER_INITIATOR, target=UNIT_TRANSFER_TARGET, expiration=lock_expiration, secret=UNIT_SECRET, payment_identifier=UNIT_TRANSFER_IDENTIFIER, channel_identifier=receiver_channel.identifier, pkey=channels.partner_privatekeys[payer_index], sender=channels.partner_address(payer_index), ) is_valid, _, msg = channel.handle_receive_lockedtransfer( receiver_channel, received_transfer, ) assert is_valid, msg message_identifier = message_identifier_from_prng(pseudo_random_generator) lockedtransfer_event = channel.send_lockedtransfer( channel_state=channels[payee_index], initiator=UNIT_TRANSFER_INITIATOR, target=UNIT_TRANSFER_TARGET, amount=amount, message_identifier=message_identifier, payment_identifier=UNIT_TRANSFER_IDENTIFIER, expiration=lock_expiration, secrethash=UNIT_SECRETHASH, ) assert lockedtransfer_event lock_timeout = lock_expiration - block_number assert mediator.is_channel_usable( candidate_channel_state=channels[payee_index], transfer_amount=amount, lock_timeout=lock_timeout, ) sent_transfer = lockedtransfer_event.transfer pair = MediationPairState( received_transfer, lockedtransfer_event.recipient, sent_transfer, ) transfers_pairs.append(pair) return MediatorTransfersPair(channels, transfers_pairs, amount, block_number)
def next_transfer_pair( payer_transfer: LockedTransferSignedState, available_routes: List['RouteState'], channelidentifiers_to_channels: Dict, pseudo_random_generator: random.Random, timeout_blocks: int, block_number: int, ): """ Given a payer transfer tries a new route to proceed with the mediation. Args: payer_transfer: The transfer received from the payer_channel. routes: Current available routes that may be used, it's assumed that the routes list is ordered from best to worst. timeout_blocks: Base number of available blocks used to compute the lock timeout. block_number: The current block number. """ assert timeout_blocks > 0 assert timeout_blocks <= payer_transfer.lock.expiration - block_number transfer_pair = None mediated_events = list() payee_channel = next_channel_from_routes( available_routes, channelidentifiers_to_channels, payer_transfer.lock.amount, timeout_blocks, ) if payee_channel: assert payee_channel.reveal_timeout < timeout_blocks assert payee_channel.token_address == payer_transfer.token lock_timeout = timeout_blocks - payee_channel.reveal_timeout lock_expiration = lock_timeout + block_number message_identifier = message_identifier_from_prng(pseudo_random_generator) lockedtransfer_event = channel.send_lockedtransfer( payee_channel, payer_transfer.initiator, payer_transfer.target, payer_transfer.lock.amount, message_identifier, payer_transfer.payment_identifier, lock_expiration, payer_transfer.lock.secrethash, ) assert lockedtransfer_event transfer_pair = MediationPairState( payer_transfer, payee_channel.partner_state.address, lockedtransfer_event.transfer, ) mediated_events = [lockedtransfer_event] return ( transfer_pair, mediated_events, )