Repository: rotki/rotki

Issue:
After user re-login the backend throws exceptions
## Problem Definition

First noticed by @kelsos [here](https://github.com/rotkehlchenio/rotkehlchen/pull/270#issuecomment-464488862) this seems to be reproducible also locally.

The two errors are: `Failed to acquire fiat to USD exchange rates: 'NoneType' object has no attribute 'get_fiat_usd_exchange_rates'` and `AttributeError: 'NoneType' object has no attribute 'query_fiat_pair'` It seems that after logging the user in again the `Inquirer` object is `None` for some reason.

## Task

Investigate and fix.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/data_handler.py b/rotkehlchen/data_handler.py
--- a/rotkehlchen/data_handler.py
+++ b/rotkehlchen/data_handler.py
@@ -297,15 +297,22 @@ def get_eth_accounts(self) -> List[typing.EthAddress]:
         blockchain_accounts = self.db.get_blockchain_accounts()
         return blockchain_accounts.eth
 
-    def set_fiat_balance(self, currency: typing.FiatAsset, balance: FVal) -> Tuple[bool, str]:
+    def set_fiat_balance(
+            self,
+            currency: typing.FiatAsset,
+            provided_balance: str,
+    ) -> Tuple[bool, str]:
         if currency not in FIAT_CURRENCIES:
             return False, 'Provided currency {} is unknown'
 
-        if balance == 0 or balance == '':
+        msg = 'Provided balance for set_fiat_balance should be a string'
+        assert isinstance(provided_balance, str), msg
+
+        if provided_balance == '':
             self.db.remove_fiat_balance(currency)
         else:
             try:
-                balance = FVal(balance)
+                balance = FVal(provided_balance)
             except ValueError:
                 return False, 'Provided amount is not a number'
 
diff --git a/rotkehlchen/rotkehlchen.py b/rotkehlchen/rotkehlchen.py
--- a/rotkehlchen/rotkehlchen.py
+++ b/rotkehlchen/rotkehlchen.py
@@ -315,8 +315,7 @@ def logout(self):
         # Reset rotkehlchen logger to default
         LoggingSettings(anonymized_logs=DEFAULT_ANONYMIZED_LOGS)
 
-        del self.inquirer
-        self.inquirer = None
+        self.inquirer.kraken = None
         del self.accountant
         self.accountant = None
         del self.trades_historian
diff --git a/rotkehlchen/server.py b/rotkehlchen/server.py
--- a/rotkehlchen/server.py
+++ b/rotkehlchen/server.py
@@ -14,7 +14,7 @@
 from rotkehlchen.errors import AuthenticationError, RotkehlchenPermissionError
 from rotkehlchen.logging import RotkehlchenLogsAdapter
 from rotkehlchen.rotkehlchen import Rotkehlchen
-from rotkehlchen.typing import Timestamp
+from rotkehlchen.typing import Asset, Timestamp
 from rotkehlchen.utils import pretty_json_dumps, process_result, process_result_list
 
 logger = logging.getLogger(__name__)
@@ -214,7 +214,7 @@ def query_fiat_balances(self):
         res = self.rotkehlchen.query_fiat_balances()
         return process_result(res)
 
-    def set_fiat_balance(self, currency, balance):
+    def set_fiat_balance(self, currency: Asset, balance: str):
         result, message = self.rotkehlchen.data.set_fiat_balance(currency, balance)
         return {'result': result, 'message': message}
 


Test patch:
diff --git a/rotkehlchen/tests/test_api.py b/rotkehlchen/tests/test_api.py
--- a/rotkehlchen/tests/test_api.py
+++ b/rotkehlchen/tests/test_api.py
@@ -71,3 +71,24 @@ def test_dbinfo_is_written_at_shutdown(rotkehlchen_instance, username):
 
     assert dbinfo['sqlcipher_version'] == sqlcipher_version
     assert 'md5_hash' in dbinfo
+
+
+@pytest.mark.parametrize('number_of_accounts', [0])
+def test_logout_and_login_again(rotkehlchen_instance, username):
+    """Test that when a rotkehlchen user logs out they can properly login again
+    Regression test for https://github.com/rotkehlchenio/rotkehlchen/issues/288
+    """
+    rotkehlchen_instance.logout()
+    assert not rotkehlchen_instance.user_is_logged_in
+    rotkehlchen_instance.unlock_user(
+        user=username,
+        password='123',
+        create_new=False,
+        sync_approval='unknown',
+        api_key='',
+        api_secret='',
+    )
+    assert rotkehlchen_instance.user_is_logged_in
+    # The bug for #288 was here. The inquirer instance was None and any
+    # queries utilizing it were throwing exceptions.
+    rotkehlchen_instance.inquirer.get_fiat_usd_exchange_rates(currencies=None)
diff --git a/rotkehlchen/tests/test_db.py b/rotkehlchen/tests/test_db.py
--- a/rotkehlchen/tests/test_db.py
+++ b/rotkehlchen/tests/test_db.py
@@ -7,7 +7,7 @@
 from eth_utils.address import to_checksum_address
 from pysqlcipher3 import dbapi2 as sqlcipher
 
-from rotkehlchen.constants import YEAR_IN_SECONDS
+from rotkehlchen.constants import S_CNY, S_EUR, YEAR_IN_SECONDS
 from rotkehlchen.data_handler import DataHandler
 from rotkehlchen.db.dbhandler import (
     DBINFO_FILENAME,
@@ -75,7 +75,7 @@ def test_export_import_db(data_dir, username):
     """Create a DB, write some data and then after export/import confirm it's there"""
     data = DataHandler(data_dir)
     data.unlock(username, '123', create_new=True)
-    data.set_fiat_balance('EUR', 10)
+    data.set_fiat_balance('EUR', '10')
 
     encoded_data, _ = data.compress_and_encrypt_db('123')
     # The server would return them decoded
@@ -446,3 +446,25 @@ def close(self):
         with pytest.raises(ValueError):
             sql_mock.return_value = ConnectionMock('no version')
             detect_sqlcipher_version()
+
+
+def test_data_set_fiat_balance(data_dir, username):
+    data = DataHandler(data_dir)
+    data.unlock(username, '123', create_new=True)
+
+    amount_eur = '100'
+    amount_cny = '500'
+
+    success, _ = data.set_fiat_balance(S_EUR, amount_eur)
+    assert success
+    success, _ = data.set_fiat_balance(S_CNY, amount_cny)
+    assert success
+    balances = data.get_fiat_balances()
+    assert len(balances) == 2
+    assert balances[S_EUR] == amount_eur
+    assert balances[S_CNY] == amount_cny
+
+    success, _ = data.set_fiat_balance(S_EUR, '')
+    balances = data.get_fiat_balances()
+    assert len(balances) == 1
+    assert balances[S_CNY] == amount_cny