tl;dr;
Jump straight to the build instructions
The Details
Looking forward to the Haskell mainnet, the next step in the Cardano project, I’ve begun exploring the cardano-node
Haskell implementation.
I find that exploring source code is much easier if you actually watch the program run for a while. So, the first thing a developer has to do is build the project!
So, while trying to build cardano-node using the published instructions, I ran into a few issues. In this post I’ll be sharing my experience, which hopefully will be useful to others.
I’m not a Haskell expert. I’ve worked with functional programming before, but mainly in hybrid languages such as Ocaml and Scala. Haskell is 100% purely functional, so it requires a different approach to several problems. In Scala, for instance, you can fall back to Java idioms if you need to in order to solve some problems. In Haskell you can’t. It’s 100% functional.
So, if you’re an experienced Haskell developer, some of the steps taken here may sound redundant or non idiomatic. I’m sorry about that.
So let’s jump right into the hackage.
Building cardano-node
According to the Github project’s README, all I gotta do is:
$ cd cardano-node
$ cabal build
So, let’s try it.
$ cabal build
Warning: The build command is a part of the legacy v1 style of cabal usage.
Please switch to using either the new project style and the new-build command
or the legacy v1-build alias as new-style projects will become the default in
the next version of cabal-install. Please file a bug if you cannot replicate a
working v1- use case with the new-style commands.
For more information, see: https://wiki.haskell.org/Cabal/NewBuild
cabal: No cabal file found.
Please create a package description file <pkgname>.cabal
Alright, that didn’t fly. So I need a cabal file. Only thing that looks like a cabal file in here is cabal.project
, but apparently I need the extension to be .cabal
, not the name.
Browsing the source tree I find a stack.yaml
file, so let’s try building with stack
instead.
$ stack build
[... hundreds of screens scroll by ...]
Process exited with code: ExitFailure 1
Progress 4/49
OK so that seemed to be going well …until it didn’t.
Buildkite to the rescue?
At the top of the project I see a Buildkite icon saying the build is passing!
Buildkite usually shows all the build steps in its log, so let’s check it out and copy the same instructions and it should work, right?
Buildkite required me to create an account to access. Fine. So, 5 minutes later:
The cardano-node directory is not found under the public IOHK Buildkite listings.
So either Buildkite isn’t actually building cardano-node
or IOHK hasn’t made it public. Let’s go up one level on the buildkite.com URL and see what the correct URL is.
OK, so IOHK only makes one Buildkite repository public: the stakepool registry one. The build might be passing on the private repository, I guess.
So I’ve hit a wall. I have no idea how to build cardano-node
.
Trying cabal again:
$ cabal build cardano-node
[...outpu....]
cabal: No cabal file found.
Please create a package description file <pkgname>.cabal
No cigar either. I assume it meant v2-build
, so let me try that:
$ cabal v2-build cardano-node
Warning: Requested index-state2020-04-01T00:00:00Z is newer than
'hackage.haskell.org'! Falling back to older state (2020-03-31T22:47:49Z).
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: lobemo-scribe-systemd-0.1.0.0 (user goal)
[__1] next goal: libsystemd-journal (dependency of lobemo-scribe-systemd)
[__1] rejecting: libsystemd-journal-1.4.4 (conflict: pkg-config package
libsystemd>=209, not found in the pkg-config database)
[__1] rejecting: libsystemd-journal-1.4.3, libsystemd-journal-1.4.2,
libsystemd-journal-1.4.1, libsystemd-journal-1.4.0, libsystemd-journal-1.3.4,
libsystemd-journal-1.3.3, libsystemd-journal-1.3.1, libsystemd-journal-1.3.0,
libsystemd-journal-1.2.0, libsystemd-journal-1.1.0, libsystemd-journal-1.0.0
(constraint from project config TODO requires >=1.4.4)
[__1] fail (backjumping, conflict set: libsystemd-journal,
lobemo-scribe-systemd)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: libsystemd-journal,
lobemo-scribe-systemd
OK, so that didn’t work. But this time it looks like something I can try to fix. Seems like it can’t find libsystemd
. Going back to Ubuntu’s package manager to install that:
$ sudo apt search libsystemd
This succeeded, so I tried to install one of the missing cabal dependencies by hand:
$ cabal install libsystemd-journal
This went fine. Until it didn’t.
cabal: Error: some packages failed to install:
entropy-0.4.1.6-6yYvxJr6pbn5FDLgHz97fz failed during the configure step. The
exception was:
dieVerbatim: user error (cabal: '/usr/bin/ghc' exited with an error:
/tmp/cabal-tmp-13229/entropy-0.4.1.6/dist/setup/setup.hs:3:1: error:
Could not find module ‘Distribution.Simple’
There are files missing in the ‘Cabal-3.2.0.0’ package,
try running 'ghc-pkg check'.
Use -v to see a list of the files searched for.
|
3 | import Distribution.Simple
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
Here, for some reason, I began to suspect that my ghc
installation was somehow corrupted or had stale dependencies. Some messages don’t match stuff I’ve been seeing in online help, which probably indicates that I need to update.
A New Beginning
So I decided to restart with a clean slate. I manually deleted ghc
, stack
, cabal
and cleared the nix
binary store.
I restarted with a fresh install from ghcup and stack.
$ ~/.ghcup/bin/cabal v2-build cardano-node
Warning: Requested index-state2020-04-01T00:00:00Z is newer than
'hackage.haskell.org'! Falling back to older state (2020-03-31T22:47:49Z).
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: Win32-network-0.1.0.0 (user goal)
[__1] next goal: base (dependency of Win32-network)
[__1] rejecting: base-4.13.0.0/installed-4.13.0.0 (conflict: Win32-network =>
base>=4.5 && <4.13)
[__1] rejecting: base-4.12.0.0, base-4.11.1.0, base-4.11.0.0, base-4.10.1.0,
base-4.10.0.0, base-4.9.1.0, base-4.9.0.0, base-4.8.2.0, base-4.8.1.0,
base-4.8.0.0, base-4.7.0.2, base-4.7.0.1, base-4.7.0.0, base-4.6.0.1,
base-4.6.0.0, base-4.5.1.0, base-4.5.0.0, base-4.4.1.0, base-4.4.0.0,
base-4.3.1.0, base-4.3.0.0, base-4.2.0.2, base-4.2.0.1, base-4.2.0.0,
base-4.1.0.0, base-4.0.0.0, base-3.0.3.2, base-3.0.3.1 (constraint from
non-upgradeable package requires installed instance)
[__1] fail (backjumping, conflict set: Win32-network, base)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, Win32-network
So, the stale version suspicion was right, as it passed all the previous obstacles this time. But now we’ve hit a systemic limitation, not just a glitch: it’s looking for Win32-network-0.1.0.0
which is Win32 stuff. Except I’m running linux.
Not good.
Flashback
Now I remember that the first time I tried to compile Daedalus and cardano-sl under linux back in 2017, I faced similar problems. It seems like IOHK develops the Windows versions first.
Win32 Follies
This is the required Win32 package:
source-repository-package
type: git
location: https://github.com/input-output-hk/ouroboros-network
tag: 18ef245af8181cf3bc208b71c7c4f8502137dbbb
--sha256: 1v0ksjw1fp9md91igya9vlmnvw5z81jylywgwc2svx125k9b79bj
subdir: Win32-network
So let’s pay a visit to the ouroboros-network
repository and take a look. Fortunately, under the Win32-network
dir there’s an example application. This might give us a clue about how this library is used.
import System.Win32 (HANDLE)
import qualified System.Win32.NamedPipes as Win32
import qualified System.Win32 as Win32
import qualified System.Win32.Async as Win32
This is how the Win32 library is used in the sample app. Let’s go back to cardano-node and see what we find by grepping for this library string:
#if defined(mingw32_HOST_OS)
import Data.Bits ((.|.))
import qualified System.Win32.NamedPipes as Win32.NamedPipes
import qualified System.Win32.Async as Win32.Async
import qualified System.Win32 as Win32
import System.IOManager
#else
import System.Process (createPipe)
import System.IO (hClose)
#endif
OK, so there’s a conditional pre-processor guard in place. Which means we can probably remove this dependency from the cabal file without breaking the compilation. Let’s try.
% cabal v2-build all
Warning: Requested index-state2020-04-01T00:00:00Z is newer than
'hackage.haskell.org'! Falling back to older state (2020-03-31T22:47:49Z).
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: byron-spec-chain-0.1.0.0 (user goal)
[__1] trying: hashable-1.3.0.0 (dependency of byron-spec-chain)
[__2] trying: base-4.13.0.0/installed-4.13.0.0 (dependency of
byron-spec-chain)
[__3] trying: cardano-sl-x509-3.0.0 (user goal)
[__4] next goal: ip (dependency of cardano-sl-x509)
[__4] rejecting: ip-1.7.1, ip-1.7.0, ip-1.6.0, ip-1.5.1, ip-1.5.0 (constraint
from project config TODO requires <1.5)
[__4] rejecting: ip-1.4.2.1 (conflict: hashable==1.3.0.0, ip => hashable>=1.2
&& <1.3)
[__4] skipping: ip-1.4.2, ip-1.4.1, ip-1.4.0, ip-1.3.0, ip-1.2.1, ip-1.2.0,
ip-1.1.2, ip-1.1.1, ip-1.1.0, ip-1.0.0, ip-0.9.3, ip-0.9.2, ip-0.9.1, ip-0.9,
ip-0.8.7, ip-0.8.6, ip-0.8.5, ip-0.8.4, ip-0.8.3, ip-0.8.1, ip-0.8, ip-0.7,
ip-0.6.2, ip-0.6.1 (has the same characteristics that caused the previous
version to fail: excludes 'hashable' version 1.3.0.0)
[__4] rejecting: ip-0.6.0 (conflict: cardano-sl-x509 => ip==1.4.*)
[__4] skipping: ip-0.5, ip-0.4, ip-0.3, ip-0.2, ip-0.1 (has the same
characteristics that caused the previous version to fail: excluded by
constraint '==1.4.*' from 'cardano-sl-x509')
[__4] fail (backjumping, conflict set: cardano-sl-x509, hashable, ip)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: hashable, base, ip, byron-spec-chain,
cardano-sl-x509
Try running with --minimize-conflict-set to improve the error message.
Alright, so the Win32 issue is gone. But now have a different problem. Looks like it can’t find hashable
, base
, ip
, byron-spec-chain
, and cardano-sl-x509
. While searching for the solution it occurred to me that I hadn’t tried stack
after the Haskell cleanup. So let’s try that and see how far it goes now:
$ stack build
Error: While constructing the build plan, the following exceptions were encountered:
In the dependencies for iohk-monitoring-0.1.10.1:
Win32-network needed, but the stack configuration has no specified version (no package with that name found, perhaps there is a typo in a
package's build-depends or an omission from the stack.yaml packages list?)
needed due to cardano-api-1.11.0 -> iohk-monitoring-0.1.10.1
In the dependencies for ouroboros-network-framework-0.1.0.0:
Win32-network must match >=0.1 && <0.2, but the stack configuration has no specified version (no package with that name found, perhaps there
is a typo in a package's build-depends or an omission from the stack.yaml packages list?)
needed due to cardano-api-1.11.0 -> ouroboros-network-framework-0.1.0.0
Some different approaches to resolving this:
Plan construction failed.
That’s just great. The empty Some different approaches to resolving this:
message is especially helpful. So, let’s try removing the Win32 dependency again, like we did with cabal
. Oops, that won’t work this time, because these are separate Git repositories. We need to import both iohk-monitoring
and ouroboros-network-framework
into our project and then edit their stack dependencies locally.
The Breakthrough
So, while I was getting beat up in every conceivable way, I suddenly came across this video about the Friends and Family (F&F) Shelley testnet:
In the video description, there’s a link to the exercise sheet that F&F pool owners are working on. It turns out this exercise sheet involves building cardano-node! And, as you might have guessed, it includes detailed instructions on how to do it straight from the insiders! Let’s try it!
$ git clone https://github.com/input-output-hk/cardano-node.git
$ cd cardano-node
$ git fetch --all --tags
$ git checkout tags/1.10.0
$ git fetch --all --tags
$ git checkout tags/1.10.0
$ cabal install cardano-node cardano-cli
cabal: Could not resolve dependencies:
[__0] trying: Win32-network-0.1.0.0 (user goal)
[__1] next goal: base (dependency of Win32-network)
[__1] rejecting: base-4.13.0.0/installed-4.13.0.0 (conflict: Win32-network =>
base>=4.5 && <4.13)
[__1] rejecting: base-4.12.0.0, base-4.11.1.0, base-4.11.0.0, base-4.10.1.0,
base-4.10.0.0, base-4.9.1.0, base-4.9.0.0, base-4.8.2.0, base-4.8.1.0,
base-4.8.0.0, base-4.7.0.2, base-4.7.0.1, base-4.7.0.0, base-4.6.0.1,
base-4.6.0.0, base-4.5.1.0, base-4.5.0.0, base-4.4.1.0, base-4.4.0.0,
base-4.3.1.0, base-4.3.0.0, base-4.2.0.2, base-4.2.0.1, base-4.2.0.0,
base-4.1.0.0, base-4.0.0.0, base-3.0.3.2, base-3.0.3.1 (constraint from
non-upgradeable package requires installed instance)
[__1] fail (backjumping, conflict set: Win32-network, base)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, Win32-network
Boom! It failed again. Let’s try building different tags.
git checkout tags/1.0.0
Previous HEAD position was 76d321b7 Merge #780
HEAD is now at d5294cd0 enable rtsopts
wrek-system-product-name% cabal install cardano-node cardano-cli
cabal: Could not resolve dependencies:
[__0] trying: canonical-json-0.6.0.0 (user goal)
[__1] trying: base-4.13.0.0/installed-4.13.0.0 (dependency of canonical-json)
[__2] next goal: cardano-config (user goal)
[__2] rejecting: cardano-config-0.1.0.0 (conflict:
base==4.13.0.0/installed-4.13.0.0, cardano-config => base>=4.12 && <4.13)
[__2] fail (backjumping, conflict set: base, cardano-config)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, cardano-config, canonical-json
No cigar. Another one:
$ git checkout tags/1.9.0
Previous HEAD position was 15de948f Merge #440
HEAD is now at 81878d59 Merge #729
$ cabal install cardano-node cardano-cli
cabal: Could not resolve dependencies:
[__0] trying: Win32-network-0.1.0.0 (user goal)
[__1] next goal: base (dependency of Win32-network)
[__1] rejecting: base-4.13.0.0/installed-4.13.0.0 (conflict: Win32-network =>
base>=4.5 && <4.13)
[__1] rejecting: base-4.12.0.0, base-4.11.1.0, base-4.11.0.0, base-4.10.1.0,
base-4.10.0.0, base-4.9.1.0, base-4.9.0.0, base-4.8.2.0, base-4.8.1.0,
base-4.8.0.0, base-4.7.0.2, base-4.7.0.1, base-4.7.0.0, base-4.6.0.1,
base-4.6.0.0, base-4.5.1.0, base-4.5.0.0, base-4.4.1.0, base-4.4.0.0,
base-4.3.1.0, base-4.3.0.0, base-4.2.0.2, base-4.2.0.1, base-4.2.0.0,
base-4.1.0.0, base-4.0.0.0, base-3.0.3.2, base-3.0.3.1 (constraint from
non-upgradeable package requires installed instance)
[__1] fail (backjumping, conflict set: Win32-network, base)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, Win32-network
No luck.
Let’s update the Ubuntu packages and retry everything exactly as in the IOHK instructions.
$ sudo apt-get update -y
$ sudo apt-get -y install build-essential pkg-config libffi-dev libgmp-dev libssl-dev libtinfo-dev libsystemd-dev zlib1g-dev make g++ tmux git jq wget libncursesw5 -y
$ wget https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz
$ tar -xf cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz
$ rm cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz cabal.sig
$ mkdir -p ~/.local/bin
$ mv cabal ~/.local/bin/
$ cabal update
$ wget https://downloads.haskell.org/~ghc/8.6.5/ghc-8.6.5-x86_64-deb9-linux.tar.xz
$ tar -xf ghc-8.6.5-x86_64-deb9-linux.tar.xz
$ rm ghc-8.6.5-x86_64-deb9-linux.tar.xz
$ cd ghc-8.6.5
$ ./configure
$ ls cardano-node
$ cd cardano-node
$ git fetch --all --tags
$ git checkout tags/1.10.0
$ cabal install cardano-node cardano-cli
Wrote tarball sdist to
/home/you/cryptos/cardano/cardano-node/dist-newstyle/sdist/cardano-config-0.1.0.0.tar.gz
cabal: filepath wildcard 'README.md' does not match any files.
Boom!
It worked. Let’s try to run cardano-node:
$ scripts/mainnet.sh
There it is! Working like a charm!
Running the cardano-node Docker Image
Containers work like magic, especially with projects which have large and complicated build instructions. In this case, we’ve got good news : IOHK provides official Docker images that you can just download and run! The cardano-node Docker image comes with everything pre-built, so you can just pull the image and run it with minimal setup.
Note on cryptocurrency Docker images: Always be extra careful when deploying Docker images for cryptocurrency wallets and full nodes – any cryptocurrency, not Cardano specifically, but the same precaution applies to cardano-node on Docker.
When you download the cardano-node
Docker image, double check the spelling to make sure you’re downloading from the inputoutput
organization. Do not trust images from non-official sources unless you absolutely trust the source.
First, download cardano-node Docker image:
docker pull inputoutput/cardano-node
Now run the cardano-node Docker image:
docker run -v /data -e NETWORK=mainnet inputoutput/cardano-node
You can also run a more complete version of the command, passing in the topology, config and database path:
docker run -v $PWD/configuration/defaults/byron-mainnet:/configuration \
inputoutput/cardano-node run \
--config /configuration/configuration.yaml \
--topology /configuration/topology.json \
--database-path /db
Links
IOHK Build Instructions (These work!)
Build and Run Instructions (Neat tutorial.)
Making a Shelley blockchain from scratch
Cardano Haskell Node at Github
Shelley Stakepool Pioneers Exercise Sheet 1