def detail_participants(_participant1, _participant2, _block_identifier, _channel_identifier): transferred_amount = TokenAmount(1) locked_amount = LockedAmount(1) locksroot = make_locksroot() balance_hash = hash_balance_data(transferred_amount, locked_amount, locksroot) our_details = ParticipantDetails( address=raiden.address, deposit=TokenAmount(5), withdrawn=WithdrawAmount(0), is_closer=False, balance_hash=balance_hash, nonce=Nonce(1), locksroot=locksroot, locked_amount=locked_amount, ) transferred_amount = TokenAmount(1) locked_amount = LockedAmount(1) # Let's mock here that partner locksroot is 0x0 balance_hash = hash_balance_data(transferred_amount, locked_amount, locksroot) partner_details = ParticipantDetails( address=participant, deposit=TokenAmount(5), withdrawn=WithdrawAmount(0), is_closer=True, balance_hash=balance_hash, nonce=Nonce(1), locksroot=LOCKSROOT_OF_NO_LOCKS, locked_amount=locked_amount, ) return ParticipantsDetails(our_details, partner_details)
def assert_channel_values( channel0: NettingChannelState, balance0: Balance, pending_locks0: List[HashTimeLockState], channel1: NettingChannelState, balance1: Balance, pending_locks1: List[HashTimeLockState], ) -> None: total_token = channel0.our_state.contract_balance + channel1.our_state.contract_balance our_balance0 = channel.get_balance(channel0.our_state, channel0.partner_state) partner_balance0 = channel.get_balance(channel0.partner_state, channel0.our_state) assert our_balance0 + partner_balance0 == total_token our_balance1 = channel.get_balance(channel1.our_state, channel1.partner_state) partner_balance1 = channel.get_balance(channel1.partner_state, channel1.our_state) assert our_balance1 + partner_balance1 == total_token locked_amount0 = LockedAmount(sum(lock.amount for lock in pending_locks0)) locked_amount1 = LockedAmount(sum(lock.amount for lock in pending_locks1)) assert_balance(channel0, balance0, locked_amount0) assert_balance(channel1, balance1, locked_amount1) # a participant's outstanding is the other's pending locks. assert_locked(channel0, pending_locks0) assert_locked(channel1, pending_locks1) assert_mirror(channel0, channel1) assert_mirror(channel1, channel0)
def __init__( self, channel_identifier: ChannelID, token_network_address: TokenNetworkAddress, balance_hash: BalanceHash = None, nonce: int = 0, additional_hash: str = "0x%064x" % 0, chain_id: int = 1, signature: str = None, transferred_amount: TokenAmount = None, locked_amount: LockedAmount = LockedAmount(0), # noqa locksroot: Locksroot = LOCKSROOT_OF_NO_LOCKS, ): self.channel_identifier = channel_identifier self.token_network_address = token_network_address self._balance_hash = balance_hash self.additional_hash = additional_hash self.nonce = nonce self.chain_id = chain_id self.signature = signature if transferred_amount and locked_amount and locksroot and balance_hash: assert 0 <= transferred_amount <= UINT256_MAX assert 0 <= locked_amount <= UINT256_MAX assert (self.hash_balance_data(transferred_amount, locked_amount, locksroot) == balance_hash) self.transferred_amount = transferred_amount self.locked_amount = locked_amount self.locksroot = locksroot
def test_receive_lockedtransfer_invalidnonce(raiden_network, number_of_nodes, deposit, token_addresses, reveal_timeout, network_wait): app0, app1, app2 = raiden_network token_address = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address) assert token_network_address channel0 = get_channelstate(app0, app1, token_network_address) amount = 10 payment_identifier = PaymentID(1) secrethash = transfer( initiator_app=app0, target_app=app2, token_address=token_address, amount=PaymentAmount(10), identifier=payment_identifier, timeout=network_wait * number_of_nodes, ) repeated_nonce = Nonce(1) expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=repeated_nonce, token_network_address=token_network_address, token=token_address, channel_identifier=channel0.identifier, transferred_amount=TokenAmount(amount), locked_amount=LockedAmount(amount), recipient=app1.raiden.address, locksroot=make_locksroot(), lock=Lock(amount=PaymentWithFeeAmount(amount), expiration=expiration, secrethash=UNIT_SECRETHASH), target=app2.raiden.address, initiator=app0.raiden.address, signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[ RouteMetadata(route=[app1.raiden.address, app2.raiden.address]) ]), ) sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1) with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash): wait_assert( assert_synced_channel_state, token_network_address, app0, deposit - amount, [], app1, deposit + amount, [], )
def assert_balance(from_channel: NettingChannelState, balance: Balance, locked: LockedAmount) -> None: """ Assert the from_channel overall token values. """ assert balance >= 0 assert locked >= 0 distributable = balance - locked channel_distributable = channel.get_distributable( from_channel.our_state, from_channel.partner_state) channel_balance = channel.get_balance(from_channel.our_state, from_channel.partner_state) channel_locked_amount = channel.get_amount_locked(from_channel.our_state) msg = f"channel balance does not match. Expected: {balance} got: {channel_balance}" assert channel_balance == balance, msg msg = (f"channel distributable amount does not match. " f"Expected: {distributable} got: {channel_distributable}") assert channel_distributable == distributable, msg msg = f"channel locked amount does not match. Expected: {locked} got: {channel_locked_amount}" assert LockedAmount(channel_locked_amount) == locked, msg msg = (f"locked_amount ({locked}) + distributable ({distributable}) " f"did not equal the balance ({balance})") assert balance == locked + distributable, msg
def make_receive_expired_lock( channel_state: NettingChannelState, privkey: bytes, nonce: Nonce, transferred_amount: TokenAmount, lock: HashTimeLockState, locked_amount: LockedAmount, pending_locks: PendingLocksState = None, chain_id: ChainID = None, ) -> ReceiveLockExpired: typecheck(lock, HashTimeLockState) signer = LocalSigner(privkey) address = signer.address if address not in (channel_state.our_state.address, channel_state.partner_state.address): raise ValueError("Private key does not match any of the participants.") if pending_locks is None: pending_locks = make_empty_pending_locks_state() else: assert lock.encoded not in pending_locks.locks locksroot = compute_locksroot(pending_locks) chain_id = chain_id or channel_state.chain_id lock_expired_msg = LockExpired( chain_id=chain_id, nonce=nonce, message_identifier=make_message_identifier(), transferred_amount=transferred_amount, locked_amount=LockedAmount(locked_amount), locksroot=locksroot, channel_identifier=channel_state.identifier, token_network_address=channel_state.token_network_address, recipient=channel_state.partner_state.address, secrethash=lock.secrethash, signature=EMPTY_SIGNATURE, ) lock_expired_msg.sign(signer) balance_proof = balanceproof_from_envelope(lock_expired_msg) receive_lockedtransfer = ReceiveLockExpired( balance_proof=balance_proof, secrethash=lock.secrethash, message_identifier=make_message_identifier(), sender=balance_proof.sender, ) return receive_lockedtransfer
def hash_balance_data( transferred_amount: TokenAmount, locked_amount: LockedAmount, locksroot: Locksroot ) -> BalanceHash: assert locksroot != b"", "Can't hash empty locksroot" assert len(locksroot) == 32, "Locksroot has wrong length" if transferred_amount == 0 and locked_amount == 0 and locksroot == LOCKSROOT_OF_NO_LOCKS: return BalanceHash(EMPTY_HASH) return keccak( transferred_amount.to_bytes(32, byteorder="big") + locked_amount.to_bytes(32, byteorder="big") + locksroot )
def test_received_lockedtransfer_closedchannel( raiden_network: List[RaidenService], reveal_timeout, token_addresses, deposit ): app0, app1 = raiden_network registry_address = app0.default_registry.address token_address = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_raiden(app0), app0.default_registry.address, token_address ) assert token_network_address channel0 = get_channelstate(app0, app1, token_network_address) RaidenAPI(app1).channel_close(registry_address, token_address, app0.address) app0.rpc_client.wait_until_block( target_block_number=BlockNumber(app0.rpc_client.block_number() + 1) ) # Now receive one mediated transfer for the closed channel lock_amount = LockedAmount(10) payment_identifier = PaymentID(1) expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=Nonce(1), token_network_address=token_network_address, token=token_address, channel_identifier=channel0.identifier, transferred_amount=TokenAmount(0), locked_amount=lock_amount, recipient=app1.address, locksroot=make_locksroot(), lock=Lock( amount=PaymentWithFeeAmount(lock_amount), expiration=expiration, secrethash=UNIT_SECRETHASH, ), target=TargetAddress(app1.address), initiator=InitiatorAddress(app0.address), signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[RouteMetadata(route=[app1.address])]), ) sign_and_inject(mediated_transfer_message, app0.signer, app1) # The local state must not change since the channel is already closed assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
def test_receive_lockedtransfer_invalidrecipient(raiden_network, token_addresses, reveal_timeout, deposit): app0, app1 = raiden_network token_address = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address) assert token_network_address channel0 = get_channelstate(app0, app1, token_network_address) payment_identifier = PaymentID(1) invalid_recipient = make_address() lock_amount = LockedAmount(10) expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=Nonce(1), token_network_address=token_network_address, token=token_address, channel_identifier=channel0.identifier, transferred_amount=TokenAmount(0), locked_amount=lock_amount, recipient=invalid_recipient, locksroot=make_locksroot(), lock=Lock( amount=PaymentWithFeeAmount(lock_amount), expiration=expiration, secrethash=UNIT_SECRETHASH, ), target=app1.raiden.address, initiator=app0.raiden.address, signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[RouteMetadata(route=[app1.raiden.address])]), ) sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1) assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
def test_receive_lockedtransfer_invalidsender( raiden_network: List[RaidenService], token_addresses, deposit, reveal_timeout ): app0, app1 = raiden_network token_address = token_addresses[0] other_key, other_address = make_privkey_address() token_network_address = views.get_token_network_address_by_token_address( views.state_from_raiden(app0), app0.default_registry.address, token_address ) assert token_network_address channel0 = get_channelstate(app0, app1, token_network_address) lock_amount = LockedAmount(10) expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=PaymentID(1), nonce=Nonce(1), token_network_address=token_network_address, token=token_address, channel_identifier=channel0.identifier, transferred_amount=TokenAmount(0), locked_amount=lock_amount, recipient=app0.address, locksroot=make_locksroot(), lock=Lock( amount=PaymentWithFeeAmount(lock_amount), expiration=expiration, secrethash=UNIT_SECRETHASH, ), target=TargetAddress(app0.address), initiator=InitiatorAddress(other_address), signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[RouteMetadata(route=[app0.address])]), ) sign_and_inject(mediated_transfer_message, LocalSigner(other_key), app0) assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
def test_regression_multiple_revealsecret( raiden_network: List[App], token_addresses: List[TokenAddress]) -> None: """ Multiple RevealSecret messages arriving at the same time must be handled properly. Unlock handling followed these steps: The Unlock message arrives The secret is registered The channel is updated and the correspoding lock is removed * A balance proof for the new channel state is created and sent to the payer The channel is unregistered for the given secrethash The step marked with an asterisk above introduced a context-switch. This allowed a second Reveal Unlock message to be handled before the channel was unregistered. And because the channel was already updated an exception was raised for an unknown secret. """ app0, app1 = raiden_network token = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token) assert token_network_address channelstate_0_1 = get_channelstate(app0, app1, token_network_address) payment_identifier = PaymentID(1) secret, secrethash = make_secret_with_hash() expiration = BlockExpiration(app0.raiden.get_block_number() + 100) lock_amount = PaymentWithFeeAmount(10) lock = Lock(amount=lock_amount, expiration=expiration, secrethash=secrethash) nonce = Nonce(1) transferred_amount = TokenAmount(0) mediated_transfer = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=nonce, token_network_address=token_network_address, token=token, channel_identifier=channelstate_0_1.identifier, transferred_amount=transferred_amount, locked_amount=LockedAmount(lock_amount), recipient=app1.raiden.address, locksroot=Locksroot(lock.lockhash), lock=lock, target=TargetAddress(app1.raiden.address), initiator=InitiatorAddress(app0.raiden.address), signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[ RouteMetadata(route=[app0.raiden.address, app1.raiden.address]) ]), ) app0.raiden.sign(mediated_transfer) app1.raiden.on_messages([mediated_transfer]) reveal_secret = RevealSecret(message_identifier=make_message_identifier(), secret=secret, signature=EMPTY_SIGNATURE) app0.raiden.sign(reveal_secret) token_network_address = channelstate_0_1.token_network_address unlock = Unlock( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=Nonce(mediated_transfer.nonce + 1), token_network_address=token_network_address, channel_identifier=channelstate_0_1.identifier, transferred_amount=TokenAmount(lock_amount), locked_amount=LockedAmount(0), locksroot=LOCKSROOT_OF_NO_LOCKS, secret=secret, signature=EMPTY_SIGNATURE, ) app0.raiden.sign(unlock) messages = [unlock, reveal_secret] receive_method = app1.raiden.on_messages wait = set( gevent.spawn_later(0.1, receive_method, [data]) for data in messages) gevent.joinall(wait, raise_error=True)
def test_receive_secrethashtransfer_unknown( raiden_network: List[RaidenService], token_addresses): app0 = raiden_network[0] token_address = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_raiden(app0), app0.default_registry.address, token_address) assert token_network_address other_key = HOP1_KEY other_signer = LocalSigner(other_key) canonical_identifier = factories.make_canonical_identifier( token_network_address=token_network_address) amount = TokenAmount(10) locksroot = Locksroot(make_32bytes()) refund_transfer_message = factories.create( factories.RefundTransferProperties( payment_identifier=PaymentID(1), nonce=Nonce(1), token=token_address, canonical_identifier=canonical_identifier, transferred_amount=amount, recipient=TargetAddress(app0.address), locksroot=locksroot, amount=amount, secret=UNIT_SECRET, )) sign_and_inject(refund_transfer_message, other_signer, app0) unlock = Unlock( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=PaymentID(1), nonce=Nonce(1), channel_identifier=canonical_identifier.channel_identifier, token_network_address=token_network_address, transferred_amount=amount, locked_amount=LockedAmount(0), locksroot=locksroot, secret=UNIT_SECRET, signature=EMPTY_SIGNATURE, ) sign_and_inject(unlock, other_signer, app0) secret_request_message = SecretRequest( message_identifier=make_message_identifier(), payment_identifier=PaymentID(1), secrethash=UNIT_SECRETHASH, amount=PaymentAmount(1), expiration=refund_transfer_message.lock.expiration, signature=EMPTY_SIGNATURE, ) sign_and_inject(secret_request_message, other_signer, app0) reveal_secret_message = RevealSecret( message_identifier=make_message_identifier(), secret=UNIT_SECRET, signature=EMPTY_SIGNATURE) sign_and_inject(reveal_secret_message, other_signer, app0)
def test_payment_channel_proxy_basics( token_network_registry_address: TokenNetworkRegistryAddress, token_network_proxy: TokenNetwork, token_proxy: Token, chain_id: ChainID, private_keys: List[PrivateKey], web3: Web3, contract_manager: ContractManager, reveal_timeout: BlockTimeout, ) -> None: token_network_address = token_network_proxy.address partner = privatekey_to_address(private_keys[0]) rpc_client = JSONRPCClient(web3, private_keys[1]) proxy_manager = ProxyManager( rpc_client=rpc_client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) token_network_proxy = proxy_manager.token_network( address=token_network_address, block_identifier=BLOCK_ID_LATEST ) start_block = web3.eth.blockNumber channel_details = token_network_proxy.new_netting_channel( partner=partner, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier=BLOCK_ID_LATEST, ) channel_identifier = channel_details.channel_identifier assert channel_identifier is not None channel_state = NettingChannelState( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, token_network_address=token_network_address, channel_identifier=channel_identifier, ), token_address=token_network_proxy.token_address(), token_network_registry_address=token_network_registry_address, reveal_timeout=reveal_timeout, settle_timeout=BlockTimeout(TEST_SETTLE_TIMEOUT_MIN), fee_schedule=FeeScheduleState(), our_state=NettingChannelEndState( address=token_network_proxy.client.address, contract_balance=Balance(0) ), partner_state=NettingChannelEndState(address=partner, contract_balance=Balance(0)), open_transaction=SuccessfulTransactionState(finished_block_number=BlockNumber(0)), ) channel_proxy_1 = proxy_manager.payment_channel( channel_state=channel_state, block_identifier=BLOCK_ID_LATEST ) assert channel_proxy_1.channel_identifier == channel_identifier assert channel_proxy_1.opened(BLOCK_ID_LATEST) is True # Test deposit initial_token_balance = 100 token_proxy.transfer(rpc_client.address, TokenAmount(initial_token_balance)) assert token_proxy.balance_of(rpc_client.address) == initial_token_balance assert token_proxy.balance_of(partner) == 0 channel_proxy_1.approve_and_set_total_deposit( total_deposit=TokenAmount(10), block_identifier=BLOCK_ID_LATEST ) # ChannelOpened, ChannelNewDeposit channel_events = get_all_netting_channel_events( proxy_manager=proxy_manager, token_network_address=token_network_address, netting_channel_identifier=channel_proxy_1.channel_identifier, contract_manager=contract_manager, from_block=start_block, to_block=web3.eth.blockNumber, ) assert len(channel_events) == 2 block_before_close = web3.eth.blockNumber empty_balance_proof = BalanceProof( channel_identifier=channel_proxy_1.channel_identifier, token_network_address=token_network_address, balance_hash=EMPTY_BALANCE_HASH, nonce=0, chain_id=chain_id, transferred_amount=TokenAmount(0), ) closing_data = ( empty_balance_proof.serialize_bin(msg_type=MessageTypeId.BALANCE_PROOF) + EMPTY_SIGNATURE ) channel_proxy_1.close( nonce=Nonce(0), balance_hash=EMPTY_BALANCE_HASH, additional_hash=EMPTY_MESSAGE_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data), block_identifier=BLOCK_ID_LATEST, ) assert channel_proxy_1.closed(BLOCK_ID_LATEST) is True # ChannelOpened, ChannelNewDeposit, ChannelClosed channel_events = get_all_netting_channel_events( proxy_manager=proxy_manager, token_network_address=token_network_address, netting_channel_identifier=channel_proxy_1.channel_identifier, contract_manager=contract_manager, from_block=start_block, to_block=web3.eth.blockNumber, ) assert len(channel_events) == 3 # check the settlement timeouts again assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN # update transfer -- we need to wait on +1 since we use the latest block on parity for # estimate gas and at the time the latest block is the settle timeout block. # More info: https://github.com/raiden-network/raiden/pull/3699#discussion_r270477227 rpc_client.wait_until_block( target_block_number=BlockNumber(rpc_client.block_number() + TEST_SETTLE_TIMEOUT_MIN + 1) ) transaction_hash = channel_proxy_1.settle( transferred_amount=TokenAmount(0), locked_amount=LockedAmount(0), locksroot=LOCKSROOT_OF_NO_LOCKS, partner_transferred_amount=TokenAmount(0), partner_locked_amount=LockedAmount(0), partner_locksroot=LOCKSROOT_OF_NO_LOCKS, block_identifier=BLOCK_ID_LATEST, ) assert is_tx_hash_bytes(transaction_hash) assert channel_proxy_1.settled(BLOCK_ID_LATEST) is True # ChannelOpened, ChannelNewDeposit, ChannelClosed, ChannelSettled channel_events = get_all_netting_channel_events( proxy_manager=proxy_manager, token_network_address=token_network_address, netting_channel_identifier=channel_proxy_1.channel_identifier, contract_manager=contract_manager, from_block=start_block, to_block=web3.eth.blockNumber, ) assert len(channel_events) == 4 channel_details = token_network_proxy.new_netting_channel( partner=partner, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier=BLOCK_ID_LATEST, ) new_channel_identifier = channel_details.channel_identifier assert new_channel_identifier is not None channel_state = NettingChannelState( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, token_network_address=token_network_address, channel_identifier=new_channel_identifier, ), token_address=token_network_proxy.token_address(), token_network_registry_address=token_network_registry_address, reveal_timeout=reveal_timeout, settle_timeout=BlockTimeout(TEST_SETTLE_TIMEOUT_MIN), fee_schedule=FeeScheduleState(), our_state=NettingChannelEndState( address=token_network_proxy.client.address, contract_balance=Balance(0) ), partner_state=NettingChannelEndState(address=partner, contract_balance=Balance(0)), open_transaction=SuccessfulTransactionState(finished_block_number=BlockNumber(0)), ) channel_proxy_2 = proxy_manager.payment_channel( channel_state=channel_state, block_identifier=BLOCK_ID_LATEST ) assert channel_proxy_2.channel_identifier == new_channel_identifier assert channel_proxy_2.opened(BLOCK_ID_LATEST) is True msg = "The channel was already closed, the second call must fail" with pytest.raises(RaidenRecoverableError): channel_proxy_1.close( nonce=Nonce(0), balance_hash=EMPTY_BALANCE_HASH, additional_hash=EMPTY_MESSAGE_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data), block_identifier=block_before_close, ) pytest.fail(msg) msg = "The channel is not open at latest, this must raise" with pytest.raises(RaidenUnrecoverableError): channel_proxy_1.close( nonce=Nonce(0), balance_hash=EMPTY_BALANCE_HASH, additional_hash=EMPTY_MESSAGE_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data), block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) msg = ( "The channel was not opened at the provided block (latest). " "This call should never have been attempted." ) with pytest.raises(BrokenPreconditionError): channel_proxy_1.approve_and_set_total_deposit( total_deposit=TokenAmount(20), block_identifier=BLOCK_ID_LATEST ) pytest.fail(msg)
def make_receive_transfer_mediated( channel_state: NettingChannelState, privkey: bytes, nonce: Nonce, transferred_amount: TokenAmount, lock: HashTimeLockState, pending_locks: PendingLocksState = None, locked_amount: Optional[PaymentWithFeeAmount] = None, chain_id: Optional[ChainID] = None, ) -> LockedTransferSignedState: typecheck(lock, HashTimeLockState) signer = LocalSigner(privkey) address = signer.address if address not in (channel_state.our_state.address, channel_state.partner_state.address): raise ValueError("Private key does not match any of the participants.") if pending_locks is None: locks = make_empty_pending_locks_state() locks.locks.append(lock.encoded) else: assert bytes(lock.encoded) in pending_locks.locks locks = pending_locks if locked_amount is None: locked_amount = lock.amount assert locked_amount >= lock.amount locksroot = compute_locksroot(locks) payment_identifier = PaymentID(nonce) transfer_target = make_target_address() transfer_initiator = make_initiator_address() chain_id = chain_id or channel_state.chain_id transfer_metadata = Metadata(routes=[ RouteMetadata( route=[channel_state.our_state.address, Address(transfer_target)]) ]) mediated_transfer_msg = LockedTransfer( chain_id=chain_id, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=nonce, token_network_address=channel_state.token_network_address, token=channel_state.token_address, channel_identifier=channel_state.identifier, transferred_amount=transferred_amount, locked_amount=LockedAmount(locked_amount), recipient=channel_state.partner_state.address, locksroot=locksroot, lock=Lock(amount=lock.amount, expiration=lock.expiration, secrethash=lock.secrethash), target=transfer_target, initiator=transfer_initiator, signature=EMPTY_SIGNATURE, metadata=transfer_metadata, ) mediated_transfer_msg.sign(signer) receive_lockedtransfer = LockedTransferSignedState( payment_identifier=payment_identifier, token=channel_state.token_address, lock=lock, initiator=transfer_initiator, target=transfer_target, message_identifier=make_message_identifier(), balance_proof=balanceproof_from_envelope(mediated_transfer_msg), routes=[ route_metadata.route for route_metadata in transfer_metadata.routes ], ) return receive_lockedtransfer
def find_max_pending_transfers(gas_limit) -> None: """Measure gas consumption of TokenNetwork.unlock() depending on number of pending transfers and find the maximum number of pending transfers so gas_limit is not exceeded.""" tester = ContractTester(generate_keys=2) tester.deploy_contract("SecretRegistry") tester.deploy_contract( "HumanStandardToken", _initialAmount=100_000, _decimalUnits=3, _tokenName="SomeToken", _tokenSymbol="SMT", ) tester.deploy_contract( "TokenNetwork", _token_address=tester.contract_address("HumanStandardToken"), _secret_registry=tester.contract_address("SecretRegistry"), _chain_id=CHAIN_ID, _settlement_timeout_min=100, _settlement_timeout_max=200, _deprecation_executor=tester.accounts[0], _channel_participant_deposit_limit=10000, _token_network_deposit_limit=10000, ) tester.call_transaction("HumanStandardToken", "transfer", _to=tester.accounts[1], _value=10000) receipt = tester.call_transaction( "TokenNetwork", "openChannel", participant1=tester.accounts[0], participant2=tester.accounts[1], settle_timeout=150, ) channel_identifier = ChannelID(int(encode_hex(receipt["logs"][0]["topics"][1]), 16)) tester.call_transaction( "HumanStandardToken", "approve", sender=tester.accounts[0], _spender=tester.contract_address("TokenNetwork"), _value=10000, ) tester.call_transaction( "HumanStandardToken", "approve", sender=tester.accounts[1], _spender=tester.contract_address("TokenNetwork"), _value=5000, ) tester.call_transaction( "TokenNetwork", "setTotalDeposit", channel_identifier=channel_identifier, participant=tester.accounts[0], total_deposit=5000, partner=tester.accounts[1], ) tester.call_transaction( "TokenNetwork", "setTotalDeposit", channel_identifier=channel_identifier, participant=tester.accounts[1], total_deposit=2000, partner=tester.accounts[0], ) print("Measuring unlock()'s gas cost for different Merkle tree widths, can take a while...") before_closing = tester.tester.take_snapshot() enough = 0 too_much = 1024 nonce = Nonce(10) additional_hash = AdditionalHash(urandom(32)) token_network_address = tester.contract_address("TokenNetwork") while enough + 1 < too_much: tree_size = (enough + too_much) // 2 tester.tester.revert_to_snapshot(before_closing) pending_transfers_tree = get_pending_transfers_tree( tester.web3, unlockable_amounts=[1] * tree_size, expired_amounts=[] ) balance_hash = hash_balance_data( transferred_amount=TokenAmount(3000), locked_amount=LockedAmount(2000), locksroot=Locksroot(pending_transfers_tree.hash_of_packed_transfers), ) canonical_identifier = CanonicalIdentifier( chain_identifier=CHAIN_ID, token_network_address=token_network_address, channel_identifier=ChannelID(channel_identifier), ) data_to_sign = pack_balance_proof( nonce=Nonce(nonce), balance_hash=balance_hash, additional_hash=additional_hash, canonical_identifier=canonical_identifier, ) signature = LocalSigner(tester.private_keys[1]).sign(data=data_to_sign) tester.call_transaction( "TokenNetwork", "closeChannel", channel_identifier=channel_identifier, partner=tester.accounts[1], balance_hash=balance_hash, nonce=nonce, additional_hash=additional_hash, signature=signature, ) tester.tester.mine_blocks(160) # close settlement window tester.call_transaction( "TokenNetwork", "settleChannel", channel_identifier=channel_identifier, participant1=tester.accounts[0], participant1_transferred_amount=0, participant1_locked_amount=0, participant1_locksroot=b"\x00" * 32, participant2=tester.accounts[1], participant2_transferred_amount=3000, participant2_locked_amount=2000, participant2_locksroot=pending_transfers_tree.hash_of_packed_transfers, ) receipt = tester.call_transaction( "TokenNetwork", "unlock", channel_identifier=channel_identifier, participant=tester.accounts[0], partner=tester.accounts[1], merkle_tree_leaves=pending_transfers_tree.packed_transfers, ) gas_used = receipt["gasUsed"] if gas_used <= gas_limit: enough = tree_size print(f"{tree_size} pending transfers work ({gas_used} gas needed to unlock)") else: too_much = tree_size print(f"{tree_size} pending transfers are too much ({gas_used} gas needed to unlock)")
def test_pfs_send_unique_capacity_and_fee_updates_during_mediated_transfer( raiden_network): """ Tests that PFSCapacityUpdates and PFSFeeUpdates are being sent only once with the most recent state change in a batch. """ app0, app1 = raiden_network chain_state = views.state_from_app(app0) # There have been two PFSCapacityUpdates and two PFSFeeUpdates per channel per node assert len(get_messages(app0)) == 4 # The mediator has two channels assert len(get_messages(app1)) == 4 # Now we create two state_changes (Deposit) regarding the same channel # and trigger handle_state_changes() of node0. The expected outcome # is that only 1 PFSCapacityUpdate and 1 PFSFeeUpdate is being sent # not one per state change pfs_fee_update_1_of_app0 = get_messages(app0)[1] assert isinstance(pfs_fee_update_1_of_app0, PFSFeeUpdate) pfs_capacity_update_2_of_app0 = get_messages(app0)[2] assert isinstance(pfs_capacity_update_2_of_app0, PFSCapacityUpdate) canonical_identifier = pfs_fee_update_1_of_app0.canonical_identifier new_total_deposit_1 = pfs_capacity_update_2_of_app0.other_capacity * 2 deposit_transaction_1 = TransactionChannelDeposit( app1.raiden.address, TokenAmount(new_total_deposit_1), chain_state.block_number) channel_deposit_1 = ContractReceiveChannelDeposit( transaction_hash=make_transaction_hash(), canonical_identifier=canonical_identifier, deposit_transaction=deposit_transaction_1, block_number=chain_state.block_number, block_hash=chain_state.block_hash, fee_config=MediationFeeConfig(), ) new_total_deposit_2 = new_total_deposit_1 * 2 deposit_transaction_2 = TransactionChannelDeposit( app1.raiden.address, TokenAmount(new_total_deposit_2), chain_state.block_number) channel_deposit_2 = ContractReceiveChannelDeposit( transaction_hash=make_transaction_hash(), canonical_identifier=canonical_identifier, deposit_transaction=deposit_transaction_2, block_number=chain_state.block_number, block_hash=chain_state.block_hash, fee_config=MediationFeeConfig(), ) state_changes = [channel_deposit_1, channel_deposit_2] app0.raiden.handle_state_changes(state_changes=state_changes) # Now we should see that app0 send 2 new messages, # one PFSCapacityUpdate and one PFSFeeUpdate with # the updated amount of the initial amount * 4 # so sending should only be triggered by the second state change pfs_capacity_update_3_of_app0 = get_messages(app0)[4] assert isinstance(pfs_capacity_update_3_of_app0, PFSCapacityUpdate) assert len(get_messages(app0)) == 6 assert (pfs_capacity_update_3_of_app0.other_capacity == pfs_capacity_update_2_of_app0.updating_capacity * 4) # Now we want to test if this also works with a state_change # that triggers only a PFSCapacityUpdate and no PFSFeeUpdate. # So at the end we expect 1 more PFSCapacityUpdate in the room. lock_secret_1 = keccak(b"test_end_state") unlock_message_1 = Unlock( chain_id=chain_state.chain_id, message_identifier=MessageID(123132), payment_identifier=PaymentID(1), nonce=Nonce(2), token_network_address=canonical_identifier.token_network_address, channel_identifier=canonical_identifier.channel_identifier, transferred_amount=TokenAmount(400), locked_amount=LockedAmount(0), locksroot=Locksroot(keccak(b"")), secret=Secret(lock_secret_1), signature=Signature(bytes(65)), ) unlock_message_1.sign(app1.raiden.signer) balance_proof_1 = balanceproof_from_envelope(unlock_message_1) unlock_1 = ReceiveUnlock( message_identifier=MessageID(5135), secret=Secret(lock_secret_1), balance_proof=balance_proof_1, sender=balance_proof_1.sender, ) lock_secret_2 = keccak(b"test_end_state_again") unlock_message_2 = Unlock( chain_id=chain_state.chain_id, message_identifier=MessageID(223132), payment_identifier=PaymentID(2), nonce=Nonce(2), token_network_address=canonical_identifier.token_network_address, channel_identifier=canonical_identifier.channel_identifier, transferred_amount=TokenAmount(500), locked_amount=LockedAmount(0), locksroot=Locksroot(keccak(b"")), secret=Secret(lock_secret_2), signature=Signature(bytes(65)), ) unlock_message_2.sign(app1.raiden.signer) balance_proof_2 = balanceproof_from_envelope(unlock_message_2) unlock_2 = ReceiveUnlock( message_identifier=MessageID(5135), secret=Secret(lock_secret_2), balance_proof=balance_proof_2, sender=balance_proof_2.sender, ) state_changes_2 = [unlock_1, unlock_2] app0.raiden.handle_state_changes(state_changes=state_changes_2) assert len(get_messages(app0)) == 7 assert len([ x for x in get_messages(app0) if isinstance(x, PFSCapacityUpdate) ]) == 4