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 channel_batch_close( self, registry_address, token_address, partner_addresses, poll_timeout=DEFAULT_POLL_TIMEOUT, retry_timeout=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) msg = 'After {} seconds the closing transactions were not properly processed.'.format( poll_timeout, ) channel_ids = [ channel_state.identifier for channel_state in channels_to_close ] with gevent.Timeout(poll_timeout, EthNodeCommunicationError(msg)): waiting.wait_for_close( self.raiden, registry_address, token_address, channel_ids, retry_timeout, )
def channel_batch_close( self, registry_address, token_address, partner_addresses, poll_timeout=DEFAULT_POLL_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 isaddress(token_address): raise InvalidAddress( 'Expected binary address format for token in channel close') if not all(map(isaddress, 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.') node_state = views.state_from_raiden(self.raiden) channels_to_close = views.filter_channels_by_partneraddress( node_state, registry_address, token_address, partner_addresses, ) # 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.netting_channel( channel_state.identifier) # Check if we can acquire the lock. If we can't raise an exception, which # will cause the ExitStack to exit, releasing all locks acquired so far if not channel.channel_operations_lock.acquire(blocking=False): raise ChannelBusyError( f'Channel with id {channel_state.identifier} is ' f'busy with another ongoing operation.') stack.push(channel.channel_operations_lock) for channel_state in channels_to_close: channel_close = ActionChannelClose( registry_address, token_address, channel_state.identifier, ) self.raiden.handle_state_change(channel_close) msg = 'After {} seconds the deposit was not properly processed.'.format( poll_timeout) channel_ids = [ channel_state.identifier for channel_state in channels_to_close ] with gevent.Timeout(poll_timeout, EthNodeCommunicationError(msg)): waiting.wait_for_close( self.raiden, registry_address, token_address, channel_ids, self.raiden.alarm.wait_time, )
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, ) # 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_address=token_network_identifier, channel_id=channel_state.identifier, ) stack.enter_context(channel.lock_or_raise()) 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_clear_closed_queue(raiden_network: List[App], token_addresses, network_wait): """ Closing a channel clears the respective message queue. """ app0, app1 = raiden_network hold_event_handler = app1.raiden.raiden_event_handler assert isinstance(hold_event_handler, HoldRaidenEventHandler) registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] chain_state0 = views.state_from_app(app0) token_network_address = views.get_token_network_address_by_token_address( chain_state0, app0.raiden.default_registry.address, token_address) assert token_network_address token_network = views.get_token_network_by_address(chain_state0, token_network_address) assert token_network channel_identifier = get_channelstate(app0, app1, token_network_address).identifier assert (channel_identifier in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address]) target = app1.raiden.address secret = Secret(sha3(target)) secrethash = sha256_secrethash(secret) hold_event_handler.hold_secretrequest_for(secrethash=secrethash) # make an unconfirmed transfer to ensure the nodes have communicated amount = PaymentAmount(10) payment_identifier = PaymentID(1337) app0.raiden.start_mediated_transfer_with_secret( token_network_address=token_network_address, amount=amount, target=TargetAddress(target), identifier=payment_identifier, secret=secret, ) app1.raiden.transport.stop() app1.raiden.transport.greenlet.get() # make sure to wait until the queue is created def has_initiator_events(): assert app0.raiden.wal, "raiden server must have been started" initiator_events = app0.raiden.wal.storage.get_events() return search_for_item(initiator_events, SendLockedTransfer, {}) assert wait_until(has_initiator_events, network_wait) # assert the specific queue is present chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue_id. canonical_identifier.channel_identifier == channel_identifier and queue ] # A ChannelClose event will be generated, this will be polled by both apps RaidenAPI(app0.raiden).channel_close(registry_address, token_address, app1.raiden.address) exception = ValueError("Could not get close event") with gevent.Timeout(seconds=30, exception=exception): waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) # assert all queues with this partner are gone or empty chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert not [(queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue] chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) assert not [(queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue]
def test_node_can_settle_if_partner_does_not_call_update_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, chain_id, ): """ A node must be able to settle a channel, even if the partner did not call update transfer. This test will: - Make a transfer from app0 to app1, to make sure there are balance proofs available - Stop app1, to make sure update is not called. - Use app0 to close the channel. - Assert that app0 can settle the closed channel, even though app1 didn't use the latest balance proof """ 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=1, timeout=network_wait * number_of_nodes, ) # stop app1 - the test uses token_network_contract now app1.stop() RaidenAPI(app0.raiden).channel_close( registry_address=registry_address, token_address=token_address, partner_address=app1.raiden.address, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) # app1 won't update the channel 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_batch_unlock_after_restart(raiden_network, token_addresses, deposit): """Simulate the case where: - A sends B a transfer - B sends A a transfer - Secrets were never revealed - B closes channel - A crashes - Wait for settle - Wait for unlock from B - Restart A At this point, the current unlock logic will try to unlock iff the node gains from unlocking. Which means that the node will try to unlock either side. In the above scenario, each node will unlock its side. This test makes sure that we do NOT invalidate A's unlock transaction based on the ContractReceiveChannelBatchUnlock caused by B's unlock. """ alice_app, bob_app = raiden_network registry_address = alice_app.raiden.default_registry.address token_address = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( chain_state=views.state_from_app(alice_app), token_network_registry_address=alice_app.raiden.default_registry. address, token_address=token_address, ) assert token_network_address timeout = 10 token_network = views.get_token_network_by_address( chain_state=views.state_from_app(alice_app), token_network_address=token_network_address) assert token_network channel_identifier = get_channelstate(alice_app, bob_app, token_network_address).identifier assert (channel_identifier in token_network.partneraddresses_to_channelidentifiers[ bob_app.raiden.address]) alice_to_bob_amount = 10 identifier = 1 alice_transfer_secret = Secret(sha3(alice_app.raiden.address)) alice_transfer_secrethash = sha256_secrethash(alice_transfer_secret) bob_transfer_secret = Secret(sha3(bob_app.raiden.address)) bob_transfer_secrethash = sha256_secrethash(bob_transfer_secret) alice_transfer_hold = bob_app.raiden.raiden_event_handler.hold_secretrequest_for( secrethash=alice_transfer_secrethash) bob_transfer_hold = alice_app.raiden.raiden_event_handler.hold_secretrequest_for( secrethash=bob_transfer_secrethash) alice_app.raiden.start_mediated_transfer_with_secret( token_network_address=token_network_address, amount=alice_to_bob_amount, target=bob_app.raiden.address, identifier=identifier, secret=alice_transfer_secret, ) bob_app.raiden.start_mediated_transfer_with_secret( token_network_address=token_network_address, amount=alice_to_bob_amount, target=alice_app.raiden.address, identifier=identifier + 1, secret=bob_transfer_secret, ) alice_transfer_hold.wait(timeout=timeout) bob_transfer_hold.wait(timeout=timeout) alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address) alice_lock = channel.get_lock(alice_bob_channel_state.our_state, alice_transfer_secrethash) bob_lock = channel.get_lock(alice_bob_channel_state.partner_state, bob_transfer_secrethash) assert alice_lock assert bob_lock # This is the current state of protocol: # # A -> B LockedTransfer # - protocol didn't continue assert_synced_channel_state( token_network_address=token_network_address, app0=alice_app, balance0=deposit, pending_locks0=[alice_lock], app1=bob_app, balance1=deposit, pending_locks1=[bob_lock], ) # 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=registry_address, token_address=token_address, partner_address=alice_app.raiden.address, ) # wait for the close transaction to be mined, this is necessary to compute # the timeout for the settle with gevent.Timeout(timeout): waiting.wait_for_close( raiden=alice_app.raiden, token_network_registry_address=registry_address, token_address=token_address, channel_ids=[alice_bob_channel_state.identifier], retry_timeout=alice_app.raiden.alarm.sleep_time, ) channel_closed = raiden_state_changes_search_for_item( bob_app.raiden, ContractReceiveChannelClosed, { "canonical_identifier": { "token_network_address": token_network_address, "channel_identifier": alice_bob_channel_state.identifier, } }, ) assert isinstance(channel_closed, ContractReceiveChannelClosed) settle_max_wait_block = BlockNumber( channel_closed.block_number + alice_bob_channel_state.settle_timeout * 2) settle_timeout = BlockTimeout( RuntimeError("settle did not happen"), bob_app.raiden, settle_max_wait_block, alice_app.raiden.alarm.sleep_time, ) with settle_timeout: waiting.wait_for_settle( raiden=alice_app.raiden, token_network_registry_address=registry_address, token_address=token_address, channel_ids=[alice_bob_channel_state.identifier], retry_timeout=alice_app.raiden.alarm.sleep_time, ) with gevent.Timeout(timeout): wait_for_batch_unlock( app=bob_app, token_network_address=token_network_address, receiver=alice_bob_channel_state.partner_state.address, sender=alice_bob_channel_state.our_state.address, ) alice_app.start() with gevent.Timeout(timeout): wait_for_batch_unlock( app=alice_app, token_network_address=token_network_address, receiver=alice_bob_channel_state.partner_state.address, sender=alice_bob_channel_state.our_state.address, )
def run_test_clear_closed_queue(raiden_network, token_addresses, network_wait): app0, app1 = raiden_network hold_event_handler = HoldOffChainSecretRequest() app1.raiden.raiden_event_handler = hold_event_handler registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] chain_state0 = views.state_from_app(app0) token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state0, app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( chain_state0, token_network_identifier, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address] target = app1.raiden.address secret = sha3(target) secrethash = sha3(secret) hold_event_handler.hold_secretrequest_for(secrethash=secrethash) # make an unconfirmed transfer to ensure the nodes have communicated amount = 10 payment_identifier = 1337 app0.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=amount, fee=0, target=target, identifier=payment_identifier, secret=secret, ) app1.raiden.transport.stop() app1.raiden.transport.get() # make sure to wait until the queue is created def has_initiator_events(): initiator_events = app0.raiden.wal.storage.get_events() return search_for_item(initiator_events, SendLockedTransfer, {}) assert wait_until(has_initiator_events, network_wait) # assert the specific queue is present chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert [(queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue_id.channel_identifier == channel_identifier and queue] # A ChannelClose event will be generated, this will be polled by both apps RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) exception = ValueError('Could not get close event') with gevent.Timeout(seconds=30, exception=exception): waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) # assert all queues with this partner are gone or empty chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert not [(queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue] chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) assert not [(queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue]
def test_node_can_settle_if_close_didnt_use_any_balance_proof( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, ): """ A node must be able to settle a channel, even if the partner used an old balance proof to close it. This test will: - Make a transfer from app0 to app1, to make sure there are balance proofs available - Call close manually in behalf of app1, without any balance proof data - Assert that app0 can settle the closed channel, even though app1 didn't use the latest balance proof """ 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=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, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) 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 channel_batch_close( self, registry_address, token_address, partner_addresses, poll_timeout=DEFAULT_POLL_TIMEOUT, retry_timeout=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) msg = 'After {} seconds the closing transactions were not properly processed.'.format( poll_timeout, ) channel_ids = [channel_state.identifier for channel_state in channels_to_close] with gevent.Timeout(poll_timeout, EthNodeCommunicationError(msg)): waiting.wait_for_close( self.raiden, registry_address, token_address, channel_ids, retry_timeout, )
def test_node_can_settle_if_partner_does_not_call_update_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, chain_id, ): """ A node must be able to settle a channel, even if the partner did not call update transfer. This test will: - Make a transfer from app0 to app1, to make sure there are balance proofs available - Stop app1, to make sure update is not called. - Use app0 to close the channel. - Assert that app0 can settle the closed channel, even though app1 didn't use the latest balance proof """ 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=1, timeout=network_wait * number_of_nodes, ) # stop app1 - the test uses token_network_contract now app1.stop() RaidenAPI(app0.raiden).channel_close( registry_address=registry_address, token_address=token_address, partner_address=app1.raiden.address, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) # app1 won't update the channel 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_clear_closed_queue(raiden_network, token_addresses, deposit): """ Closing a channel clears the respective message queue. """ app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] chain_state0 = views.state_from_app(app0) token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state0, app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( chain_state0, 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 ] app1.raiden.transport.stop() app1.raiden.transport.get() # make a direct transfer to ensure the nodes have communicated amount = 10 payment_identifier = 1337 app0.raiden.direct_transfer_async( token_network_identifier, amount, app1.raiden.address, identifier=payment_identifier, ) # assert the specific queue is present chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue_id.channel_identifier == channel_identifier and queue ] # A ChannelClose event will be generated, this will be polled by both apps RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) exception = ValueError('Could not get close event') with gevent.Timeout(seconds=30, exception=exception): waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) # assert all queues with this partner are gone or empty chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert not [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue ] chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) assert not [ (queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue ]
def test_node_can_settle_if_close_didnt_use_any_balance_proof( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, ): """ A node must be able to settle a channel, even if the partner used an old balance proof to close it. This test will: - Make a transfer from app0 to app1, to make sure there are balance proofs available - Call close manually in behalf of app1, without any balance proof data - Assert that app0 can settle the closed channel, even though app1 didn't use the latest balance proof """ 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=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, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_node_clears_pending_withdraw_transaction_after_channel_is_closed( raiden_network, token_addresses, network_wait, number_of_nodes, retry_timeout ): """ A test case related to https://github.com/raiden-network/raiden/issues/4639 Where a node sends a withdraw transaction, is stopped before the transaction is completed. Meanwhile, the partner node closes the channel so when the stopped node is back up, it tries to execute the pending withdraw transaction and fails because the channel was closed. Expected behaviour: Channel closed state change should cancel a withdraw transaction. Buggy behaviour: The channel closure isn't detected on recovery and the on-chain transaction fails. """ app0, app1 = raiden_network token_address = token_addresses[0] # Prevent the withdraw transaction from being sent on-chain. This # will keep the transaction in the pending list send_channel_withdraw_event = app0.raiden.raiden_event_handler.hold( ContractSendChannelWithdraw, {} ) channel_state = views.get_channelstate_for( chain_state=views.state_from_app(app0), token_network_registry_address=app0.raiden.default_registry.address, token_address=token_address, partner_address=app1.raiden.address, ) assert channel_state, "Channel does not exist" app0.raiden.withdraw(canonical_identifier=channel_state.canonical_identifier, total_withdraw=1) timeout = network_wait * number_of_nodes with gevent.Timeout(seconds=timeout): send_channel_withdraw_event.wait() msg = "A withdraw transaction should be in the pending transactions list" chain_state = views.state_from_app(app0) assert search_for_item( item_list=chain_state.pending_transactions, item_type=ContractSendChannelWithdraw, attributes={"total_withdraw": 1}, ), msg app0.raiden.stop() app0.stop() app1_api = RaidenAPI(app1.raiden) app1_api.channel_close( registry_address=app0.raiden.default_registry.address, token_address=token_address, partner_address=app0.raiden.address, ) waiting.wait_for_close( raiden=app1.raiden, token_network_registry_address=app1.raiden.default_registry.address, token_address=token_address, channel_ids=[channel_state.identifier], retry_timeout=retry_timeout, ) app0.raiden.start() chain_state = views.state_from_app(app0) msg = "The withdraw transaction should have been invalidated on restart." assert ( search_for_item( item_list=chain_state.pending_transactions, item_type=ContractSendChannelWithdraw, attributes={"total_withdraw": 1}, ) is None ), msg
def test_invalid_close( raiden_network, number_of_nodes, 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 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=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, manager_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, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def run_test_settle_is_automatically_called(raiden_network, token_addresses): """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_channelidentifiers[ 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_channelidentifiers[ app1.raiden.address]) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier="latest") assert search_for_item( state_changes, ContractReceiveChannelClosed, { "token_network_identifier": token_network_identifier, "channel_identifier": channel_identifier, "transaction_from": app1.raiden.address, "block_number": channel_state.close_transaction.finished_block_number, }, ) assert search_for_item( state_changes, ContractReceiveChannelSettled, { "token_network_identifier": token_network_identifier, "channel_identifier": channel_identifier, }, )
def test_invalid_update_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, chain_id, ): 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 mediated_transfer( initiator_app=app0, target_app=app1, token_network_identifier=token_network_identifier, amount=1, timeout=network_wait * number_of_nodes, ) # stop app1 - the test uses token_network_contract now app1.stop() # close the channel RaidenAPI(app0.raiden).channel_close( registry_address=registry_address, token_address=token_address, partner_address=app1.raiden.address, ) waiting.wait_for_close( raiden=app0.raiden, payment_network_id=registry_address, token_address=token_address, channel_ids=[channel_identifier], retry_timeout=app0.raiden.alarm.sleep_time, ) # app1 won't update the channel # app0 waits for settle 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 must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, })
def test_clear_closed_queue(raiden_network, token_addresses, deposit, network_wait): """ Closing a channel clears the respective message queue. """ app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] chain_state0 = views.state_from_app(app0) token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state0, app0.raiden.default_registry.address, token_address, ) token_network = views.get_token_network_by_identifier( chain_state0, token_network_identifier, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[ app1.raiden.address ] with dont_handle_secret_request_mock(app0): # make an unconfirmed transfer to ensure the nodes have communicated amount = 10 payment_identifier = 1337 app0.raiden.mediated_transfer_async( token_network_identifier=token_network_identifier, amount=amount, target=app1.raiden.address, identifier=payment_identifier, ) app1.raiden.transport.stop() app1.raiden.transport.get() # make sure to wait until the queue is created def has_initiator_events(): initiator_events = app0.raiden.wal.storage.get_events() return must_contain_entry(initiator_events, SendLockedTransfer, {}) assert wait_until(has_initiator_events, network_wait) # assert the specific queue is present chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue_id.channel_identifier == channel_identifier and queue ] # A ChannelClose event will be generated, this will be polled by both apps RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) exception = ValueError('Could not get close event') with gevent.Timeout(seconds=30, exception=exception): waiting.wait_for_close( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) # assert all queues with this partner are gone or empty chain_state0 = views.state_from_app(app0) queues0 = views.get_all_messagequeues(chain_state=chain_state0) assert not [ (queue_id, queue) for queue_id, queue in queues0.items() if queue_id.recipient == app1.raiden.address and queue ] chain_state1 = views.state_from_app(app1) queues1 = views.get_all_messagequeues(chain_state=chain_state1) assert not [ (queue_id, queue) for queue_id, queue in queues1.items() if queue_id.recipient == app0.raiden.address and queue ]
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_identifiers( 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, ) greenlets: typing.List[Greenlet] = list() for channel_state in channels_to_close: channel_close = ActionChannelClose( token_network_identifier=token_network_identifier, channel_identifier=channel_state.identifier, ) greenlets.extend(self.raiden.handle_state_change(channel_close), ) gevent.joinall(greenlets, raise_error=True) 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_settle_is_automatically_called(raiden_network, token_addresses): """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_channelidentifiers[ 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_channelidentifiers[ 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, '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_settle_is_automatically_called( raiden_network: List[App], token_addresses: List[TokenAddress] ) -> None: """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_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address ) assert token_network_address token_network = views.get_token_network_by_address( views.state_from_app(app0), token_network_address ) assert token_network channel_identifier = get_channelstate(app0, app1, token_network_address).identifier assert ( channel_identifier in token_network.partneraddresses_to_channelidentifiers[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 assert channel_state.close_transaction 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_address( views.state_from_app(app0), token_network_address ) assert token_network assert ( channel_identifier not in token_network.partneraddresses_to_channelidentifiers[app1.raiden.address] ) assert app0.raiden.wal, MSG_BLOCKCHAIN_EVENTS assert app0.raiden.alarm, MSG_BLOCKCHAIN_EVENTS state_changes = app0.raiden.wal.storage.get_statechanges_by_range(RANGE_ALL_STATE_CHANGES) assert search_for_item( state_changes, ContractReceiveChannelClosed, { "token_network_address": token_network_address, "channel_identifier": channel_identifier, "transaction_from": app1.raiden.address, "block_number": channel_state.close_transaction.finished_block_number, }, ) assert search_for_item( state_changes, ContractReceiveChannelSettled, {"token_network_address": token_network_address, "channel_identifier": channel_identifier}, )