def test_failsfast_lockedtransfer_exceeding_distributable( raiden_network, token_addresses, deposit, ): app0, app1 = raiden_network token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address, ) result = app0.raiden.mediated_transfer_async( token_network_identifier, deposit * 2, app1.raiden.address, identifier=1, ) assert result.successful() assert result.get_nowait() is False assert_synced_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], )
def token_network_connect( self, registry_address, token_address, funds, initial_channel_target=3, joinable_funds_target=.4, ): """Automatically maintain channels open for the given token network. Args: token_address (bin): the ERC20 token network to connect to. funds (int): the amount of funds that can be used by the ConnectionMananger. initial_channel_target (int): number of channels to open proactively. joinable_funds_target (float): fraction of the funds that will be used to join channels opened by other participants. """ if not is_binary_address(token_address): raise InvalidAddress('token_address must be a valid address in binary') token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) connection_manager = self.raiden.connection_manager_for_token_network( token_network_identifier, ) connection_manager.connect( funds, initial_channel_target=initial_channel_target, joinable_funds_target=joinable_funds_target, )
def test_receive_directtransfer_invalidnonce(raiden_network, deposit, token_addresses): app0, app1 = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) transferred_amount = 10 same_payment_identifier = 1 message_identifier = random.randint(0, UINT64_MAX) event = channel.send_directtransfer( channel0, transferred_amount, message_identifier, same_payment_identifier, ) direct_transfer_message = DirectTransfer.from_event(event) sign_and_inject( direct_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) # Send a *different* direct transfer with the *same nonce* invalid_transferred_amount = transferred_amount // 2 message_identifier = random.randint(0, UINT64_MAX) invalid_direct_transfer_message = DirectTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=message_identifier, payment_identifier=same_payment_identifier, nonce=1, token_network_address=token_network_identifier, token=token_address, channel_identifier=channel0.identifier, transferred_amount=invalid_transferred_amount, locked_amount=0, recipient=app1.raiden.address, locksroot=EMPTY_MERKLE_ROOT, ) sign_and_inject( invalid_direct_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) assert_synched_channel_state( token_network_identifier, app0, deposit - transferred_amount, [], app1, deposit + transferred_amount, [], )
def token_network_leave( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, ) -> typing.List[NettingChannelState]: """ Close all channels and wait for settlement. """ if not is_binary_address(registry_address): raise InvalidAddress('registry_address must be a valid address in binary') if not is_binary_address(token_address): raise InvalidAddress('token_address must be a valid address in binary') if token_address not in self.get_tokens_list(registry_address): raise UnknownTokenAddress('token_address unknown') token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) connection_manager = self.raiden.connection_manager_for_token_network( token_network_identifier, ) return connection_manager.leave(registry_address)
def test_direct_transfer(raiden_network, token_addresses, deposit, network_wait): token_address = token_addresses[0] app0, app1 = raiden_network amount = 10 chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) direct_transfer( app0, app1, token_network_identifier, amount, timeout=network_wait, ) assert_synched_channel_state( token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], )
def test_close_channel_lack_of_balance_proof(raiden_chain, deposit, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) token_proxy = app0.raiden.chain.token(token_address) initial_balance0 = token_proxy.balance_of(app0.raiden.address) initial_balance1 = token_proxy.balance_of(app1.raiden.address) amount = 100 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_network_identifier, amount, identifier, ) # Stop app0 to avoid sending the unlock app0.raiden.transport.stop_and_wait() reveal_secret = RevealSecret( random.randint(0, UINT64_MAX), secret, ) app0.raiden.sign(reveal_secret) message_handler.on_message(app1.raiden, reveal_secret) RaidenAPI(app0.raiden).channel_close( app0.raiden.default_registry.address, token_address, app1.raiden.address, ) channel_state = get_channelstate(app0, app1, token_network_identifier) waiting.wait_for_settle( app0.raiden, app0.raiden.default_registry.address, token_address, [channel_state.identifier], app0.raiden.alarm.sleep_time, ) # wait for the node to call batch unlock with gevent.Timeout(10): wait_for_batch_unlock( app0, token_network_identifier, channel_state.partner_state.address, channel_state.our_state.address, ) expected_balance0 = initial_balance0 + deposit - amount expected_balance1 = initial_balance1 + deposit + amount assert token_proxy.balance_of(app0.raiden.address) == expected_balance0 assert token_proxy.balance_of(app1.raiden.address) == expected_balance1
def test_regression_unfiltered_routes( raiden_network, token_addresses, settle_timeout, deposit, ): """ The transfer should proceed without triggering an assert. Transfers failed in networks where two or more paths to the destination are possible but they share same node as a first hop. """ app0, app1, app2, app3, app4 = raiden_network token = token_addresses[0] registry_address = app0.raiden.default_registry.address # Topology: # # 0 -> 1 -> 2 -> 4 # | ^ # +--> 3 ---+ app_channels = [ (app0, app1), (app1, app2), (app1, app3), (app3, app4), (app2, app4), ] greenlets = [] for first_app, second_app in app_channels: greenlets.append(gevent.spawn( payment_channel_open_and_deposit, first_app, second_app, token, deposit, settle_timeout, )) gevent.wait(greenlets) wait_for_channels( app_channels, registry_address, [token], deposit, ) payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token, ) transfer = app0.raiden.mediated_transfer_async( token_network_identifier=token_network_identifier, amount=1, target=app4.raiden.address, identifier=1, ) assert transfer.wait()
def test_mediated_transfer_events(raiden_network, number_of_nodes, token_addresses, network_wait): app0, app1, app2 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) amount = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) def test_initiator_events(): initiator_blockevents = app0.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) initiator_events = [blocknumber_event[1] for blocknumber_event in initiator_blockevents] return ( must_contain_entry(initiator_events, SendRevealSecret, {}) and must_contain_entry(initiator_events, EventUnlockSuccess, {}) ) assert wait_until(test_initiator_events, network_wait) def test_mediator_events(): mediator_blockevents = app1.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) mediator_events = [blocknumber_event[1] for blocknumber_event in mediator_blockevents] return ( must_contain_entry(mediator_events, EventUnlockSuccess, {}) and must_contain_entry(mediator_events, EventUnlockClaimSuccess, {}) ) assert wait_until(test_mediator_events, network_wait) def test_target_events(): target_blockevents = app2.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) target_events = [blocknumber_event[1] for blocknumber_event in target_blockevents] return ( must_contain_entry(target_events, SendSecretRequest, {}) and must_contain_entry(target_events, SendRevealSecret, {}) and must_contain_entry(target_events, EventUnlockClaimSuccess, {}) ) assert wait_until(test_target_events, network_wait)
def test_refund_messages(raiden_chain, token_addresses, deposit): # The network has the following topology: # # App0 <---> App1 <---> App2 app0, app1, app2 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address, ) # Exhaust the channel App1 <-> App2 (to force the refund transfer) exhaust_amount = deposit mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=exhaust_amount, identifier=1, ) refund_amount = deposit // 2 identifier = 1 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, refund_amount, app2.raiden.address, identifier, ) assert async_result.wait() is False, 'Must fail, there are no routes available' # The transfer from app0 to app2 failed, so the balances did change. # Since the refund is not unlocked both channels have the corresponding # amount locked (issue #1091) send_lockedtransfer = raiden_events_must_contain_entry( app0.raiden, SendLockedTransfer, {'transfer': {'lock': {'amount': refund_amount}}}, ) assert send_lockedtransfer send_refundtransfer = raiden_events_must_contain_entry(app1.raiden, SendRefundTransfer, {}) assert send_refundtransfer assert_synced_channel_state( token_network_identifier, app0, deposit, [send_lockedtransfer.transfer.lock], app1, deposit, [send_refundtransfer.transfer.lock], ) # This channel was exhausted to force the refund transfer assert_synced_channel_state( token_network_identifier, app1, 0, [], app2, deposit * 2, [], )
def test_receive_secrethashtransfer_unknown(raiden_network, token_addresses): app0 = raiden_network[0] token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) other_key = HOP1_KEY other_address = HOP1 channel_identifier = make_channel_identifier() amount = 10 refund_transfer_message = make_refund_transfer( payment_identifier=1, nonce=1, token_network_address=token_network_identifier, token=token_address, channel_identifier=channel_identifier, transferred_amount=amount, recipient=app0.raiden.address, locksroot=UNIT_SECRETHASH, amount=amount, secrethash=UNIT_SECRETHASH, ) sign_and_inject(refund_transfer_message, other_key, other_address, app0) secret = Secret( chain_id=UNIT_CHAIN_ID, message_identifier=random.randint(0, UINT64_MAX), payment_identifier=1, nonce=1, channel_identifier=channel_identifier, token_network_address=token_network_identifier, transferred_amount=amount, locked_amount=0, locksroot=UNIT_SECRETHASH, secret=UNIT_SECRET, ) sign_and_inject(secret, other_key, other_address, app0) secret_request_message = SecretRequest( message_identifier=random.randint(0, UINT64_MAX), payment_identifier=1, secrethash=UNIT_SECRETHASH, amount=1, expiration=refund_transfer_message.lock.expiration, ) sign_and_inject(secret_request_message, other_key, other_address, app0) reveal_secret_message = RevealSecret( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, ) sign_and_inject(reveal_secret_message, other_key, other_address, app0)
def channel_batch_close( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, partner_addresses: typing.List[typing.Address], retry_timeout: typing.NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ): """Close a channel opened with `partner_address` for the given `token_address`. Race condition, this can fail if channel was closed externally. """ if not is_binary_address(token_address): raise InvalidAddress('Expected binary address format for token in channel close') if not all(map(is_binary_address, partner_addresses)): raise InvalidAddress('Expected binary address format for partner in channel close') valid_tokens = views.get_token_network_addresses_for( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, ) if token_address not in valid_tokens: raise UnknownTokenAddress('Token address is not known.') chain_state = views.state_from_raiden(self.raiden) channels_to_close = views.filter_channels_by_partneraddress( chain_state=chain_state, payment_network_id=registry_address, token_address=token_address, partner_addresses=partner_addresses, ) token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) for channel_state in channels_to_close: channel_close = ActionChannelClose( token_network_identifier=token_network_identifier, channel_identifier=channel_state.identifier, ) self.raiden.handle_state_change(channel_close) channel_ids = [channel_state.identifier for channel_state in channels_to_close] waiting.wait_for_close( raiden=self.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=channel_ids, retry_timeout=retry_timeout, )
def test_locked_transfer_secret_registered_onchain( raiden_network, token_addresses, secret_registry_address, ): app0 = raiden_network[0] token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) amount = 1 target = UNIT_TRANSFER_INITIATOR identifier = 1 transfer_secret = sha3(target + b'1') secret_registry_proxy = app0.raiden.chain.secret_registry( secret_registry_address, ) secret_registry_proxy.register_secret(transfer_secret) # Test that sending a transfer with a secret already registered on-chain fails with pytest.raises(RaidenUnrecoverableError): app0.raiden.start_mediated_transfer_with_secret( token_network_identifier, amount, target, identifier, transfer_secret, ) expiration = 9999 transfer = make_signed_transfer( amount, UNIT_TRANSFER_INITIATOR, app0.raiden.address, expiration, transfer_secret, ) message_handler = MessageHandler() message_handler.handle_message_lockedtransfer( app0.raiden, transfer, ) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(0, 'latest') transfer_statechange_dispatched = ( must_contain_entry(state_changes, ActionInitMediator, {}) or must_contain_entry(state_changes, ActionInitTarget, {}) ) assert not transfer_statechange_dispatched
def test_settle_is_automatically_called(raiden_network, token_addresses, deposit): """Settle is automatically called by one of the nodes.""" app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], ) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) channel_state = get_channelstate(app0, app1, token_network_identifier) assert channel_state.close_transaction.finished_block_number assert channel_state.settle_transaction.finished_block_number assert must_contain_entry(state_changes, ContractReceiveChannelClosed, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'closing_address': app1.raiden.address, 'closed_block_number': channel_state.close_transaction.finished_block_number, }) assert must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'settle_block_number': channel_state.settle_transaction.finished_block_number, })
def test_received_directtransfer_closedchannel(raiden_network, token_addresses, deposit): app0, app1 = raiden_network token_address = token_addresses[0] registry_address = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), registry_address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) wait_until_block( app0.raiden.chain, app0.raiden.chain.block_number() + 1, ) # Now receive one direct transfer for the closed channel message_identifier = random.randint(0, UINT64_MAX) direct_transfer_message = DirectTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=message_identifier, payment_identifier=1, nonce=1, token_network_address=token_network_identifier, token=token_address, channel_identifier=channel0.identifier, transferred_amount=10, locked_amount=0, recipient=app0.raiden.address, locksroot=EMPTY_MERKLE_ROOT, ) sign_and_inject( direct_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) # The local state must not change since the channel is already closed assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], )
def transfer_async( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, amount: typing.TokenAmount, target: typing.Address, identifier: typing.PaymentID = None, ): if not isinstance(amount, int): raise InvalidAmount('Amount not a number') if amount <= 0: raise InvalidAmount('Amount negative') if not is_binary_address(token_address): raise InvalidAddress('token address is not valid.') if not is_binary_address(target): raise InvalidAddress('target address is not valid.') valid_tokens = views.get_token_network_addresses_for( views.state_from_raiden(self.raiden), registry_address, ) if token_address not in valid_tokens: raise UnknownTokenAddress('Token address is not known.') log.debug( 'Initiating transfer', initiator=pex(self.raiden.address), target=pex(target), token=pex(token_address), amount=amount, identifier=identifier, ) payment_network_identifier = self.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_raiden(self.raiden), payment_network_id=payment_network_identifier, token_address=token_address, ) async_result = self.raiden.mediated_transfer_async( token_network_identifier=token_network_identifier, amount=amount, target=target, identifier=identifier, ) return async_result
def test_receive_lockedtransfer_invalidrecipient( raiden_network, token_addresses, reveal_timeout, deposit, ): app0, app1 = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) payment_identifier = 1 invalid_recipient = make_address() lock_amount = 10 expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=random.randint(0, UINT64_MAX), payment_identifier=payment_identifier, nonce=1, token_network_address=token_network_identifier, token=token_address, channel_identifier=channel0.identifier, transferred_amount=0, locked_amount=lock_amount, recipient=invalid_recipient, locksroot=UNIT_SECRETHASH, lock=Lock(lock_amount, expiration, UNIT_SECRETHASH), target=app1.raiden.address, initiator=app0.raiden.address, fee=0, ) sign_and_inject( mediated_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) assert_synced_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], )
def token_network_connect( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, funds: typing.TokenAmount, initial_channel_target: int = 3, joinable_funds_target: float = 0.4, ) -> None: """ Automatically maintain channels open for the given token network. Args: token_address: the ERC20 token network to connect to. funds: the amount of funds that can be used by the ConnectionMananger. initial_channel_target: number of channels to open proactively. joinable_funds_target: fraction of the funds that will be used to join channels opened by other participants. """ if not is_binary_address(registry_address): raise InvalidAddress('registry_address must be a valid address in binary') if not is_binary_address(token_address): raise InvalidAddress('token_address must be a valid address in binary') token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) connection_manager = self.raiden.connection_manager_for_token_network( token_network_identifier, ) has_enough_reserve, estimated_required_reserve = has_enough_gas_reserve( raiden=self.raiden, channels_to_open=initial_channel_target, ) if not has_enough_reserve: raise InsufficientGasReserve(( 'The account balance is below the estimated amount necessary to ' 'finish the lifecycles of all active channels. A balance of at ' f'least {estimated_required_reserve} wei is required.' )) connection_manager.connect( funds=funds, initial_channel_target=initial_channel_target, joinable_funds_target=joinable_funds_target, )
def test_automatic_secret_registration(raiden_chain, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) amount = 100 identifier = 1 hold_event_handler = HoldOffChainSecretRequest() app1.raiden.raiden_event_handler = hold_event_handler target = app1.raiden.address secret = sha3(target) secrethash = sha3(secret) hold_event_handler.hold_secretrequest_for(secrethash=secrethash) app0.raiden.start_mediated_transfer_with_secret( token_network_identifier, amount, target, identifier, secret, ) gevent.sleep(1) # wait for the messages to be exchanged # Stop app0 to avoid sending the unlock app0.raiden.transport.stop() reveal_secret = RevealSecret( random.randint(0, UINT64_MAX), secret, ) app0.raiden.sign(reveal_secret) message_handler.MessageHandler().on_message(app1.raiden, reveal_secret) chain_state = views.state_from_app(app1) secrethash = sha3(secret) target_task = chain_state.payment_mapping.secrethashes_to_task[secrethash] lock_expiration = target_task.target_state.transfer.lock.expiration wait_until_block(app1.raiden.chain, lock_expiration) assert app1.raiden.default_secret_registry.check_registered(secrethash)
def test_mediated_transfer_with_entire_deposit( raiden_network, number_of_nodes, token_addresses, deposit, network_wait, public_and_private_rooms, ): app0, app1, app2 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) mediated_transfer( app0, app2, token_network_identifier, deposit, timeout=network_wait * number_of_nodes, ) mediated_transfer( app2, app0, token_network_identifier, deposit * 2, timeout=network_wait * number_of_nodes, ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit * 2, [], app1, 0, [], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit * 2, [], app2, 0, [], )
def test_receive_directtransfer_invalidlocksroot(raiden_network, token_addresses): app0, app1 = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) balance0 = channel.get_balance(channel0.our_state, channel0.partner_state) balance1 = channel.get_balance(channel0.partner_state, channel0.our_state) payment_identifier = 1 invalid_locksroot = UNIT_SECRETHASH channel_identifier = channel0.identifier message_identifier = random.randint(0, UINT64_MAX) direct_transfer_message = DirectTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=message_identifier, payment_identifier=payment_identifier, nonce=1, token_network_address=token_network_identifier, token=token_address, channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, recipient=app1.raiden.address, locksroot=invalid_locksroot, ) sign_and_inject( direct_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) assert_synched_channel_state( token_network_identifier, app0, balance0, [], app1, balance1, [], )
def test_log_directransfer(raiden_chain, token_addresses, deposit): """The action that starts a direct transfer must be logged in the WAL.""" app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) amount = int(deposit / 2.) payment_identifier = 13 direct_transfer( app0, app1, token_network_identifier, amount, payment_identifier, ) app0_state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry(app0_state_changes, ActionTransferDirect, { 'token_network_identifier': token_network_identifier, 'amount': amount, 'receiver_address': app1.raiden.address, }) app1_state_changes = app1.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry(app1_state_changes, ReceiveTransferDirect, { 'token_network_identifier': token_network_identifier, 'payment_identifier': payment_identifier, 'balance_proof': { 'transferred_amount': amount, 'sender': app0.raiden.address, }, })
def test_regression_revealsecret_after_secret(raiden_network, token_addresses, transport_protocol): """ A RevealSecret message received after a Secret message must be cleanly handled. """ app0, app1, app2 = raiden_network token = token_addresses[0] identifier = 1 payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token, ) transfer = app0.raiden.mediated_transfer_async( token_network_identifier, amount=1, target=app2.raiden.address, identifier=identifier, ) assert transfer.wait() event = must_contain_entry( app1.raiden.wal.storage.get_events(), SendSecretReveal, {}, ) assert event message_identifier = random.randint(0, UINT64_MAX) reveal_secret = RevealSecret( message_identifier, event.secret, ) app2.raiden.sign(reveal_secret) if transport_protocol is TransportProtocol.UDP: reveal_data = reveal_secret.encode() host_port = None app1.raiden.transport.receive(reveal_data, host_port) elif transport_protocol is TransportProtocol.MATRIX: app1.raiden.transport._receive_message(reveal_secret) # pylint: disable=protected-access else: raise TypeError('Unknown TransportProtocol')
def test_failfast_lockedtransfer_nochannel(raiden_network, token_addresses): """When the node has no channels it should fail without raising exceptions.""" token_address = token_addresses[0] app0, app1 = raiden_network amount = 10 payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address, ) async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount, app1.raiden.address, identifier=1, ) assert async_result.wait() is False
def test_mediated_transfer_messages_out_of_order( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_matrix, ): app0, app1, app2 = raiden_network _patch_transport(app1.raiden.transport) _patch_transport(app2.raiden.transport) token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) amount = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], ) with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_identifier, app1, deposit - amount, [], app2, deposit + amount, [], )
def token_network_leave(self, registry_address, token_address, only_receiving=True): """Close all channels and wait for settlement.""" if not is_binary_address(token_address): raise InvalidAddress('token_address must be a valid address in binary') if token_address not in self.get_tokens_list(registry_address): raise UnknownTokenAddress('token_address unknown') token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_raiden(self.raiden), payment_network_id=registry_address, token_address=token_address, ) connection_manager = self.raiden.connection_manager_for_token_network( token_network_identifier, ) return connection_manager.leave(registry_address, only_receiving)
def test_receive_directtransfer_invalidtoken(raiden_network, deposit, token_addresses): app0, app1 = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) message_identifier = random.randint(0, UINT64_MAX) payment_identifier = 1 invalid_token_address = make_address() channel_identifier = channel0.identifier direct_transfer_message = DirectTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=message_identifier, payment_identifier=payment_identifier, nonce=1, token_network_address=token_network_identifier, token=invalid_token_address, channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, recipient=app1.raiden.address, locksroot=EMPTY_MERKLE_ROOT, ) sign_and_inject( direct_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], )
def transfer(initiator_app, target_app, token, amount, identifier): """ Nice to read shortcut to make a transfer. The transfer is either a DirectTransfer or a LockedTransfer, in both cases all apps are synched, in the case of a LockedTransfer the secret will be revealed. """ payment_network_identifier = initiator_app.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(initiator_app), payment_network_identifier, token, ) async_result = initiator_app.raiden.mediated_transfer_async( token_network_identifier, amount, target_app.raiden.address, identifier, ) assert async_result.wait()
def test_direct_transfer_to_offline_node(raiden_network, token_addresses, deposit): app0, app1 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) # Wait until the initialization of the node is complete and then stop it gevent.wait([app1.raiden.start_event]) app1.raiden.stop() amount = 10 target = app1.raiden.address payment_identifier = 13 app0.raiden.direct_transfer_async( token_network_identifier, amount, target, identifier=payment_identifier, ) app1.raiden.start() exception = ValueError('Waiting for transfer received success in the WAL timed out') with gevent.Timeout(seconds=5, exception=exception): wait_for_transfer_success( app1.raiden, payment_identifier, amount, app1.raiden.alarm.sleep_time, ) no_outstanding_locks = [] assert_synched_channel_state( token_network_identifier, app0, deposit - amount, no_outstanding_locks, app1, deposit + amount, no_outstanding_locks, )
def test_mediated_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, ): app0, app1, app2 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) amount = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) wait_assert( token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], func=assert_synched_channel_state, timeout=network_wait, ) wait_assert( token_network_identifier, app1, deposit - amount, [], app2, deposit + amount, [], func=assert_synched_channel_state, timeout=network_wait, )
def test_initiator_log_directransfer_success(raiden_chain, token_addresses, deposit): app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 7 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) direct_transfer( app0, app1, token_network_identifier, amount, identifier, ) app0_events = app0.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) app0_all_events = [event for _, event in app0_events] assert must_contain_entry(app0_all_events, EventTransferSentSuccess, { 'identifier': identifier, 'amount': amount, 'target': app1.raiden.address, }) app1_state_events = app1.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) app1_all_events = [event for _, event in app1_state_events] assert must_contain_entry(app1_all_events, EventTransferReceivedSuccess, { 'identifier': identifier, 'amount': amount, 'initiator': app0.raiden.address, })
def _transfer_unlocked( initiator_app: App, target_app: App, token_address: TokenAddress, amount: PaymentAmount, identifier: PaymentID, fee: FeeAmount = 0, timeout: Optional[float] = None, ) -> None: assert isinstance(target_app.raiden.message_handler, WaitForMessage) if timeout is None: timeout = 10 wait_for_unlock = target_app.raiden.message_handler.wait_for_message( Unlock, {"payment_identifier": identifier}) payment_network_identifier = initiator_app.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_app(initiator_app), payment_network_id=payment_network_identifier, token_address=token_address, ) payment_status = initiator_app.raiden.mediated_transfer_async( token_network_identifier=token_network_identifier, amount=amount, target=target_app.raiden.address, identifier=identifier, fee=fee, ) with Timeout(seconds=timeout): wait_for_unlock.get() msg = (f"transfer from {pex(initiator_app.raiden.address)} " f"to {pex(target_app.raiden.address)} failed.") assert payment_status.payment_done.get(), msg
def handle_channel_settled(raiden, event): registry_address = event.event_data['registry_address'] data = event.event_data channel_identifier = event.originating_contract channel_state = views.search_for_channel( views.state_from_raiden(raiden), registry_address, channel_identifier, ) if channel_state: token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_raiden(raiden), registry_address, channel_state.token_address, ) channel_settled = ContractReceiveChannelSettled( token_network_identifier, channel_identifier, data['block_number'], ) raiden.handle_state_change(channel_settled)
def _transfer_secret_not_requested( initiator_app: App, target_app: App, token_address: TokenAddress, amount: PaymentAmount, identifier: PaymentID, fee: FeeAmount = 0, timeout: Optional[float] = None, ): if timeout is None: timeout = 10 secret = make_secret() secrethash = sha3(secret) hold_secret_request = target_app.raiden.raiden_event_handler.hold( SendSecretRequest, {"secrethash": secrethash}) payment_network_identifier = initiator_app.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=views.state_from_app(initiator_app), payment_network_id=payment_network_identifier, token_address=token_address, ) initiator_app.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=amount, fee=fee, target=target_app.raiden.address, identifier=identifier, secret=secret, secrethash=secrethash, ) with Timeout(seconds=timeout): hold_secret_request.get()
def test_settled_lock(token_addresses, raiden_network, deposit): """ Any transfer following a secret revealed must update the locksroot, so hat an attacker cannot reuse a secret to double claim a lock.""" app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] amount = 30 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) address0 = app0.raiden.address address1 = app1.raiden.address deposit0 = deposit deposit1 = deposit token_proxy = app0.raiden.chain.token(token_address) initial_balance0 = token_proxy.balance_of(address0) initial_balance1 = token_proxy.balance_of(address1) # Using a pending mediated transfer because this allows us to compute the # merkle proof identifier = 1 secret = pending_mediated_transfer( raiden_network, token_network_identifier, amount, identifier, ) # Save the merkle tree leaves from the pending transfer, used to test the unlock channelstate_0_1 = get_channelstate(app0, app1, token_network_identifier) batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state) assert batch_unlock claim_lock(raiden_network, identifier, token_network_identifier, secret) # Make a new transfer direct_transfer(app0, app1, token_network_identifier, amount, identifier=1) RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_settle( app1.raiden, app1.raiden.default_registry.address, token_address, [channelstate_0_1.identifier], app1.raiden.alarm.sleep_time, ) netting_channel = app1.raiden.chain.payment_channel( token_network_identifier, channelstate_0_1.identifier, ) # The direct transfer locksroot must not contain the unlocked lock, the # unlock must fail. with pytest.raises(Exception): netting_channel.unlock( channelstate_0_1.partner_state.address, batch_unlock, ) expected_balance0 = initial_balance0 + deposit0 - amount * 2 expected_balance1 = initial_balance1 + deposit1 + amount * 2 assert token_proxy.balance_of(address0) == expected_balance0 assert token_proxy.balance_of(address1) == expected_balance1
def test_refund_transfer_after_2nd_hop( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, ): """Test the refund transfer sent due to failure after 2nd hop""" # Topology: # # 0 -> 1 -> 2 -> 3 # app0, app1, app2, app3 = raiden_chain token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address, ) # make a transfer to test the path app0 -> app1 -> app2 -> app3 identifier_path = 1 amount_path = 1 mediated_transfer( initiator_app=app0, target_app=app3, token_network_identifier=token_network_identifier, amount=amount_path, identifier=identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app2 -> app3 identifier_drain = 2 amount_drain = deposit * 8 // 10 mediated_transfer( initiator_app=app2, target_app=app3, token_network_identifier=token_network_identifier, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) assert_synced_channel_state( token_network_identifier, app1, deposit - amount_path, [], app2, deposit + amount_path, [], ) assert_synced_channel_state( token_network_identifier, app2, deposit - amount_path - amount_drain, [], app3, deposit + amount_path + amount_drain, [], ) # app0 -> app1 -> app2 > app3 is the only available path, but the channel # app2 -> app3 doesn't have capacity, so a refund will be sent on # app2 -> app1 -> app0 identifier_refund = 3 amount_refund = 50 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app3.raiden.address, identifier_refund, ) assert async_result.wait( ) is False, 'there is no path with capacity, the transfer must fail' gevent.sleep(0.2) # Lock structures with the correct amount send_locked1 = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': amount_refund } }}, ) assert send_locked1 send_refund1 = raiden_events_search_for_item(app1.raiden, SendRefundTransfer, {}) assert send_refund1 lock1 = send_locked1.transfer.lock refund_lock1 = send_refund1.transfer.lock assert lock1.amount == refund_lock1.amount assert lock1.secrethash == refund_lock1.secrethash send_locked2 = raiden_events_search_for_item( app1.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': amount_refund } }}, ) assert send_locked2 send_refund2 = raiden_events_search_for_item(app2.raiden, SendRefundTransfer, {}) assert send_refund2 lock2 = send_locked2.transfer.lock refund_lock2 = send_refund2.transfer.lock assert lock2.amount == refund_lock2.amount assert lock2.secrethash assert lock2.expiration # channels have the amount locked because of the refund message assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock1)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock1)], ) assert_synced_channel_state( token_network_identifier, app1, deposit - amount_path, [lockstate_from_lock(lock2)], app2, deposit + amount_path, [lockstate_from_lock(refund_lock2)], ) assert_synced_channel_state( token_network_identifier, app2, deposit - amount_path - amount_drain, [], app3, deposit + amount_path + amount_drain, [], )
def test_refund_messages(raiden_chain, token_addresses, deposit): # The network has the following topology: # # App0 <---> App1 <---> App2 app0, app1, app2 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address, ) # Exhaust the channel App1 <-> App2 (to force the refund transfer) exhaust_amount = deposit mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=exhaust_amount, identifier=1, ) refund_amount = deposit // 2 identifier = 1 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, refund_amount, app2.raiden.address, identifier, ) assert async_result.wait( ) is False, 'Must fail, there are no routes available' # The transfer from app0 to app2 failed, so the balances did change. # Since the refund is not unlocked both channels have the corresponding # amount locked (issue #1091) send_lockedtransfer = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': refund_amount } }}, ) assert send_lockedtransfer send_refundtransfer = raiden_events_search_for_item( app1.raiden, SendRefundTransfer, {}) assert send_refundtransfer assert_synced_channel_state( token_network_identifier, app0, deposit, [send_lockedtransfer.transfer.lock], app1, deposit, [send_refundtransfer.transfer.lock], ) # This channel was exhausted to force the refund transfer assert_synced_channel_state( token_network_identifier, app1, 0, [], app2, deposit * 2, [], )
def run_test_payment_statuses_are_restored( raiden_network, token_addresses, network_wait, ): app0, app1 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) app0.event_handler = HoldRaidenEvent() app0.event_handler.hold(SendSecretReveal, {}) # make a few transfers from app0 to app1 amount = 1 spent_amount = 7 identifier = 1 for identifier in range(spent_amount): identifier = identifier + 1 payment_status = app0.raiden.mediated_transfer_async( token_network_identifier=token_network_identifier, amount=amount, target=app1.raiden.address, identifier=identifier, ) assert payment_status.payment_identifier == identifier raiden_event_handler = RaidenEventHandler() message_handler = MessageHandler() app0_restart = App( config=app0.config, chain=app0.raiden.chain, query_start_block=0, default_registry=app0.raiden.default_registry, default_secret_registry=app0.raiden.default_secret_registry, default_service_registry=app0.raiden.default_service_registry, transport=MatrixTransport(app0.raiden.config['transport']['matrix'], ), raiden_event_handler=raiden_event_handler, message_handler=message_handler, discovery=app0.raiden.discovery, ) app0.stop() del app0 # from here on the app0_restart should be used # stop app1 to make sure that we don't complete the transfers before our checks app1.stop() app0_restart.start() # Check that the payment statuses were restored properly after restart for identifier in range(spent_amount): identifier = identifier + 1 mapping = app0_restart.raiden.targets_to_identifiers_to_statuses status = mapping[app1.raiden.address][identifier] assert status.amount == 1 assert status.payment_identifier == identifier assert status.token_network_identifier == token_network_identifier app1.start() # now that our checks are done start app1 again waiting.wait_for_healthy( app0_restart.raiden, app1.raiden.address, network_wait, ) waiting.wait_for_payment_balance( raiden=app1.raiden, payment_network_id=payment_network_id, token_address=token_address, partner_address=app0_restart.raiden.address, target_address=app1.raiden.address, target_balance=spent_amount, retry_timeout=network_wait, ) # Check that payments are completed after both nodes come online after restart for identifier in range(spent_amount): assert raiden_events_search_for_item( app0_restart.raiden, EventPaymentSentSuccess, { 'identifier': identifier + 1, 'amount': 1 }, )
def channel_batch_close( self, registry_address: typing.PaymentNetworkID, token_address: typing.TokenAddress, partner_addresses: typing.List[typing.Address], retry_timeout: typing.NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ): """Close a channel opened with `partner_address` for the given `token_address`. Race condition, this can fail if channel was closed externally. """ if not is_binary_address(token_address): raise InvalidAddress( 'Expected binary address format for token in channel close') if not all(map(is_binary_address, partner_addresses)): raise InvalidAddress( 'Expected binary address format for partner in channel close') valid_tokens = views.get_token_network_addresses_for( views.state_from_raiden(self.raiden), registry_address, ) if token_address not in valid_tokens: raise UnknownTokenAddress('Token address is not known.') chain_state = views.state_from_raiden(self.raiden) channels_to_close = views.filter_channels_by_partneraddress( chain_state, registry_address, token_address, partner_addresses, ) token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_raiden(self.raiden), registry_address, token_address, ) # If concurrent operations are happening on one of the channels, fail entire # request. with ExitStack() as stack: # Put all the locks in this outer context so that the netting channel functions # don't release the locks when their context goes out of scope for channel_state in channels_to_close: channel = self.raiden.chain.payment_channel( token_network_identifier, channel_state.identifier, ) stack.enter_context(channel.lock_or_raise()) for channel_state in channels_to_close: channel_close = ActionChannelClose( token_network_identifier, channel_state.identifier, ) self.raiden.handle_state_change(channel_close) channel_ids = [ channel_state.identifier for channel_state in channels_to_close ] waiting.wait_for_close( self.raiden, registry_address, token_address, channel_ids, retry_timeout, )
def test_receive_lockedtransfer_invalidnonce( raiden_network, deposit, token_addresses, reveal_timeout, network_wait, skip_if_not_udp, ): app0, app1, app2 = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) amount = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait, ) amount = 10 payment_identifier = 1 repeated_nonce = 1 expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( message_identifier=random.randint(0, UINT64_MAX), payment_identifier=payment_identifier, nonce=repeated_nonce, token_network_address=token_network_identifier, token=token_address, channel=channel0.identifier, transferred_amount=amount, locked_amount=amount, recipient=app1.raiden.address, locksroot=UNIT_SECRETHASH, lock=Lock(amount, expiration, UNIT_SECRETHASH), target=app2.raiden.address, initiator=app0.raiden.address, fee=0, ) sign_and_inject( mediated_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) assert_synched_channel_state( token_network_identifier, app0, deposit - amount, [], app1, deposit + amount, [], )
def test_channel_deposit(raiden_chain, deposit, retry_timeout, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] registry_address = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) channel1 = get_channelstate(app1, app0, token_network_identifier) assert channel0 is None assert channel1 is None RaidenAPI(app0.raiden).channel_open(registry_address, token_address, app1.raiden.address) gevent.sleep(retry_timeout) assert_synched_channel_state( token_network_identifier, app0, 0, [], app1, 0, [], ) RaidenAPI(app0.raiden).set_total_channel_deposit( registry_address, token_address, app1.raiden.address, deposit, ) gevent.sleep(retry_timeout) assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, 0, [], ) RaidenAPI(app1.raiden).set_total_channel_deposit( registry_address, token_address, app0.raiden.address, deposit, ) gevent.sleep(retry_timeout) assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], )
def test_recovery_happy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, ): app0, app1, app2 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) # make a few transfers from app0 to app2 amount = 1 spent_amount = deposit - 2 for _ in range(spent_amount): mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) app0.raiden.stop() host_port = (app0.raiden.config['host'], app0.raiden.config['port']) socket = server._udp_socket(host_port) new_transport = UDPTransport( app0.discovery, socket, app0.raiden.transport.throttle_policy, app0.raiden.config['transport'], ) app0_restart = App( config=app0.config, chain=app0.raiden.chain, query_start_block=0, default_registry=app0.raiden.default_registry, default_secret_registry=app0.raiden.default_secret_registry, transport=new_transport, discovery=app0.raiden.discovery, ) app0.stop() del app0 # from here on the app0_restart should be used assert_synched_channel_state( token_network_identifier, app0_restart, deposit - spent_amount, [], app1, deposit + spent_amount, [], ) assert_synched_channel_state( token_network_identifier, app1, deposit - spent_amount, [], app2, deposit + spent_amount, [], ) # wait for the nodes' healthcheck to update the network statuses waiting.wait_for_healthy( app0_restart.raiden, app1.raiden.address, network_wait, ) waiting.wait_for_healthy( app1.raiden, app0_restart.raiden.address, network_wait, ) mediated_transfer( app2, app0_restart, token_network_identifier, amount, timeout=network_wait * number_of_nodes * 2, ) mediated_transfer( app0_restart, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes * 2, ) assert_synched_channel_state( token_network_identifier, app0_restart, deposit - spent_amount, [], app1, deposit + spent_amount, [], ) assert_synched_channel_state( token_network_identifier, app1, deposit - spent_amount, [], app2, deposit + spent_amount, [], )
def test_batch_unlock(raiden_network, token_addresses, secret_registry_address, deposit): """Batch unlock can be called after the channel is settled.""" alice_app, bob_app = raiden_network registry_address = alice_app.raiden.default_registry.address token_address = token_addresses[0] token_proxy = alice_app.raiden.chain.token(token_address) token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_identifier = get_channelstate(alice_app, bob_app, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channels[ bob_app.raiden.address] alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address) bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address) alice_to_bob_amount = 10 identifier = 1 secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) secrethash = sha3(secret) alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(bob_app.raiden).channel_close( registry_address, token_address, alice_app.raiden.address, ) secret_registry_proxy = alice_app.raiden.chain.secret_registry( secret_registry_address, ) secret_registry_proxy.register_secret(secret) assert lock, 'the lock must still be part of the node state' msg = 'the secret must be registered before the lock expires' assert lock.expiration > alice_app.raiden.get_block_number(), msg assert lock.secrethash == sha3(secret) waiting.wait_for_settle( alice_app.raiden, registry_address, token_address, [alice_bob_channel_state.identifier], alice_app.raiden.alarm.sleep_time, ) token_network = views.get_token_network_by_identifier( views.state_from_app(bob_app), token_network_identifier, ) assert channel_identifier in token_network.partneraddresses_to_channels[ alice_app.raiden.address] # wait for the node to call batch unlock with gevent.Timeout(10): wait_for_batch_unlock( bob_app, token_network_identifier, alice_bob_channel_state.partner_state.address, alice_bob_channel_state.our_state.address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(bob_app), token_network_identifier, ) assert channel_identifier not in token_network.partneraddresses_to_channels[ alice_app.raiden.address] alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount assert token_proxy.balance_of( alice_app.raiden.address) == alice_new_balance assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance
def test_query_events(raiden_chain, token_addresses, deposit, settle_timeout, retry_timeout): app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), registry_address, token_address, ) manager0 = app0.raiden.default_registry.token_network_by_token( token_address) channelcount0 = views.total_token_network_channels( views.state_from_app(app0), registry_address, token_address, ) events = get_token_network_registry_events( app0.raiden.chain, registry_address, events=ALL_EVENTS, ) assert must_have_event( events, { 'event': EVENT_TOKEN_NETWORK_CREATED, 'args': { 'token_network_address': to_checksum_address(manager0.address), 'token_address': to_checksum_address(token_address), }, }, ) events = get_token_network_registry_events( app0.raiden.chain, app0.raiden.default_registry.address, events=ALL_EVENTS, from_block=999999998, to_block=999999999, ) assert not events RaidenAPI(app0.raiden).channel_open( registry_address, token_address, app1.raiden.address, ) events = get_token_network_events( app0.raiden.chain, manager0.address, events=ALL_EVENTS, ) _event = must_have_event( events, { 'event': EVENT_CHANNEL_OPENED, 'args': { 'participant1': to_checksum_address(app0.raiden.address), 'participant2': to_checksum_address(app1.raiden.address), 'settle_timeout': settle_timeout, }, }, ) assert _event channel_id = _event['args']['channel_identifier'] events = get_token_network_events( app0.raiden.chain, manager0.address, events=ALL_EVENTS, from_block=999999998, to_block=999999999, ) assert not events # channel is created but not opened and without funds channelcount1 = views.total_token_network_channels( views.state_from_app(app0), registry_address, token_address, ) assert channelcount0 + 1 == channelcount1 assert_synched_channel_state( token_network_identifier, app0, 0, [], app1, 0, [], ) RaidenAPI(app0.raiden).set_total_channel_deposit( registry_address, token_address, app1.raiden.address, deposit, ) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, token_network_identifier, channel_id, ) deposit_events = get_netting_channel_deposit_events( app0.raiden.chain, token_network_identifier, channel_id, ) total_deposit_event = { 'event': EVENT_CHANNEL_DEPOSIT, 'args': { 'participant': to_checksum_address(app0.raiden.address), 'total_deposit': deposit, 'channel_identifier': channel_id, }, } assert must_have_event(deposit_events, total_deposit_event) assert must_have_event(all_netting_channel_events, total_deposit_event) RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, token_network_identifier, channel_id, ) closed_events = get_netting_channel_closed_events( app0.raiden.chain, token_network_identifier, channel_id, ) closed_event = { 'event': EVENT_CHANNEL_CLOSED, 'args': { 'channel_identifier': channel_id, 'closing_participant': to_checksum_address(app0.raiden.address), }, } assert must_have_event(closed_events, closed_event) assert must_have_event(all_netting_channel_events, closed_event) settle_expiration = app0.raiden.chain.block_number() + settle_timeout + 5 wait_until_block(app0.raiden.chain, settle_expiration) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, token_network_identifier, channel_id, ) settled_events = get_netting_channel_settled_events( app0.raiden.chain, token_network_identifier, channel_id, ) settled_event = { 'event': EVENT_CHANNEL_SETTLED, 'args': { 'channel_identifier': channel_id, }, } assert must_have_event(settled_events, settled_event) assert must_have_event(all_netting_channel_events, settled_event)
def test_lock_expiry(raiden_network, token_addresses, secret_registry_address, deposit): """Test lock expiry and removal.""" alice_app, bob_app = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(alice_app), token_network_identifier, ) channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) channel_identifier = channel_state.identifier assert channel_identifier in token_network.partneraddresses_to_channels[ bob_app.raiden.address] alice_to_bob_amount = 10 identifier = 1 transfer_1_secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) transfer_1_secrethash = sha3(transfer_1_secret) alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue assert_synced_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # Verify lock is registered in both channel states alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task # Wait for the expiration to trigger with some additional buffer # time for processing (+2) blocks. waiting.wait_for_block( alice_app.raiden, lock.expiration + (DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK + 2), DEFAULT_RETRY_TIMEOUT, ) alice_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier) assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks # Verify Bob received the message and processed the LockExpired message bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task # Make another transfer alice_to_bob_amount = 10 identifier = 2 transfer_2_secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) transfer_2_secrethash = sha3(transfer_2_secret) # Make sure the other transfer still exists alice_chain_state = views.state_from_raiden(alice_app.raiden) assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task bob_channel_state = get_channelstate(bob_app, alice_app, token_network_identifier) assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks
def test_unlock(raiden_network, token_addresses, deposit): """Unlock can be called on a closed channel.""" alice_app, bob_app = raiden_network registry_address = alice_app.raiden.default_registry.address token_address = token_addresses[0] token_proxy = alice_app.raiden.chain.token(token_address) token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address, ) alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address) bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address) alice_to_bob_amount = 10 identifier = 1 secret = pending_mediated_transfer( raiden_network, token_network_identifier, alice_to_bob_amount, identifier, ) secrethash = sha3(secret) # This is the current state of the protocol: # # A -> B LockedTransfer # B -> A SecretRequest # - protocol didn't continue alice_bob_channel = get_channelstate(alice_app, bob_app, token_network_identifier) bob_alice_channel = get_channelstate(bob_app, alice_app, token_network_identifier) lock = channel.get_lock(alice_bob_channel.our_state, secrethash) assert lock assert_synched_channel_state( token_network_identifier, alice_app, deposit, [lock], bob_app, deposit, [], ) # get proof, that locked transfermessage was in merkle tree, with locked.root unlock_proof = channel.compute_proof_for_lock( alice_bob_channel.our_state, secret, lock, ) assert validate_proof( unlock_proof.merkle_proof, merkleroot(bob_alice_channel.partner_state.merkletree), sha3(lock.encoded), ) assert unlock_proof.lock_encoded == lock.encoded assert unlock_proof.secret == secret # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(bob_app.raiden).channel_close( registry_address, token_address, alice_app.raiden.address, ) # Unlock will not be called because the secret was not revealed assert lock.expiration > alice_app.raiden.chain.block_number() assert lock.secrethash == sha3(secret) nettingchannel_proxy = bob_app.raiden.chain.netting_channel( bob_alice_channel.identifier, ) nettingchannel_proxy.unlock(unlock_proof) waiting.wait_for_settle( alice_app.raiden, registry_address, token_address, [alice_bob_channel.identifier], alice_app.raiden.alarm.wait_time, ) alice_bob_channel = get_channelstate(alice_app, bob_app, token_network_identifier) bob_alice_channel = get_channelstate(bob_app, alice_app, token_network_identifier) alice_netted_balance = alice_initial_balance + deposit - alice_to_bob_amount bob_netted_balance = bob_initial_balance + deposit + alice_to_bob_amount assert token_proxy.balance_of(alice_app.raiden.address) == alice_netted_balance assert token_proxy.balance_of(bob_app.raiden.address) == bob_netted_balance # Now let's query the WAL to see if the state changes were logged as expected state_changes = alice_app.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) alice_bob_channel = get_channelstate(alice_app, bob_app, token_network_identifier) bob_alice_channel = get_channelstate(bob_app, alice_app, token_network_identifier) assert must_contain_entry(state_changes, ContractReceiveChannelUnlock, { 'payment_network_identifier': registry_address, 'token_address': token_address, 'channel_identifier': alice_bob_channel.identifier, 'secrethash': secrethash, 'secret': secret, 'receiver': bob_app.raiden.address, })
def test_participant_selection(raiden_network, token_addresses): registry_address = raiden_network[0].raiden.default_registry.address # pylint: disable=too-many-locals token_address = token_addresses[0] # connect the first node (will register the token if necessary) RaidenAPI(raiden_network[0].raiden).token_network_connect( registry_address=registry_address, token_address=token_address, funds=100, ) # Test invalid argument values with pytest.raises(InvalidAmount): RaidenAPI(raiden_network[0].raiden).token_network_connect( registry_address=registry_address, token_address=token_address, funds=-1, ) with pytest.raises(InvalidAmount): RaidenAPI(raiden_network[0].raiden).token_network_connect( registry_address=registry_address, token_address=token_address, funds=100, joinable_funds_target=2, ) with pytest.raises(InvalidAmount): RaidenAPI(raiden_network[0].raiden).token_network_connect( registry_address=registry_address, token_address=token_address, funds=100, joinable_funds_target=-1, ) # connect the other nodes connect_greenlets = [ gevent.spawn( RaidenAPI(app.raiden).token_network_connect, registry_address, token_address, 100, ) for app in raiden_network[1:] ] gevent.wait(connect_greenlets) token_network_registry_address = views.get_token_network_identifier_by_token_address( views.state_from_raiden(raiden_network[0].raiden), payment_network_id=registry_address, token_address=token_address, ) connection_managers = [ app.raiden.connection_manager_for_token_network( token_network_registry_address, ) for app in raiden_network ] unsaturated_connection_managers = connection_managers[:] exception = AssertionError('Unsaturated connection managers', unsaturated_connection_managers) with gevent.Timeout(120, exception): while unsaturated_connection_managers: for manager in unsaturated_connection_managers: if is_manager_saturated(manager, registry_address, token_address): unsaturated_connection_managers.remove(manager) gevent.sleep(1) assert saturated_count( connection_managers, registry_address, token_address, ) == len(connection_managers) # ensure unpartitioned network for app in raiden_network: node_state = views.state_from_raiden(app.raiden) network_state = views.get_token_network_by_token_address( node_state, registry_address, token_address, ) assert network_state is not None for target in raiden_network: if target.raiden.address == app.raiden.address: continue routes = routing.get_best_routes( chain_state=node_state, token_network_id=network_state.address, from_address=app.raiden.address, to_address=target.raiden.address, amount=1, previous_address=None, config={}, ) assert routes is not None # create a transfer to the leaving node, so we have a channel to settle for app in raiden_network: sender = app.raiden sender_channel = next( (channel_state for channel_state in RaidenAPI(sender).get_channel_list( registry_address=registry_address, token_address=token_address, ) if channel_state.our_state.contract_balance > 0 and channel_state.partner_state.contract_balance > 0), None) # choose a fully funded channel from sender if sender_channel: break registry_address = sender.default_registry.address receiver = next( app.raiden for app in raiden_network if app.raiden.address == sender_channel.partner_state.address) # assert there is a direct channel receiver -> sender (vv) receiver_channel = RaidenAPI(receiver).get_channel_list( registry_address=registry_address, token_address=token_address, partner_address=sender.address, ) assert len(receiver_channel) == 1 receiver_channel = receiver_channel[0] exception = ValueError('partner not reachable') with gevent.Timeout(30, exception=exception): waiting.wait_for_healthy(sender, receiver.address, 1) amount = 1 RaidenAPI(sender).transfer_and_wait( registry_address, token_address, amount, receiver.address, transfer_timeout=10, ) exception = ValueError('timeout while waiting for incoming transaction') with gevent.Timeout(30, exception=exception): wait_for_transaction( receiver, registry_address, token_address, sender.address, ) # test `leave()` method connection_manager = connection_managers[0] timeout = (sender_channel.settle_timeout * connection_manager.raiden.chain.estimate_blocktime() * 10) assert timeout > 0 exception = ValueError('timeout while waiting for leave') with gevent.Timeout(timeout, exception=exception): # sender leaves the network RaidenAPI(sender).token_network_leave( registry_address, token_address, ) before_block = connection_manager.raiden.chain.block_number() wait_blocks = sender_channel.settle_timeout + 10 # wait until both chains are synced? connection_manager.raiden.chain.wait_until_block( target_block_number=before_block + wait_blocks, ) receiver.chain.wait_until_block(target_block_number=before_block + wait_blocks, ) receiver_channel = RaidenAPI(receiver).get_channel_list( registry_address=registry_address, token_address=token_address, partner_address=sender.address, ) # because of timing, channel may already have been cleaned assert not receiver_channel or receiver_channel[ 0].settle_transaction is not None
def test_channel_lifecycle(raiden_network, token_addresses, deposit, transport_config): node1, node2 = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(node1), node1.raiden.default_registry.address, token_address, ) api1 = RaidenAPI(node1.raiden) api2 = RaidenAPI(node2.raiden) registry_address = node1.raiden.default_registry.address # nodes don't have a channel, so they are not healthchecking assert api1.get_node_network_state(api2.address) == NODE_NETWORK_UNKNOWN assert api2.get_node_network_state(api1.address) == NODE_NETWORK_UNKNOWN assert not api1.get_channel_list(registry_address, token_address, api2.address) # open is a synchronous api api1.channel_open(node1.raiden.default_registry.address, token_address, api2.address) channels = api1.get_channel_list(registry_address, token_address, api2.address) assert len(channels) == 1 channel12 = get_channelstate(node1, node2, token_network_identifier) assert channel.get_status(channel12) == CHANNEL_STATE_OPENED event_list1 = api1.get_blockchain_events_channel( token_address, channel12.partner_state.address, ) assert any((event['event'] == ChannelEvent.OPENED and is_same_address( event['args']['participant1'], to_normalized_address(api1.address), ) and is_same_address( event['args']['participant2'], to_normalized_address(api2.address), )) for event in event_list1) token_events = api1.get_blockchain_events_token_network(token_address, ) assert token_events[0]['event'] == ChannelEvent.OPENED registry_address = api1.raiden.default_registry.address # Load the new state with the deposit api1.set_total_channel_deposit( registry_address, token_address, api2.address, deposit, ) # let's make sure it's idempotent. Same deposit should raise deposit mismatch limit with pytest.raises(DepositMismatch): api1.set_total_channel_deposit( registry_address, token_address, api2.address, deposit, ) channel12 = get_channelstate(node1, node2, token_network_identifier) assert channel.get_status(channel12) == CHANNEL_STATE_OPENED assert channel.get_balance(channel12.our_state, channel12.partner_state) == deposit assert channel12.our_state.contract_balance == deposit assert api1.get_channel_list(registry_address, token_address, api2.address) == [channel12] # there is a channel open, they must be healthchecking each other assert api1.get_node_network_state(api2.address) == NODE_NETWORK_REACHABLE assert api2.get_node_network_state(api1.address) == NODE_NETWORK_REACHABLE event_list2 = api1.get_blockchain_events_channel( token_address, channel12.partner_state.address, ) assert any((event['event'] == ChannelEvent.DEPOSIT and is_same_address( event['args']['participant'], to_normalized_address(api1.address), ) and event['args']['total_deposit'] == deposit) for event in event_list2) api1.channel_close(registry_address, token_address, api2.address) # Load the new state with the channel closed channel12 = get_channelstate(node1, node2, token_network_identifier) event_list3 = api1.get_blockchain_events_channel( token_address, channel12.partner_state.address, ) assert len(event_list3) > len(event_list2) assert any((event['event'] == ChannelEvent.CLOSED and is_same_address( event['args']['closing_participant'], to_normalized_address(api1.address), )) for event in event_list3) assert channel.get_status(channel12) == CHANNEL_STATE_CLOSED settlement_block = ( channel12.close_transaction.finished_block_number + channel12.settle_timeout + 10 # arbitrary number of additional blocks, used to wait for the settle() call ) wait_until_block(node1.raiden.chain, settlement_block) state_changes = node1.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry( state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel12.identifier, })
def test_secret_revealed(raiden_chain, deposit, settle_timeout, token_addresses): app0, app1, app2 = raiden_chain registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) amount = 10 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_network_identifier, amount, identifier, ) secrethash = sha3(secret) gevent.sleep(.1) # wait for the messages channel_state2_1 = get_channelstate(app2, app1, token_network_identifier) # the secret hasn't been revealed yet (through messages) assert len(channel_state2_1.our_state.secrethashes_to_lockedlocks) == 1 proofs = list(channel.get_known_unlocks(channel_state2_1.our_state)) assert not proofs channel.register_secret(channel_state2_1, secret, secrethash) # Close the channel netting_channel_proxy = app2.raiden.chain.netting_channel( channel_state2_1.identifier) netting_channel_proxy.channel_close( registry_address, channel_state2_1.partner_state.balance_proof, ) # Reveal the secret through the blockchain (this needs to emit the # SecretRevealed event) for unlock_proof in channel.get_known_unlocks( channel_state2_1.partner_state): netting_channel_proxy.unlock(unlock_proof) settle_expiration = app0.raiden.chain.block_number() + settle_timeout wait_until_block(app0.raiden.chain, settle_expiration) assert_synched_channel_state( token_address, app1, deposit - amount, [], app2, deposit + amount, [], ) assert_synched_channel_state( token_address, app0, deposit - amount, [], app1, deposit + amount, [], )
def test_secret_revealed(raiden_chain, deposit, settle_timeout, token_addresses): app0, app1, app2 = raiden_chain registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) amount = 10 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_network_identifier, amount, identifier, ) secrethash = sha3(secret) gevent.sleep(.1) # wait for the messages # The secret hasn't been revealed yet channel_state2_1 = get_channelstate(app2, app1, token_network_identifier) assert len(channel_state2_1.our_state.secrethashes_to_lockedlocks) == 1 channel.register_secret(channel_state2_1, secret, secrethash) # Close the channel # This needs to register the secrets on chain netting_channel_proxy = app2.raiden.chain.payment_channel( token_network_identifier, channel_state2_1.identifier, ) netting_channel_proxy.channel_close( registry_address, channel_state2_1.partner_state.balance_proof, ) settle_expiration = app0.raiden.chain.block_number() + settle_timeout wait_until_block(app0.raiden.chain, settle_expiration) assert_synched_channel_state( token_address, app1, deposit - amount, [], app2, deposit + amount, [], ) assert_synched_channel_state( token_address, app0, deposit - amount, [], app1, deposit + amount, [], )
def test_start_end_attack(token_addresses, raiden_chain, deposit): """ An attacker can try to steal tokens from a hub or the last node in a path. The attacker needs to use two addresses (A1 and A2) and connect both to the hub H. Once connected a mediated transfer is initialized from A1 to A2 through H. Once the node A2 receives the mediated transfer the attacker uses the known secret and reveal to close and settle the channel H-A2, without revealing the secret to H's raiden node. The intention is to make the hub transfer the token but for him to be unable to require the token A1.""" amount = 30 token = token_addresses[0] app0, app1, app2 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token, ) # the attacker owns app0 and app2 and creates a transfer through app1 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_network_identifier, amount, identifier, ) secrethash = sha3(secret) attack_channel = get_channelstate(app2, app1, token_network_identifier) attack_transfer = None # TODO attack_contract = attack_channel.external_state.netting_channel.address hub_contract = (get_channelstate( app1, app0, token_network_identifier).external_state.netting_channel.address) # the attacker can create a merkle proof of the locked transfer lock = attack_channel.partner_state.get_lock_by_secrethash(secrethash) unlock_proof = attack_channel.partner_state.compute_proof_for_lock( secret, lock) # start the settle counter attack_balance_proof = attack_transfer.to_balanceproof() attack_channel.netting_channel.channel_close(attack_balance_proof) # wait until the last block to reveal the secret, hopefully we are not # missing a block during the test wait_until_block(app2.raiden.chain, attack_transfer.lock.expiration - 1) # since the attacker knows the secret he can net the lock attack_channel.netting_channel.unlock( UnlockProofState(unlock_proof, attack_transfer.lock, secret), ) # XXX: verify that the secret was publicized # at this point the hub might not know the secret yet, and won't be able to # claim the token from the channel A1 - H # the attacker settles the contract app2.raiden.chain.next_block() attack_channel.netting_channel.settle(token, attack_contract) # at this point the attacker has the "stolen" funds attack_contract = app2.raiden.chain.token_hashchannel[token][ attack_contract] assert attack_contract.participants[ app2.raiden.address]['netted'] == deposit + amount assert attack_contract.participants[ app1.raiden.address]['netted'] == deposit - amount # and the hub's channel A1-H doesn't hub_contract = app1.raiden.chain.token_hashchannel[token][hub_contract] assert hub_contract.participants[app0.raiden.address]['netted'] == deposit assert hub_contract.participants[app1.raiden.address]['netted'] == deposit # to mitigate the attack the Hub _needs_ to use a lower expiration for the # locked transfer between H-A2 than A1-H. For A2 to acquire the token # it needs to make the secret public in the blockchain so it publishes the # secret through an event and the Hub is able to require its funds app1.raiden.chain.next_block() # XXX: verify that the Hub has found the secret, close and settle the channel # the hub has acquired its token hub_contract = app1.raiden.chain.token_hashchannel[token][hub_contract] assert hub_contract.participants[ app0.raiden.address]['netted'] == deposit + amount assert hub_contract.participants[ app1.raiden.address]['netted'] == deposit - amount
def run_test_node_can_settle_if_close_didnt_use_any_balance_proof( raiden_network, number_of_nodes, token_addresses, network_wait, ): app0, app1 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address registry_address = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state=chain_state, payment_network_id=payment_network_id, token_address=token_address, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier # make a transfer from app0 to app1 so that app1 is supposed to have a non # empty balance hash transfer( initiator_app=app0, target_app=app1, token_address=token_address, amount=1, identifier=1, timeout=network_wait * number_of_nodes, ) # stop app1 - the test uses token_network_contract now app1.stop() token_network_contract = TokenNetwork( jsonrpc_client=app1.raiden.chain.client, token_network_address=token_network_identifier, contract_manager=app1.raiden.contract_manager, ) # app1 closes the channel with an empty hash instead of the expected hash # of the transferred amount from app0 token_network_contract.close( channel_identifier=channel_identifier, partner=app0.raiden.address, balance_hash=EMPTY_HASH, nonce=0, additional_hash=EMPTY_HASH, signature=EMPTY_SIGNATURE, given_block_identifier='latest', ) waiting.wait_for_settle( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert search_for_item( state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, }, )
def test_settle_is_automatically_called(raiden_network, token_addresses, deposit): """Settle is automatically called by one of the nodes.""" app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( views.state_from_app(app0), token_network_identifier, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channels[ app1.raiden.address] # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) channel_state = views.get_channelstate_for( views.state_from_raiden(app0.raiden), registry_address, token_address, app1.raiden.address, ) assert channel_state.close_transaction.finished_block_number waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) token_network = views.get_token_network_by_identifier( views.state_from_app(app0), token_network_identifier, ) assert channel_identifier not in token_network.partneraddresses_to_channels[ app1.raiden.address] state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry( state_changes, ContractReceiveChannelClosed, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'transaction_from': app1.raiden.address, 'closed_block_number': channel_state.close_transaction.finished_block_number, }) assert must_contain_entry( state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_stress( request, raiden_network, deposit, retry_timeout, token_addresses, port_generator, skip_if_not_udp, ): config_converter = LogLevelConfigType() logging_levels = config_converter.convert( value=request.config.option.log_config or '', param=None, ctx=None, ) _trimmed_logging(logging_levels) token_address = token_addresses[0] rest_apis = start_apiserver_for_network(raiden_network, port_generator) identifier_generator = count() timeout = 120 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(raiden_network[0]), raiden_network[0].raiden.default_registry.address, token_address, ) for _ in range(3): with gevent.Timeout(timeout): assert_channels( raiden_network, token_network_identifier, deposit, ) with gevent.Timeout(timeout): stress_send_serial_transfers( rest_apis, token_address, identifier_generator, deposit, ) raiden_network, rest_apis = restart_network_and_apiservers( raiden_network, rest_apis, port_generator, retry_timeout, ) with gevent.Timeout(timeout): assert_channels( raiden_network, token_network_identifier, deposit, ) with gevent.Timeout(timeout): stress_send_parallel_transfers( rest_apis, token_address, identifier_generator, deposit, ) raiden_network, rest_apis = restart_network_and_apiservers( raiden_network, rest_apis, port_generator, retry_timeout, ) with gevent.Timeout(timeout): assert_channels( raiden_network, token_network_identifier, deposit, ) with gevent.Timeout(timeout): stress_send_and_receive_parallel_transfers( rest_apis, token_address, identifier_generator, deposit, ) raiden_network, rest_apis = restart_network_and_apiservers( raiden_network, rest_apis, port_generator, retry_timeout, ) restart_network(raiden_network, retry_timeout)
def test_automatic_dispute(raiden_network, deposit, token_addresses): app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) token_proxy = app0.raiden.chain.token(channel0.token_address) initial_balance0 = token_proxy.balance_of(app0.raiden.address) initial_balance1 = token_proxy.balance_of(app1.raiden.address) amount0_1 = 10 direct_transfer( app0, app1, token_network_identifier, amount0_1, ) amount1_1 = 50 direct_transfer( app1, app0, token_network_identifier, amount1_1, ) amount0_2 = 60 direct_transfer( app0, app1, token_network_identifier, amount0_2, ) # Alice can only provide one of Bob's transfer, so she is incentivized to # use the one with the largest transferred_amount. RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) # Bob needs to provide a transfer otherwise its netted balance will be # wrong, so he is incentivised to use Alice's transfer with the largest # transferred_amount. # # This is done automatically # channel1.external_state.update_transfer( # alice_second_transfer, # ) waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel0.identifier], app0.raiden.alarm.sleep_time, ) # check that the channel is properly settled and that Bob's client # automatically called updateTransfer() to reflect the actual transactions assert token_proxy.balance_of(token_network_identifier) == 0 total0 = amount0_1 + amount0_2 total1 = amount1_1 expected_balance0 = initial_balance0 + deposit - total0 + total1 expected_balance1 = initial_balance1 + deposit + total0 - total1 assert token_proxy.balance_of(app0.raiden.address) == expected_balance0 assert token_proxy.balance_of(app1.raiden.address) == expected_balance1
def test_received_lockedtransfer_closedchannel( raiden_network, reveal_timeout, token_addresses, deposit, ): app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) wait_until_block( app0.raiden.chain, app0.raiden.chain.block_number() + 1, ) # Now receive one mediated transfer for the closed channel lock_amount = 10 payment_identifier = 1 expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( message_identifier=random.randint(0, UINT64_MAX), payment_identifier=payment_identifier, nonce=1, token_network_address=token_network_identifier, token=token_address, channel=channel0.identifier, transferred_amount=0, locked_amount=lock_amount, recipient=app1.raiden.address, locksroot=UNIT_SECRETHASH, lock=Lock(lock_amount, expiration, UNIT_SECRETHASH), target=app1.raiden.address, initiator=app0.raiden.address, fee=0, ) sign_and_inject( mediated_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) # The local state must not change since the channel is already closed assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], )
def test_refund_transfer(raiden_chain, token_addresses, deposit, network_wait, skip_if_not_udp): """A failed transfer must send a refund back. TODO: - Unlock the token on refund #1091 - Clear the merkletree and update the locked amount #193 - Remove the refund message type #490""" # Topology: # # 0 -> 1 -> 2 # app0, app1, app2 = raiden_chain token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address, ) # make a transfer to test the path app0 -> app1 -> app2 identifier_path = 1 amount_path = 1 mediated_transfer( app0, app2, token_network_identifier, amount_path, identifier_path, timeout=network_wait, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 direct_transfer( app1, app2, token_network_identifier, amount_drain, identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synched_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) assert_synched_channel_state( token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # app0 -> app1 -> app2 is the only available path, but the channel app1 -> # app2 doesn't have capacity, so a refund will be sent on app1 -> app0 identifier_refund = 3 amount_refund = 50 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, ) assert async_result.wait( ) is False, 'there is no path with capacity, the transfer must fail' gevent.sleep(0.2) # A lock structure with the correct amount send_locked = next( event for _, event in app0.raiden.wal.storage.get_events_by_identifier( 0, 'latest') if isinstance(event, SendLockedTransfer) and event.transfer.lock.amount == amount_refund) assert send_locked send_refund = next( event for _, event in app1.raiden.wal.storage.get_events_by_identifier( 0, 'latest') if isinstance(event, SendRefundTransfer)) assert send_refund lock = send_locked.transfer.lock refund_lock = send_refund.lock assert lock.amount == refund_lock.amount assert lock.secrethash assert lock.expiration # Both channels have the amount locked because of the refund message assert_synched_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) assert_synched_channel_state( token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], )
def test_stress( raiden_network, deposit, retry_timeout, token_addresses, port_generator, skip_if_not_udp, ): token_address = token_addresses[0] rest_apis = start_apiserver_for_network(raiden_network, port_generator) identifier_generator = count() timeout = 120 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(raiden_network[0]), raiden_network[0].raiden.default_registry.address, token_address, ) for _ in range(3): with gevent.Timeout(timeout): assert_channels( raiden_network, token_network_identifier, deposit, ) with gevent.Timeout(timeout): stress_send_serial_transfers( rest_apis, token_address, identifier_generator, deposit, ) raiden_network, rest_apis = restart_network_and_apiservers( raiden_network, rest_apis, port_generator, retry_timeout, ) with gevent.Timeout(timeout): assert_channels( raiden_network, token_network_identifier, deposit, ) with gevent.Timeout(timeout): stress_send_parallel_transfers( rest_apis, token_address, identifier_generator, deposit, ) raiden_network, rest_apis = restart_network_and_apiservers( raiden_network, rest_apis, port_generator, retry_timeout, ) with gevent.Timeout(timeout): assert_channels( raiden_network, token_network_identifier, deposit, ) with gevent.Timeout(timeout): stress_send_and_receive_parallel_transfers( rest_apis, token_address, identifier_generator, deposit, ) raiden_network, rest_apis = restart_network_and_apiservers( raiden_network, rest_apis, port_generator, retry_timeout, ) restart_network(raiden_network, retry_timeout)
def test_refund_transfer( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout, # UDP does not seem to retry messages until processed # https://github.com/raiden-network/raiden/issues/3185 skip_if_not_matrix, ): """A failed transfer must send a refund back. TODO: - Unlock the token on refund #1091 - Clear the merkletree and update the locked amount #193 - Remove the refund message type #490""" # Topology: # # 0 -> 1 -> 2 # app0, app1, app2 = raiden_chain token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address, ) # make a transfer to test the path app0 -> app1 -> app2 identifier_path = 1 amount_path = 1 mediated_transfer( app0, app2, token_network_identifier, amount_path, identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) assert_synced_channel_state( token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # app0 -> app1 -> app2 is the only available path, but the channel app1 -> # app2 doesn't have capacity, so a refund will be sent on app1 -> app0 identifier_refund = 3 amount_refund = 50 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, ) assert async_result.wait( ) is False, 'there is no path with capacity, the transfer must fail' gevent.sleep(0.2) # A lock structure with the correct amount send_locked = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': amount_refund } }}, ) assert send_locked secrethash = send_locked.transfer.lock.secrethash send_refund = raiden_events_search_for_item(app1.raiden, SendRefundTransfer, {}) assert send_refund lock = send_locked.transfer.lock refund_lock = send_refund.transfer.lock assert lock.amount == refund_lock.amount assert lock.secrethash assert lock.expiration assert lock.secrethash == refund_lock.secrethash # Both channels have the amount locked because of the refund message assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) assert_synced_channel_state( token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # Additional checks for LockExpired causing nonce mismatch after refund transfer: # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046 # At this point make sure that the initiator has not deleted the payment task assert secrethash in state_from_raiden( app0.raiden).payment_mapping.secrethashes_to_task # Wait for lock lock expiration but make sure app0 never processes LockExpired with dont_handle_lock_expired_mock(app0): wait_for_block( raiden=app0.raiden, block_number=channel.get_sender_expiration_threshold(lock) + 1, retry_timeout=retry_timeout, ) # make sure that app0 still has the payment task for the secrethash # https://github.com/raiden-network/raiden/issues/3183 assert secrethash in state_from_raiden( app0.raiden).payment_mapping.secrethashes_to_task # make sure that app1 sent a lock expired message for the secrethash send_lock_expired = raiden_events_search_for_item( app1.raiden, SendLockExpired, {'secrethash': secrethash}, ) assert send_lock_expired # make sure that app0 never got it state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( 0, 'latest') assert not search_for_item( state_changes, ReceiveLockExpired, {'secrethash': secrethash}, ) # Out of the handicapped app0 transport. # Now wait till app0 receives and processes LockExpired receive_lock_expired = wait_for_state_change( app0.raiden, ReceiveLockExpired, {'secrethash': secrethash}, retry_timeout, ) # And also till app1 received the processed wait_for_state_change( app1.raiden, ReceiveProcessed, {'message_identifier': receive_lock_expired.message_identifier}, retry_timeout, ) # make sure app1 queue has cleared the SendLockExpired chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) result = [(queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue] assert not result # and now wait for 1 more block so that the payment task can be deleted wait_for_block( raiden=app0.raiden, block_number=app0.raiden.get_block_number() + 1, retry_timeout=retry_timeout, ) # and since the lock expired message has been sent and processed then the # payment task should have been deleted from both nodes # https://github.com/raiden-network/raiden/issues/3183 assert secrethash not in state_from_raiden( app0.raiden).payment_mapping.secrethashes_to_task assert secrethash not in state_from_raiden( app1.raiden).payment_mapping.secrethashes_to_task
def run_test_send_queued_messages( raiden_network, deposit, token_addresses, network_wait, ): app0, app1 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) with dont_handle_node_change_network_state(): # stop app1 - transfer must be left unconfirmed app1.stop() # make a few transfers from app0 to app1 amount = 1 spent_amount = 7 identifier = 1 for _ in range(spent_amount): app0.raiden.mediated_transfer_async( token_network_identifier=token_network_identifier, amount=amount, target=app1.raiden.address, identifier=identifier, ) identifier += 1 # restart app0 app0.raiden.stop() new_transport = MatrixTransport( app0.raiden.config['transport']['matrix'], ) raiden_event_handler = RaidenEventHandler() message_handler = MessageHandler() app0_restart = App( config=app0.config, chain=app0.raiden.chain, query_start_block=0, default_registry=app0.raiden.default_registry, default_secret_registry=app0.raiden.default_secret_registry, default_service_registry=app0.raiden.default_service_registry, transport=new_transport, raiden_event_handler=raiden_event_handler, message_handler=message_handler, discovery=app0.raiden.discovery, ) app0.stop() del app0 # from here on the app0_restart should be used app1.start() app0_restart.start() waiting.wait_for_healthy( app0_restart.raiden, app1.raiden.address, network_wait, ) waiting.wait_for_healthy( app1.raiden, app0_restart.raiden.address, network_wait, ) exception = RuntimeError('Timeout while waiting for new channel') with gevent.Timeout(5, exception=exception): waiting.wait_for_newchannel( raiden=app0_restart.raiden, payment_network_id=payment_network_id, token_address=token_address, partner_address=app1.raiden.address, retry_timeout=network_wait, ) exception = RuntimeError( 'Timeout while waiting for balance update for app0') with gevent.Timeout(30, exception=exception): waiting.wait_for_payment_balance( raiden=app0_restart.raiden, payment_network_id=payment_network_id, token_address=token_address, partner_address=app1.raiden.address, target_address=app1.raiden.address, target_balance=spent_amount, retry_timeout=network_wait, ) waiting.wait_for_payment_balance( raiden=app1.raiden, payment_network_id=payment_network_id, token_address=token_address, partner_address=app0_restart.raiden.address, target_address=app1.raiden.address, target_balance=spent_amount, retry_timeout=network_wait, ) assert_synced_channel_state( token_network_identifier, app0_restart, deposit - spent_amount, [], app1, deposit + spent_amount, [], )
def test_different_view_of_last_bp_during_unlock( raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout, # UDP does not seem to retry messages until processed # https://github.com/raiden-network/raiden/issues/3185 skip_if_not_matrix, ): """Test for https://github.com/raiden-network/raiden/issues/3196#issuecomment-449163888""" # Topology: # # 0 -> 1 -> 2 # app0, app1, app2 = raiden_chain token_address = token_addresses[0] payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token_address, ) token_proxy = app0.raiden.chain.token(token_address) initial_balance0 = token_proxy.balance_of(app0.raiden.address) initial_balance1 = token_proxy.balance_of(app1.raiden.address) # make a transfer to test the path app0 -> app1 -> app2 identifier_path = 1 amount_path = 1 mediated_transfer( app0, app2, token_network_identifier, amount_path, identifier_path, timeout=network_wait * number_of_nodes, ) # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 mediated_transfer( initiator_app=app1, target_app=app2, token_network_identifier=token_network_identifier, amount=amount_drain, identifier=identifier_drain, timeout=network_wait, ) # wait for the nodes to sync gevent.sleep(0.2) assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [], app1, deposit + amount_path, [], ) assert_synced_channel_state( token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # app0 -> app1 -> app2 is the only available path, but the channel app1 -> # app2 doesn't have capacity, so a refund will be sent on app1 -> app0 identifier_refund = 3 amount_refund = 50 async_result = app0.raiden.mediated_transfer_async( token_network_identifier, amount_refund, app2.raiden.address, identifier_refund, ) assert async_result.wait( ) is False, 'there is no path with capacity, the transfer must fail' gevent.sleep(0.2) # A lock structure with the correct amount send_locked = raiden_events_search_for_item( app0.raiden, SendLockedTransfer, {'transfer': { 'lock': { 'amount': amount_refund } }}, ) assert send_locked secrethash = send_locked.transfer.lock.secrethash send_refund = raiden_events_search_for_item(app1.raiden, SendRefundTransfer, {}) assert send_refund lock = send_locked.transfer.lock refund_lock = send_refund.transfer.lock assert lock.amount == refund_lock.amount assert lock.secrethash assert lock.expiration assert lock.secrethash == refund_lock.secrethash # Both channels have the amount locked because of the refund message assert_synced_channel_state( token_network_identifier, app0, deposit - amount_path, [lockstate_from_lock(lock)], app1, deposit + amount_path, [lockstate_from_lock(refund_lock)], ) assert_synced_channel_state( token_network_identifier, app1, deposit - amount_path - amount_drain, [], app2, deposit + amount_path + amount_drain, [], ) # Additional checks for LockExpired causing nonce mismatch after refund transfer: # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046 # At this point make sure that the initiator has not deleted the payment task assert secrethash in state_from_raiden( app0.raiden).payment_mapping.secrethashes_to_task with dont_handle_node_change_network_state(): # now app1 goes offline app1.raiden.stop() app1.raiden.get() assert not app1.raiden # Wait for lock expiration so that app0 sends a LockExpired wait_for_block( raiden=app0.raiden, block_number=channel.get_sender_expiration_threshold(lock) + 1, retry_timeout=retry_timeout, ) # make sure that app0 sent a lock expired message for the secrethash wait_for_raiden_event( app0.raiden, SendLockExpired, {'secrethash': secrethash}, retry_timeout, ) # now app0 closes the channel RaidenAPI(app0.raiden).channel_close( registry_address=payment_network_identifier, token_address=token_address, partner_address=app1.raiden.address, ) count = 0 original_update = app1.raiden.raiden_event_handler.handle_contract_send_channelupdate def patched_update(raiden, event): nonlocal count count += 1 original_update(raiden, event) app1.raiden.raiden_event_handler.handle_contract_send_channelupdate = patched_update # and now app1 comes back online app1.raiden.start() # test for https://github.com/raiden-network/raiden/issues/3216 assert count == 1, 'Update transfer should have only been called once during restart' channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier # and we wait for settlement wait_for_settle( raiden=app0.raiden, payment_network_id=payment_network_identifier, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) with gevent.Timeout(10): unlock_app0 = wait_for_state_change( app0.raiden, ContractReceiveChannelBatchUnlock, {'participant': app0.raiden.address}, retry_timeout, ) assert unlock_app0.returned_tokens == 50 with gevent.Timeout(10): unlock_app1 = wait_for_state_change( app1.raiden, ContractReceiveChannelBatchUnlock, {'participant': app1.raiden.address}, retry_timeout, ) assert unlock_app1.returned_tokens == 50 final_balance0 = token_proxy.balance_of(app0.raiden.address) final_balance1 = token_proxy.balance_of(app1.raiden.address) assert final_balance0 - deposit - initial_balance0 == -1 assert final_balance1 - deposit - initial_balance1 == 1