Repository: rotki/rotki

Issue:
Rotki does not connect to Turbogeth
## Problem Definition

A user with dappnode and turbogeth tried to connect rotki to it and failed with the following exception:

```
[24/11/2020 22:30:29 CET] INFO rotkehlchen.api.server.pywsgi: 127.0.0.1 - - "OPTIONS /api/1/settings HTTP/1.1" 200 319 0.001064
[24/11/2020 22:30:29 CET] DEBUG web3.providers.HTTPProvider: Making request HTTP. URI: http://turbo-geth.dappnode:8545/, Method: web3_clientVersion
[24/11/2020 22:30:29 CET] DEBUG web3.providers.HTTPProvider: Getting response HTTP. URI: http://turbo-geth.dappnode:8545/, Method: web3_clientVersion, Response: {'jsonrpc': '2.0', 'id': 0, 'error': {'code': -32601, 'message': 'the method web3_clientVersion does not exist/is not available'}}
[24/11/2020 22:30:29 CET] ERROR rotkehlchen.api.server: Exception on /api/1/settings [PUT]
Traceback (most recent call last):
  File "site-packages/flask/app.py", line 1949, in full_dispatch_request
  File "site-packages/flask/app.py", line 1935, in dispatch_request
  File "site-packages/flask_restful/__init__.py", line 458, in wrapper
  File "site-packages/flask/views.py", line 89, in view
  File "site-packages/flask_restful/__init__.py", line 573, in dispatch_request
  File "site-packages/webargs/core.py", line 366, in wrapper
  File "rotkehlchen/api/v1/resources.py", line 164, in put
  File "rotkehlchen/api/rest.py", line 130, in wrapper
  File "rotkehlchen/api/rest.py", line 268, in set_settings
  File "rotkehlchen/rotkehlchen.py", line 858, in set_settings
  File "rotkehlchen/chain/manager.py", line 275, in set_eth_rpc_endpoint
  File "rotkehlchen/chain/ethereum/manager.py", line 257, in set_rpc_endpoint
  File "rotkehlchen/chain/ethereum/manager.py", line 203, in attempt_connect
  File "site-packages/web3/main.py", line 260, in isConnected
  File "site-packages/web3/providers/base.py", line 108, in isConnected
AssertionError
[24/11/2020 22:30:29 CET] INFO rotkehlchen.api.server.pywsgi: 127.0.0.1 - - "PUT /api/1/settings HTTP/1.1" 500 216 0.049721
```

I also tried the same with a turbogeth rpcdaemon and turbogeth instance that I just synced. It went further than the user (presumably due to my rpcdaemon's flags `--http.api=eth,debug,net,web3`)

But still failed due to `net_version` later.

```
Traceback (most recent call last):
  File "src/gevent/greenlet.py", line 818, in gevent._greenlet.Greenlet.run
  File "/home/lefteris/w/rotkehlchen/rotkehlchen/chain/ethereum/manager.py", line 276, in attempt_connect
    network_id = int(web3.net.version)
  File "/home/lefteris/.virtualenvs/rotkipy37/lib/python3.7/site-packages/web3/net.py", line 44, in version
    return self._version()
  File "/home/lefteris/.virtualenvs/rotkipy37/lib/python3.7/site-packages/web3/module.py", line 44, in caller
    result = w3.manager.request_blocking(method_str, params, error_formatters)
  File "/home/lefteris/.virtualenvs/rotkipy37/lib/python3.7/site-packages/web3/manager.py", line 153, in request_blocking
    raise ValueError(response["error"])
ValueError: {'code': -32000, 'message': 'the function net_version is not available, please use --private.api.addr option instead of --chaindata option'}
2020-11-26T23:45:40Z <Greenlet at 0x7fe0a0a3d5f0: <bound method EthereumManager.attempt_connect of <rotkehlchen.chain.ethereum.manager.EthereumManager object at 0x7fe0a09afed0>>(name=<NodeName.OWN: 0>, ethrpc_endpoint='http://XXXX', mainnet_check=True)> failed with ValueError

Task for Attempt connection to own node ethereum node died with exception: {'code': -32000, 'message': 'the function net_version is not available, please use --private.api.addr option instead of --chaindata option'}.
Exception Name: <class 'ValueError'>
Exception Info: {'code': -32000, 'message': 'the function net_version is not available, please use --private.api.addr option instead of --chaindata option'}
Traceback:
   File "src/gevent/greenlet.py", line 818, in gevent._greenlet.Greenlet.run
  File "/home/lefteris/w/rotkehlchen/rotkehlchen/chain/ethereum/manager.py", line 276, in attempt_connect
    network_id = int(web3.net.version)
  File "/home/lefteris/.virtualenvs/rotkipy37/lib/python3.7/site-packages/web3/net.py", line 44, in version
    return self._version()
  File "/home/lefteris/.virtualenvs/rotkipy37/lib/python3.7/site-packages/web3/module.py", line 44, in caller
    result = w3.manager.request_blocking(method_str, params, error_formatters)
  File "/home/lefteris/.virtualenvs/rotkipy37/lib/python3.7/site-packages/web3/manager.py", line 153, in request_blocking
    raise ValueError(response["error"])

Task for Attempt connection to own node ethereum node died with exception: {'code': -32000, 'message': 'the function net_version is not available, please use --private.api.addr option instead of --chaindata option'}. Check the logs for more details
^CKeyboardInterrupt
2020-11-26T23:45:47Z
Traceback (most recent call last):
  File "tools/uniswapv2/detect.py", line 194, in <module>
    use_other_nodes=args.use_other_nodes,
  File "tools/uniswapv2/detect.py", line 46, in init_ethereum
    ethereum=ethereum,
  File "/home/lefteris/w/rotkehlchen/rotkehlchen/tests/utils/ethereum.py", line 49, in wait_until_all_nodes_connected
    gevent.sleep(0.1)
  File "/home/lefteris/.virtualenvs/rotkipy37/lib/python3.7/site-packages/gevent/hub.py", line 159, in sleep
    hub.wait(t)
  File "src/gevent/_hub_primitives.py", line 46, in gevent.__hub_primitives.WaitOperationsGreenlet.wait
  File "src/gevent/_hub_primitives.py", line 55, in gevent.__hub_primitives.WaitOperationsGreenlet.wait
  File "src/gevent/_waiter.py", line 151, in gevent.__waiter.Waiter.get
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 65, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/__greenlet_primitives.pxd", line 35, in gevent.__greenlet_primitives._greenlet_switch
```

Errors TL;DR:

User
```
Response: {'jsonrpc': '2.0', 'id': 0, 'error': {'code': -32601, 'message': 'the method web3_clientVersion does not exist/is not available'}}
```

Me
```
ValueError: {'code': -32000, 'message': 'the function net_version is not available, please use --private.api.addr option instead of --chaindata option'}
```



## Task

1. Make sure that this error, the one of the user does not result in a 500 Error. Probably need to catch the Assertionerror from web3.py. This is terrible :(
2. Find out why the net_version happens with turbogeth, and perhaps add a special rule/exception for them




Discussion:

Resolving patch:
diff --git a/rotkehlchen/chain/ethereum/manager.py b/rotkehlchen/chain/ethereum/manager.py
--- a/rotkehlchen/chain/ethereum/manager.py
+++ b/rotkehlchen/chain/ethereum/manager.py
@@ -268,30 +268,44 @@ def attempt_connect(
             log.warning(message)
             return False, message
 
-        if web3.isConnected():
+        try:
+            is_connected = web3.isConnected()
+        except AssertionError:
+            # Terrible, terrible hack but needed due to https://github.com/rotki/rotki/issues/1817
+            is_connected = False
+
+        if is_connected:
             # Also make sure we are actually connected to the Ethereum mainnet
             synchronized = True
             msg = ''
-            if mainnet_check:
-                network_id = int(web3.net.version)
-                if network_id != 1:
-                    message = (
-                        f'Connected to ethereum node {name} at endpoint {ethrpc_endpoint} but '
-                        f'it is not on the ethereum mainnet. The chain id '
-                        f'the node is in is {network_id}.'
-                    )
-                    log.warning(message)
-                    return False, message
-
-                current_block = web3.eth.blockNumber  # pylint: disable=no-member
-                try:
-                    latest_block = self.query_eth_highest_block()
-                except RemoteError:
-                    msg = 'Could not query latest block'
-                    log.warning(msg)
-                    synchronized = False
-                else:
-                    synchronized, msg = _is_synchronized(current_block, latest_block)
+            try:
+                if mainnet_check:
+                    network_id = int(web3.net.version)
+
+                    if network_id != 1:
+                        message = (
+                            f'Connected to ethereum node {name} at endpoint {ethrpc_endpoint} but '
+                            f'it is not on the ethereum mainnet. The chain id '
+                            f'the node is in is {network_id}.'
+                        )
+                        log.warning(message)
+                        return False, message
+
+                    current_block = web3.eth.blockNumber  # pylint: disable=no-member
+                    try:
+                        latest_block = self.query_eth_highest_block()
+                    except RemoteError:
+                        msg = 'Could not query latest block'
+                        log.warning(msg)
+                        synchronized = False
+                    else:
+                        synchronized, msg = _is_synchronized(current_block, latest_block)
+            except ValueError as e:
+                message = (
+                    f'Failed to connect to ethereum node {name} at endpoint '
+                    f'{ethrpc_endpoint} due to {str(e)}'
+                )
+                return False, message
 
             if not synchronized:
                 self.msg_aggregator.add_warning(


Test patch: