Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Launcher

Hiroto Shioi edited this page Nov 20, 2019 · 14 revisions

Issues with launcher in Cardano SL

Existing launcher has a number of issues:

  • It depends on the modules from cardano-sl which is a huge burden when it comes to building, maintaining, etc.
  • It can be run on multiple scenarios (server, client, frontend only). As of right now, frontend scenario is the only one being used. This means that many of the code used in the launcher is dead code.
  • Its codes are way too complicated for what it is doing.
  • Most of the code has no test associated with it. This means the only way we can assure that everything works as expected was for QA to test the launcher.

Our aim for the launcher was to extract the code from existing code and try to simplify it as much as we can whilst testing many of the code with property-based testing as well as state-machine testing to ensure that everything works as expected.

Requirements

On Linux, in order for cardano-launcher to run, it needs environment variable DAEDALUS_CONFIG to be set before running. The value should be file path to the directory which contains the configuration files that are needed for Cardano to run. This is set by the script which executes the launcher. For more information, please see this page.

Basic flow

The diagram below shows the basic flow of the launcher.

Setup env vars

Following environment variables are being set.

Variable name Value Used for Notes
DAEDALUS_INSTALL_DIRECTORY Path to directory in which launcher executable is placed within To specify the path to tls configuration file, x509 tools, and wallet/node executable for the launcher All platforms
LAUNCHER_CONFIG Path to launcher-config.yaml To let Daedalus know the path to launcher.yaml file All platforms
LC_ALL en_GB.UTF-8 To prevent the program from crashing when non-ASCII character was printed on stdout https://gitlab.haskell.org/ghc/ghc/issues/15118 All platforms
LANG en_GB.UTF-8 To prevent the program from crashing when non-ASCII character was printed on stdout https://gitlab.haskell.org/ghc/ghc/issues/15118 All platforms
XDG_DATA_HOME Path to special directories for storing user-specific application data, configuration, and cache files To specify the path to the working directory, updater script, tls certs, and state directory for the launcher All platforms

Acquire path to config file via CLI

The launcher will then read the config-file launcher-config.yaml and parse them. The file path to the launcher can be specified by the command line argument with argument -c. If the path was not specified, the launcher will try to read launcher-config.yaml that is placed in the same directory as the launcher.

Env var substitution

Some of the value in the config file has a placeholder wrapped with brackets (e.g. ${FOO}). This needs to be replaced with the env var defined with the same name. For example, if there's placeholder ${FOO} then the launcher needs to lookup env var FOO and replace ${FOO} with that value.

This is needed for launcher to understand:

  • Where to store TLS certificates before launching Daedalus
  • Where the state directory is (This is needed for storing the state of launch mode)
  • Where to find update files

Setup working directory

After parsing the config file, the launcher will set the working directory to the path that is specified by the config file's value workingDir.

Apply an exclusive lock on a lock file

To prevent multiple instances of cardano-launcher from running, the launcher will apply an exclusive lock on a daedalus_lockfile which is located within state path.

Generate TLS certificate

Every time the launcher is being launched, it will create a TLS certificate that is used by Daedalus to communicate with cardano-wallet. Configuration file cert-configuration.yaml is required for the launcher to generate certificates and the path to the file is specified by the launcher configuration file's value, configuration.filePath.

Run update system

Before launching Daedalus, the launcher will check if the update needs to be performed. For more details on how the update is being done, please see the wiki page.

Run Daedalus

The launcher will spawn Daedalus as a child process. How the code being spawned are specified by the config file's value, walletPath, walletArgs which are the path to the Daedalus executable and argument the launcher provides.

Handling restart/exit process

Some of the exitcode of the Daedalus has special meanings. These numbers will indicate launcher that Daedalus is asking for some action.

ExitCode # What it means What it does
20 Daedalus is ready to run the update system Launcher will run update system
21 Daedalus asks launcher to relaunch Daedalus with GPU safe mode Launcher will respawn daedalus as a child process with arguments --safe-mode --disable-gpu --disable-d3d11
22 Daedalus asks launcher to relaunch Daedalus with normal mode Launcher will respawn daedalus without the GPU safemode arguments
Others Daedalus wants launcher to exit as well Launcher will perform clean up on the logging feature, then exits itself

Restart in GPU-safe mode

On rare occasions, Daedalus shows a blank screen to the user. This is due to some bug in the electron library that Daedalus is using. As a workaround, we provide GPU-safe mode to the user which will make Daedalus avoid using GPUs. This is done by launching the Daedalus with the argument --safe-mode --disable-gpu --disable-d3d11.

Shutting down the launcher

When the Daedalus exits with the exitcode other than 20, 21, or 22, the launcher will perform a cleanup process and shut itself down, exiting with the same ExitCode that Daedalus threw.

Error handling

On all the platforms, any error message that launcher throws will be stored on a log file. If a user has encountered any issues with Daedalus, one can send the file to the IOHK help desk to triage it. For more information about logging, please see the Logging section.

Windows

On windows, if the launcher throws an exception, an error message will pop up. This is done by passing an argument -optl-mwindows in cabal file.

https://stackoverflow.com/questions/51015178/how-to-get-rid-of-the-black-console-window-for-a-compiled-haskell-gui-application

  if os(windows)
    ghc-options: -optl-mwindows

MacOS

On macOS, the launcher uses osascript to emit error message. osascript is a command which lets you display any message as a dialog/notification.

https://scriptingosx.com/2018/08/user-interaction-from-bash-scripts/

Linux

On Linux, the error message will be emitted on the terminal.

Configuration

Cardano launcher uses command-line argument (CLI) and configuration file to configure it's operation.

CLI

In CLI, you can pass the file path to the configuration file via argument --config or -c. If the argument was not provided, the launcher will instead lookup configuration file launcher-config.yaml that is located within the same directory as launcher.

Configuration file

The launcher uses a yaml file as a configuration file. We have 3 clusters (mainnet, stating, testnet) with 3 platforms meaning we have total of 9 yaml files, each of them with different values. In order for us to manage them, we use sets of dhall files which can be used to generate configuration files corresponding to each cluster and platform. Currently, these dhall files live in Daedalus repository. The CI will use these dhall files to produce the yaml files as artifacts.

Logging

For logging, cardano-launcher uses iohk-monitoring-framework. Log messages will be outputted on both stdout and log file. The path to the log file is specified by the value of launcherLogsPrefix from the config file. If the user has any issues with Daedalus, the Daedalus will send the log file to the IOHK's help desk which will try to triage the issue.

Testing

QuickCheck is heavily used to practice property-based testing. Property-based testing enables us to test the application much more extensively than unit tests. We do both positive and negative test to ensure that the application fails as expected. We also use QuickCheck state machine to test the restart process. Restart process involves various components being at different state and using state machine testing helped us test them quite nicely.