[SOLVED] Daedalus wallet appears stuck on «Connecting to network»

As I had the same recurrent issue as a few people here when launching Daedalus, from the logs I saw that my node wasn’t able to reach the IOHK node. After some research I found it could be fixed by adding a few other nodes in my topology.yaml file. For GNU/Linux, here is an example of how to locate and display it :

$ cat $(locate topology.yaml) | jq

{
  "Producers": [
    {
      "addr": "relays-new.cardano-mainnet.iohk.io",
      "port": 3001,
      "valency": 1
    }
  ]
}

And a simple DNS query on relays-new.cardano-mainnet.iohk.io gives us

$ dig relays-new.cardano-mainnet.iohk.io +short
54.215.120.53
18.158.36.122
13.114.93.89
18.159.26.101
3.23.160.18
54.250.104.14
18.133.108.207
52.14.186.237

So it is quite possible that some IP in this set are not always reachable, but it’s up to the implementation to choose which one will be used from the FQDN. That’s why a possible fix is adding manually other nodes (FQDN or IP), the procedure is described here

Since there are many nodes to choose from in IOHK topology.json, I wrote a simple Python script in order to find the 4 nodes with the lowest RTT (round trip time).

Python 3.x source code
#!/usr/bin/env python3

'''
 TopoSorter -- Simple program to sort nodes from topology.json file by their
 RTT (specific to Cardano project). The intended audience vary from SPO to
 Daedalus users (may help in making sensible choices for topology.yaml)

  This file is part of TopoSorter.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <https://www.gnu.org/licenses/>.
'''

import json
import pandas as pd
import requests as rq
import socket as sock
import time as tm

'''
TopoSorter is written in Python 3.x and depends on python3-pandas for DataFrame

Please note there are (a few) limitations :

    * as I have been gently reminded by my preferred SPO, given the P2P upgrade
    in progress on Cardano this tool will not be useful for long.
    * we rely on a connect() call to approximate RTT, it is far to be perfect
    but the objective here is to sort, not to get a usec order precision.
    * connect() implementation is relying at some point on getaddrinfo() and
    using empirical approach it takes a long time in some case (esp. ddns)
    * the current version does not allow for filtering on a specific continent
    (predicate matching could be implemented with filter() though) We believe
    it might serves the end-user better by making no (geographic) assumption.
    That also avoids the user having to put an IP address (potentially subject
    to a change) in his topology.yaml file instead of FQDN when available.
    * some relays have several IP addresses behind a domain name, however we
    currently use only one, as unfair as it might be for some relays, we
    believe on most configurations those different IPs belong to the same
    subnetwork and as such shouldn't present induce/warrant too big a change in
    error margin and most probably not in sorting order.
    * only one measure is taken for each node, in order to take the weather
    into acount (SYN tempest)
    * it can take some time to process every node, although this part could be
    mutlithreaded we try not to induce bias in results.
    * this tool will not open firewall ports for you in case you decide to
    update topology.yaml
    * obviously tests are to be conducted at different periods of time as
    network load and routes are constantly changing. It is only meant to be
    used as a tool and not as an «oracle». On that note it would be pretty
    straightforward to implement some daemon to monitor RTT for a few nodes,
    then plot a graph using the collected data.
'''

TOPOLOGY_JSON_URL = u'https://explorer.cardano-mainnet.iohk.io/relays/topology.json'
TOPOLOGY_FILENAME = u'topology.yaml'
# number of entries to be saved in topology.yaml (JSON ⊂ YAML)
NB_ROWS = 4

class TopoSorter:

    def __init__(self, *args, **kwargs):

        self.df = ''

    def do_http_get(self, url):
        try:
            r = rq.get(url)
            if r.status_code != 200:
                r.raise_for_status()
        except rq.HTTPError as e:
            print(e)
        except ConnectionError as e:
            print(e)
        return r

    def get_dataframe(self, url):

        j = self.do_http_get(url).json()
        #  print(j)
        p = j['Producers']

        #  print(f'{len(p)} elements in JSON')

        return pd.DataFrame(p, columns=['addr', 'port', 'continent', 'state', 'RTT'])

    def get_rtt(self, host, port):

        d = 255.0 # we chose a huge value to avoid «connection refused» bias
        print(f'Check RTT on {host} {port}/tcp')
        ''' we use the time needed to connect() as an approximation for RTT,
            we could have used another port and looked for ICMP Port
            Unreachable but we're lazy, and of course there is no guarantee
            that the port will not be filtered and the packet silently dropped
            by some evil (but useful) fw
        '''

        s = sock.socket(sock.AF_INET, sock.SOCK_STREAM)
        s.setsockopt(sock.SOL_SOCKET, sock.SO_REUSEADDR, 1)
        s.setsockopt(sock.IPPROTO_TCP, sock.TCP_NODELAY, 1)
        s.settimeout(3)
        try:

            start_time = tm.time()
            s.connect((host, port))
            end_time = tm.time()
            d = end_time - start_time

        except ConnectionRefusedError as e:
            print(f'\033[31m{host} {e}\033[0m')
        except IOError as e:
            print(f'\033[31m{host} NXDOMAIN OR timeout\033[0m')
        except Exception as e:
            print(f'\033[31m{host} Unknown exception {e}\033[0m')
        finally:
            s.close()

        return d

    def get_data(self, url):

        self.df = self.get_dataframe(url)

        ''' now we compute each RTT '''
        for row in self.df.itertuples():
            # row[0] is Index, so row[1] is host and row[2] is port
            self.df.at[row.Index, 'RTT'] = self.get_rtt(row[1], row[2])

        return self.df

    def sort_data(self):

        self.df.sort_values(by=['RTT'], inplace=True)

    def save_topo_file(self, fn, df):

        print(df)
        j = {}
        j['Producers'] = []
        for row in df.itertuples():
            j['Producers'].append({
                'addr' : row[1],
                'port' : row[2],
                'valency' : 1
                })

        with open(TOPOLOGY_FILENAME, 'w') as f:
            json.dump(j, f)

    def get_df(self):

        return self.df

    ''' check that we are indeed connected to the Internet,
        and try to gracefully handle ugly exceptions '''
    @staticmethod
    def is_connected():
        try:
            # connect to the host -- tells us if the host is actually reachable
            sk = sock.create_connection(('www.google.com', 80))
            if sk is not None:
                # closing socket
                sk.close()
            return True
        except OSError:
            pass
        return False

def main():

    if not TopoSorter.is_connected():
        sys.stderr.write('No Internet access, please try again.\n')
        sys.exit(-1)

    t = TopoSorter() # get an instance

    df = t.get_data(TOPOLOGY_JSON_URL) # fetch data

    t.sort_data() # now we sort by RTT

    print(f'\nSample of results:\n{t.get_df()}\n') # print sample

    # then we display the NB_ROWS most fastest results, following
    # topology.yaml style (JSON ⊂ YAML)
    t.save_topo_file(TOPOLOGY_FILENAME, t.get_df().iloc[:NB_ROWS])

if __name__ == '__main__':
    main()

Be advised that it will take around 20 minutes to check the full set of 3 294 nodes. Moreover, as my preferred SPO gently reminded me, given the P2P upgrade in progress on Cardano this tool will not be useful once deployment reaches mainnet.

2 Likes

@raph_cardano We had a similar idea in a thread over here: Daedalus: Relay Node Configuration Help? - #23 by DinoDude

It’s more focused on filtering by geographic location than sorting on response time. Ironically by the time we collectively combine every idea into a script, then combine the scripts, and then somebody hosts that somewhere the real fix ought to make it all moot.

These temporary workarounds will have to do for now …

Thank you very much for the feedback @DinoDude :+1:

Your solution is elegant, and way faster :wink: I chose the RTT so that it could also apply to users who live at the edges of a zone, but you’re right, choosing a State should do it.

I wish I had time to sit down and learn to understand what’s written here and then learn how to apply it in the correct areas suggested to use the code. I started a topic on this for mannet 4.1.0 on windows 10. Seems knowing how to navigate and code is the only real solution. So far. :slightly_frowning_face: but I’m hopeful. Since deleting and re syncing, it’s gone about .40% past where it was stuck for 3 days. But it’s taken about 2 hours to do so. Connection drops then it starts syncing again. But doesn’t drop as long as before. I’m at 94.92%

Hello @Crypto_Dryp, this is a Python script, so it should work as well on Windows as on GNU/Linux, provided you have a Python interpreter. You just have to launch it and wait for every RTT to be computed. Then you’ll get the 4 fastest nodes to connect to. After that you should spend less than 5 seconds on «Connecting to network» step on Daedalus (in fact most of the time, it’s not even displayed long enough to read it). That being said, the first sync is long because you have a whole blockchain instance to get, several GB, after that it doesn’t take that long provided you sync once a week, only the time needed to get the last blocks.

1 Like

What am I doing with the python scripts? Where do they go?

Let’s say the code is saved in file TopoSorter.py, either you use the CLI (on any Windows it’s the program cmd.exe) and provided you have installed Python 3.x for Windows, you type something like

> Python TopoSorter.py

from the same directory, or it’s also possible that you could just click on it (to be confirmed though). Then you just have to wait for every node to be checked, you’ll see the domain name of each one of them as it’s being processed. It takes usually around 20 minutes for all the nodes in topology.json. Then you’ll get a topology.yaml file in the same directory. You can save the old one (move or rename it) and use this one instead.

NB: @DinoDude script will be way faster but you’ll have to modify region and states variables in order to reflect yours before launching the script (same procedure otherwise).

1 Like

About Python installation, apparently on Windows 10 it can be done quickly and painlessly from the Microsoft Store:

The “Install Python” step should be the only one of use to you for now.

1 Like

And according to this stackoverflow thread, you shouldn’t get any trouble with the shebang I used. The shebang is the very first line of any Python or shell script. It gives the path to the interpreter, and as you probably know already, paths on GNU/Linux and Windows are different (regarding file system hierarchy and separators)

1 Like

@raph_cardano script will actually work better even though it takes a bit longer to run as it measures the response time of each node and sorts by the fastest nodes found! Mine just filters by available nodes nearest to you but you have to follow the TODO instructions in the code to setup your preferred location as it’s very basic. You should only need to run either of these “configuration helper” scripts once anyway.

@Crypto_Dryp below is the general steps for using either Python script for newbies or less technical folks:

  1. Make sure you have a python interpreter installed. Most computers already have it installed by default or due to other Python apps you already use. If not, it’s a free download at Download Python | Python.org including install instructions if you need them.
  2. Copy and paste either Raph’s or my code snippet and save it to a file anywhere. Download folder or desktop works great. Typically people use the .py extension for python files. Hint: pick a short file name that makes sense to you as you may need to type this in step 3!
  3. Run the script. This differs by operating system but here is a simple guide that explains how for all of them: How to run Python Scripts? Once complete both our workaround scripts will generate a file called topology.yaml which is a drop in replacement for Daedalus configuration in the format the wallet expects.
  4. Find where your Daedalus node configuration currently exists and make a backup copy.
    On Linux and Mac you can use find command in the terminal find ~/.daedalus -name topology.yaml on Windows you can use the search feature from start menu or from your C: drive window once open. Sorry, been awhile since I used Windows.
  5. Copy the newly created topology.yaml into the Daedalus configuration location and restart the wallet to use the new faster relay nodes to connect to the network and sync!

Of course if that still seems super complicated or you don’t feel comfortable running a script that you don’t completely understand that’s OK. The default configuration of Daedalus will only use IOHK relay nodes and it will eventually connect and sync if you leave it running overnight. After the first “full sync” a new epoch or block comes out every 5 days so just make sure to sync up at least once a week and it won’t take as long in the future. Also as Raph mentioned sometime soon the “official developers” will improve the peer-to-peer (P2P) discovery code within the Cardano network itself and then we won’t need these temporary workarounds anymore.

1 Like