Repository: rotki/rotki

Issue:
Calling endpoint /blockchains/eth with a valid body but no configured path to query the address will return an internal server error
## Problem Definition

Making a PUT call with a valid body to `/blockchains/eth` when the user does not have a valid etherscan API key (or ethereum node perhaps?) set up will cause the API to return an internal server error instead of the expected etherscan.io api key requirement message.

This does not appear to affect the rotki front-end application (perhaps because it uses an async call). Malformed bodies produce expected errors (e.g. invalid field, unexpected value, etc.).

**Steps to reproduce:**
* Ensure that the currently logged in user does not have an etherscan API key / ethereum node configured
* Make a valid HTTP PUT call to `http://127.0.0.1:5042/api/1/blockchains/eth`, you will get an internal server error message returned.


Relevant `rotkehlchen.log` output:
```
07/04/2020 17:44:25 W. Europe Daylight Time -- DEBUG:rotkehlchen.externalapis.cryptocompare:Querying cryptocompare url=https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD
07/04/2020 17:44:25 W. Europe Daylight Time -- DEBUG:rotkehlchen.inquirer:Got usd price from cryptocompare asset=Ethereum, price=170.17
07/04/2020 17:44:25 W. Europe Daylight Time -- ERROR:rotkehlchen.api.server:Exception on /api/1/blockchains/eth [PUT]
Traceback (most recent call last):
  File "C:\Users\Gebruiker\Envs\rotkehlchen\lib\site-packages\flask\app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\Gebruiker\Envs\rotkehlchen\lib\site-packages\flask\app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Users\Gebruiker\Envs\rotkehlchen\lib\site-packages\flask_restful\__init__.py", line 458, in wrapper
    resp = resource(*args, **kwargs)
  File "C:\Users\Gebruiker\Envs\rotkehlchen\lib\site-packages\flask\views.py", line 89, in view
    return self.dispatch_request(*args, **kwargs)
  File "C:\Users\Gebruiker\Envs\rotkehlchen\lib\site-packages\flask_restful\__init__.py", line 573, in dispatch_request
    resp = meth(*args, **kwargs)
  File "C:\Users\Gebruiker\Envs\rotkehlchen\lib\site-packages\webargs\core.py", line 366, in wrapper
    return func(*args, **kwargs)
  File "C:\Users\Gebruiker\Source\Repos\rotki\rotkehlchen\api\v1\resources.py", line 630, in put
    async_query=async_query,
  File "C:\Users\Gebruiker\Source\Repos\rotki\rotkehlchen\api\rest.py", line 101, in wrapper
    return f(wrappingobj, *args, **kwargs)
  File "C:\Users\Gebruiker\Source\Repos\rotki\rotkehlchen\api\rest.py", line 1151, in add_blockchain_accounts
    return api_response(wrap_in_fail_result(msg), status_code=response['status_code'])
KeyError: 'status_code'
07/04/2020 17:44:25 W. Europe Daylight Time -- INFO:rotkehlchen.api.server.pywsgi:127.0.0.1 - - [2020-04-07 17:44:25] "PUT /api/1/blockchains/eth HTTP/1.1" 500 164 0.021062
```
### System Description

```
System: Windows 10 64-bit
Rotkehlchen version: 1.3.1 (develop)
```



Discussion:

Resolving patch:
diff --git a/rotkehlchen/api/rest.py b/rotkehlchen/api/rest.py
--- a/rotkehlchen/api/rest.py
+++ b/rotkehlchen/api/rest.py
@@ -1141,7 +1141,7 @@ def _add_blockchain_accounts(
         except TagConstraintError as e:
             return {'result': None, 'message': str(e), 'status_code': HTTPStatus.CONFLICT}
         except RemoteError as e:
-            return {'result': None, 'message': str(e), 'status_code:': HTTPStatus.BAD_GATEWAY}
+            return {'result': None, 'message': str(e), 'status_code': HTTPStatus.BAD_GATEWAY}
 
         # success
         return {'result': result.serialize(), 'message': ''}
@@ -1211,7 +1211,7 @@ def _remove_blockchain_accounts(
         except InputError as e:
             return {'result': None, 'message': str(e), 'status_code': HTTPStatus.BAD_REQUEST}
         except RemoteError as e:
-            return {'result': None, 'message': str(e), 'status_code:': HTTPStatus.BAD_GATEWAY}
+            return {'result': None, 'message': str(e), 'status_code': HTTPStatus.BAD_GATEWAY}
 
         return {'result': result.serialize(), 'message': ''}
 


Test patch:
diff --git a/rotkehlchen/tests/api/test_blockchain.py b/rotkehlchen/tests/api/test_blockchain.py
--- a/rotkehlchen/tests/api/test_blockchain.py
+++ b/rotkehlchen/tests/api/test_blockchain.py
@@ -540,6 +540,46 @@ def test_add_blockchain_accounts(
     )
 
 
+@pytest.mark.parametrize('include_etherscan_key', [False])
+def test_add_blockchain_accounts_synchronously_no_etherscan(rotkehlchen_api_server):
+    """Make sure that adding an ethereum blockchain account without etherscan key returns error
+
+    Regression test for https://github.com/rotki/rotki/issues/852
+    """
+    response = requests.put(api_url_for(
+        rotkehlchen_api_server,
+        "blockchainsaccountsresource",
+        blockchain='ETH',
+    ), json={'accounts': [{'address': make_ethereum_address()}]})
+    assert_error_response(
+        response=response,
+        contained_in_msg='Etherscan has introduced compulsory API keys.',
+        status_code=HTTPStatus.BAD_GATEWAY,
+    )
+
+
+@pytest.mark.parametrize('include_etherscan_key', [False])
+@pytest.mark.parametrize('number_of_eth_accounts', [2])
+def test_remove_blockchain_accounts_synchronously_no_etherscan(
+        rotkehlchen_api_server,
+        ethereum_accounts,
+):
+    """Make sure that removing an ethereum blockchain account without etherscan key returns error
+
+    Regression test for https://github.com/rotki/rotki/issues/852
+    """
+    response = requests.delete(api_url_for(
+        rotkehlchen_api_server,
+        "blockchainsaccountsresource",
+        blockchain='ETH',
+    ), json={'accounts': [ethereum_accounts[0]]})
+    assert_error_response(
+        response=response,
+        contained_in_msg='Etherscan has introduced compulsory API keys.',
+        status_code=HTTPStatus.BAD_GATEWAY,
+    )
+
+
 @pytest.mark.parametrize('number_of_eth_accounts', [2])
 @pytest.mark.parametrize('btc_accounts', [[UNIT_BTC_ADDRESS1, UNIT_BTC_ADDRESS2]])
 @pytest.mark.parametrize('owned_eth_tokens', [[A_RDN]])