def test_funds_check_for_openchannel(raiden_network, token_addresses): """Reproduces issue 2923 -- two open channel racing through the gas reserve""" app0, app1, app2 = raiden_network token_address = token_addresses[0] gas = get_required_gas_estimate(raiden=app0.raiden, channels_to_open=1) gas = round(gas * GAS_RESERVE_ESTIMATE_SECURITY_FACTOR) api0 = RaidenAPI(app0.raiden) burn_eth( raiden_service=app0.raiden, amount_to_leave=gas, ) partners = [app1.raiden.address, app2.raiden.address] greenlets = [ gevent.spawn( api0.channel_open, app0.raiden.default_registry.address, token_address, partner, ) for partner in partners ] # Opening two channels needs to fail, because the gas reserve is not big enough # This didn't fail prior to #2977, which serializes calls to channel open, # so that the gas reserve checks cannot pass in parallel with pytest.raises(InsufficientGasReserve): gevent.joinall(greenlets, raise_error=True)
def test_register_token_insufficient_eth(raiden_network, token_amount, contract_manager): app1 = raiden_network[0] registry_address = app1.raiden.default_registry.address token_address = deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.chain.client, contract_manager=contract_manager, constructor_arguments=( token_amount, 2, 'raiden', 'Rd', ), ) api1 = RaidenAPI(app1.raiden) assert token_address not in api1.get_tokens_list(registry_address) # app1.raiden loses all its ETH because it has been naughty burn_eth(app1.raiden) # At this point we should get an UnrecoverableError due to InsufficientFunds with pytest.raises(InsufficientFunds): api1.token_network_register(registry_address, token_address)
def test_api_testnet_token_mint(api_server_test_instance: APIServer, token_addresses): user_address = factories.make_checksum_address() token_address = token_addresses[0] url = api_url_for(api_server_test_instance, "tokensmintresource", token_address=token_address) request = grequests.post(url, json=dict(to=user_address, value=1)) response = request.send().response assert_response_with_code(response, HTTPStatus.OK) # mint method defaults to mintFor request = grequests.post(url, json=dict(to=user_address, value=10)) response = request.send().response assert_response_with_code(response, HTTPStatus.OK) # invalid due to negative value request = grequests.post(url, json=dict(to=user_address, value=-1)) response = request.send().response assert_response_with_error(response, HTTPStatus.BAD_REQUEST) # invalid due to invalid address request = grequests.post(url, json=dict(to=user_address[:-2], value=10)) response = request.send().response assert_response_with_error(response, HTTPStatus.BAD_REQUEST) # trying to mint with no ETH burn_eth(api_server_test_instance.rest_api.raiden_api.raiden.rpc_client) request = grequests.post(url, json=dict(to=user_address, value=1)) response = request.send().response assert_response_with_code(response, HTTPStatus.PAYMENT_REQUIRED)
def test_register_token_insufficient_eth(raiden_network, retry_timeout, unregistered_token): app1 = raiden_network[0] registry_address = app1.raiden.default_registry.address token_address = unregistered_token # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app1.raiden, block_number=app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1, retry_timeout=retry_timeout, ) api1 = RaidenAPI(app1.raiden) assert token_address not in api1.get_tokens_list(registry_address) # app1.raiden loses all its ETH because it has been naughty burn_eth(app1.raiden.rpc_client) with pytest.raises(InsufficientEth): api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=TokenAmount(UINT256_MAX), token_network_deposit_limit=TokenAmount(UINT256_MAX), )
def test_matrix_tx_error_handling( # pylint: disable=unused-argument raiden_chain: List[App], token_addresses, request ): """Proxies exceptions must be forwarded by the transport.""" if request.config.option.usepdb: pytest.skip("test fails with pdb") app0, app1 = raiden_chain token_address = token_addresses[0] 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, ) burn_eth(app0.raiden.rpc_client) def make_tx(*args, **kwargs): # pylint: disable=unused-argument close_channel = ActionChannelClose(canonical_identifier=channel_state.canonical_identifier) app0.raiden.handle_and_track_state_changes([close_channel]) app0.raiden.transport._client.add_presence_listener(make_tx) exception = ValueError("Exception was not raised from the transport") with pytest.raises(InsufficientEth), gevent.Timeout(10, exception=exception): # Change presence in peer app to trigger callback in app0 app1.raiden.transport._client.set_presence_state(UserPresence.UNAVAILABLE.value) app0.raiden.greenlet.get()
def test_matrix_tx_error_handling( # pylint: disable=unused-argument skip_if_not_matrix, raiden_chain, token_addresses): """Proxies exceptions must be forwarded by the transport.""" app0, app1 = raiden_chain token_address = token_addresses[0] channel_state = views.get_channelstate_for( chain_state=views.state_from_app(app0), payment_network_id=app0.raiden.default_registry.address, token_address=token_address, partner_address=app1.raiden.address, ) burn_eth(app0.raiden) def make_tx(*args, **kwargs): # pylint: disable=unused-argument close_channel = ActionChannelClose( canonical_identifier=channel_state.canonical_identifier) app0.raiden.handle_and_track_state_change(close_channel) app0.raiden.transport._client.add_presence_listener(make_tx) exception = ValueError("exception was not raised from the transport") with pytest.raises(InsufficientFunds), gevent.Timeout(200, exception=exception): app0.raiden.get()
def test_register_token_without_balance( api_server_test_instance, token_amount, raiden_network: List[RaidenService], contract_manager, retry_timeout, ): app0 = raiden_network[0] contract_proxy, _ = app0.rpc_client.deploy_single_contract( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, contract=contract_manager.get_contract(CONTRACT_HUMAN_STANDARD_TOKEN), constructor_parameters=(token_amount, 2, "raiden", "Rd2"), ) new_token_address = Address(to_canonical_address(contract_proxy.address)) # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. wait_for_block( raiden=app0, block_number=BlockNumber(app0.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1), retry_timeout=retry_timeout, ) # Burn all the eth and then make sure we get the appropriate API error burn_eth(app0.rpc_client) poor_request = grequests.put( api_url_for( api_server_test_instance, "registertokenresource", token_address=to_checksum_address(new_token_address), )) poor_response = poor_request.send().response assert_response_with_error(poor_response, HTTPStatus.PAYMENT_REQUIRED)
def test_handle_insufficient_eth(raiden_network, token_addresses, caplog): app0, app1 = raiden_network token = token_addresses[0] registry_address = app0.raiden.default_registry.address channel_state = views.get_channelstate_for( chain_state=views.state_from_raiden(app0.raiden), token_network_registry_address=registry_address, token_address=token, partner_address=app1.raiden.address, ) assert isinstance(channel_state, NettingChannelState) channel_identifier = channel_state.identifier transfer( initiator_app=app0, target_app=app1, amount=PaymentAmount(1), token_address=token, identifier=PaymentID(1), timeout=60, ) app1.raiden.stop() burn_eth(app1.raiden.rpc_client) app1.raiden.start() settle_block_timeout = BlockTimeout( exception_to_throw=RuntimeError("Settle did not happen."), raiden=app0.raiden, block_number=app0.raiden.get_block_number() + channel_state.settle_timeout * 2, retry_timeout=DEFAULT_RETRY_TIMEOUT, ) with settle_block_timeout: RaidenAPI(app0.raiden).channel_close( registry_address=registry_address, token_address=token, partner_address=app1.raiden.address, ) waiting.wait_for_settle( raiden=app0.raiden, token_network_registry_address=registry_address, token_address=token, channel_ids=[channel_identifier], retry_timeout=DEFAULT_RETRY_TIMEOUT, ) assert any( "subtask died" in message and "insufficient ETH" in message for message in caplog.messages )
def test_transact_fails_if_the_account_does_not_have_enough_eth_to_pay_for_the_gas( deploy_client: JSONRPCClient, ) -> None: """ The gas estimation does not fail if the transaction execution requires more gas then the account's eth balance. However sending the transaction will. """ contract_proxy, _ = deploy_rpc_test_contract(deploy_client, "RpcTest") estimated_transaction = deploy_client.estimate_gas(contract_proxy, "loop", {}, 1000) assert estimated_transaction, "The gas estimation should not have failed." burn_eth(deploy_client, amount_to_leave=estimated_transaction.estimated_gas // 2) with pytest.raises(InsufficientEth): deploy_client.transact(estimated_transaction)
def test_transact_fails_if_the_account_does_not_have_enough_eth_to_pay_for_the_gas( deploy_client: JSONRPCClient) -> None: """ The gas estimation does not fail if the transaction execution requires more gas then the account's eth balance. However sending the transaction will. """ contract_proxy, _ = deploy_rpc_test_contract(deploy_client, "RpcTest") check_block = deploy_client.get_checking_block() startgas = contract_proxy.estimate_gas(check_block, "loop", 1000) assert startgas, "The gas estimation should not have failed." burn_eth(deploy_client, amount_to_leave=startgas // 2) with pytest.raises(InsufficientEth): contract_proxy.transact("loop", startgas, 1000)
def test_handle_insufficient_eth( raiden_network: List[RaidenService], restart_node, token_addresses, caplog ): app0, app1 = raiden_network token = token_addresses[0] registry_address = app0.default_registry.address channel_state = views.get_channelstate_for( chain_state=views.state_from_raiden(app0), token_network_registry_address=registry_address, token_address=token, partner_address=app1.address, ) assert isinstance(channel_state, NettingChannelState) channel_identifier = channel_state.identifier with block_offset_timeout(app0): transfer( initiator_app=app0, target_app=app1, token_address=token, amount=PaymentAmount(1), identifier=PaymentID(1), ) app1.stop() burn_eth(app1.rpc_client) restart_node(app1) block_offset = BlockOffset(channel_state.settle_timeout * 2) with block_offset_timeout(app0, "Settle did not happen", block_offset): RaidenAPI(app0).channel_close( registry_address=registry_address, token_address=token, partner_address=app1.address, ) waiting.wait_for_settle( raiden=app0, token_network_registry_address=registry_address, token_address=token, channel_ids=[channel_identifier], retry_timeout=DEFAULT_RETRY_TIMEOUT, ) assert any( "subtask died" in message and "insufficient ETH" in message for message in caplog.messages )
def test_api_channel_close_insufficient_eth( api_server_test_instance: APIServer, token_addresses, reveal_timeout): # let's create a new channel partner_address = "0x61C808D82A3Ac53231750daDc13c777b59310bD9" token_address = token_addresses[0] settle_timeout = 1650 channel_data_obj = { "partner_address": partner_address, "token_address": to_checksum_address(token_address), "settle_timeout": str(settle_timeout), } request = grequests.put(api_url_for(api_server_test_instance, "channelsresource"), json=channel_data_obj) response = request.send().response balance = 0 assert_proper_response(response, status_code=HTTPStatus.CREATED) channel_identifier = 1 json_response = get_json_response(response) expected_response = channel_data_obj.copy() expected_response.update({ "balance": str(balance), "state": ChannelState.STATE_OPENED.value, "reveal_timeout": str(reveal_timeout), "channel_identifier": str(channel_identifier), "total_deposit": "0", }) assert check_dict_nested_attrs(json_response, expected_response) # let's burn all eth and try to close the channel burn_eth(api_server_test_instance.rest_api.raiden_api.raiden.rpc_client) request = grequests.patch( api_url_for( api_server_test_instance, "channelsresourcebytokenandpartneraddress", token_address=token_address, partner_address=partner_address, ), json={"state": ChannelState.STATE_CLOSED.value}, ) response = request.send().response assert_proper_response(response, HTTPStatus.PAYMENT_REQUIRED) json_response = get_json_response(response) assert "insufficient ETH" in json_response["errors"]
def test_connect_insufficient_reserve(api_server_test_instance: APIServer, token_addresses): # Burn all eth and then try to connect to a token network burn_eth(api_server_test_instance.rest_api.raiden_api.raiden.rpc_client) funds = 100 token_address1 = to_checksum_address(token_addresses[0]) connect_data_obj = {"funds": funds} request = grequests.put( api_url_for(api_server_test_instance, "connectionsresource", token_address=token_address1), json=connect_data_obj, ) response = request.send().response assert_proper_response(response, HTTPStatus.PAYMENT_REQUIRED) json_response = get_json_response(response) assert "The account balance is below the estimated amount" in json_response[ "errors"]
def test_register_token_insufficient_eth( raiden_network, token_amount, contract_manager, retry_timeout ): app1 = raiden_network[0] registry_address = app1.raiden.default_registry.address token_address = deploy_contract_web3( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, deploy_client=app1.raiden.rpc_client, contract_manager=contract_manager, constructor_arguments=(token_amount, 2, "raiden", "Rd"), ) # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. waiting.wait_for_block( raiden=app1.raiden, block_number=app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1, retry_timeout=retry_timeout, ) api1 = RaidenAPI(app1.raiden) assert token_address not in api1.get_tokens_list(registry_address) # app1.raiden loses all its ETH because it has been naughty burn_eth(app1.raiden.rpc_client) # At this point we should get an UnrecoverableError due to InsufficientFunds with pytest.raises(InsufficientFunds): api1.token_network_register( registry_address=registry_address, token_address=token_address, channel_participant_deposit_limit=UINT256_MAX, token_network_deposit_limit=UINT256_MAX, )
def test_api_channel_open_and_deposit(api_server_test_instance: APIServer, token_addresses, reveal_timeout): first_partner_address = "0x61C808D82A3Ac53231750daDc13c777b59310bD9" token_address = token_addresses[0] token_address_hex = to_checksum_address(token_address) settle_timeout = 1650 channel_data_obj = { "partner_address": first_partner_address, "token_address": token_address_hex, "settle_timeout": str(settle_timeout), "reveal_timeout": str(reveal_timeout), } # First let's try to create channel with the null address and see error is handled channel_data_obj["partner_address"] = NULL_ADDRESS_HEX request = grequests.put(api_url_for(api_server_test_instance, "channelsresource"), json=channel_data_obj) response = request.send().response assert_response_with_error(response, status_code=HTTPStatus.BAD_REQUEST) # now let's really create a new channel channel_data_obj["partner_address"] = first_partner_address request = grequests.put(api_url_for(api_server_test_instance, "channelsresource"), json=channel_data_obj) response = request.send().response assert_proper_response(response, HTTPStatus.CREATED) first_channel_id = 1 json_response = get_json_response(response) expected_response = channel_data_obj.copy() expected_response.update({ "balance": "0", "state": ChannelState.STATE_OPENED.value, "channel_identifier": "1", "total_deposit": "0", }) assert check_dict_nested_attrs(json_response, expected_response) token_network_address = json_response["token_network_address"] # Now let's try to open the same channel again, because it is possible for # the participants to race on the channel creation, this is not considered # an error. request = grequests.put(api_url_for(api_server_test_instance, "channelsresource"), json=channel_data_obj) response = request.send().response assert_proper_response(response, HTTPStatus.OK) json_response = get_json_response(response) assert check_dict_nested_attrs(json_response, expected_response) # now let's open a channel and make a deposit too second_partner_address = "0x29FA6cf0Cce24582a9B20DB94Be4B6E017896038" total_deposit = 100 channel_data_obj = { "partner_address": second_partner_address, "token_address": to_checksum_address(token_address), "settle_timeout": str(settle_timeout), "reveal_timeout": str(reveal_timeout), "total_deposit": str(total_deposit), } request = grequests.put(api_url_for(api_server_test_instance, "channelsresource"), json=channel_data_obj) response = request.send().response assert_proper_response(response, HTTPStatus.CREATED) second_channel_id = 2 json_response = get_json_response(response) expected_response = channel_data_obj.copy() expected_response.update({ "balance": str(total_deposit), "state": ChannelState.STATE_OPENED.value, "channel_identifier": str(second_channel_id), "token_network_address": token_network_address, "total_deposit": str(total_deposit), }) assert check_dict_nested_attrs(json_response, expected_response) # assert depositing again with less than the initial deposit returns 409 request = grequests.patch( api_url_for( api_server_test_instance, "channelsresourcebytokenandpartneraddress", token_address=token_address, partner_address=second_partner_address, ), json={"total_deposit": "99"}, ) response = request.send().response assert_proper_response(response, HTTPStatus.CONFLICT) # assert depositing negative amount fails request = grequests.patch( api_url_for( api_server_test_instance, "channelsresourcebytokenandpartneraddress", token_address=token_address, partner_address=first_partner_address, ), json={"total_deposit": "-1000"}, ) response = request.send().response assert_proper_response(response, HTTPStatus.CONFLICT) # let's deposit on the first channel request = grequests.patch( api_url_for( api_server_test_instance, "channelsresourcebytokenandpartneraddress", token_address=token_address, partner_address=first_partner_address, ), json={"total_deposit": str(total_deposit)}, ) response = request.send().response assert_proper_response(response) json_response = get_json_response(response) expected_response = { "channel_identifier": str(first_channel_id), "partner_address": first_partner_address, "token_address": to_checksum_address(token_address), "settle_timeout": str(settle_timeout), "reveal_timeout": str(reveal_timeout), "state": ChannelState.STATE_OPENED.value, "balance": str(total_deposit), "total_deposit": str(total_deposit), "token_network_address": token_network_address, } assert check_dict_nested_attrs(json_response, expected_response) # let's try querying for the second channel request = grequests.get( api_url_for( api_server_test_instance, "channelsresourcebytokenandpartneraddress", token_address=token_address, partner_address=second_partner_address, )) response = request.send().response assert_proper_response(response) json_response = get_json_response(response) expected_response = { "channel_identifier": str(second_channel_id), "partner_address": second_partner_address, "token_address": to_checksum_address(token_address), "settle_timeout": str(settle_timeout), "reveal_timeout": str(reveal_timeout), "state": ChannelState.STATE_OPENED.value, "balance": str(total_deposit), "total_deposit": str(total_deposit), "token_network_address": token_network_address, } assert check_dict_nested_attrs(json_response, expected_response) # finally let's burn all eth and try to open another channel burn_eth(api_server_test_instance.rest_api.raiden_api.raiden.rpc_client) channel_data_obj = { "partner_address": "0xf3AF96F89b3d7CdcBE0C083690A28185Feb0b3CE", "token_address": to_checksum_address(token_address), "settle_timeout": str(settle_timeout), "reveal_timeout": str(reveal_timeout), } request = grequests.put(api_url_for(api_server_test_instance, "channelsresource"), json=channel_data_obj) response = request.send().response assert_proper_response(response, HTTPStatus.PAYMENT_REQUIRED) json_response = get_json_response(response) assert "The account balance is below the estimated amount" in json_response[ "errors"]