|
| 1 | +******************************************** |
| 2 | +Contributing to the ``cardano-node`` project |
| 3 | +******************************************** |
| 4 | + |
| 5 | +The ``cardano-node`` development is primarily based on the Nix infrastructure (https://nixos.org/ ), which enables packaging, CI, development environments and deployments. |
| 6 | + |
| 7 | +On how to set up Nix for ``cardano-node`` development, please see `Building Cardano Node with nix <https://github.com/input-output-hk/cardano-node/tree/master/doc/getting-started/building-the-node-using-nix.md>`_. |
| 8 | + |
| 9 | +Supplementary tooling |
| 10 | +==== |
| 11 | + |
| 12 | +GHCID |
| 13 | +---- |
| 14 | + |
| 15 | +run *ghcid* with: ``ghcid -c "cabal repl exe:cardano-node --reorder-goals"`` |
| 16 | + |
| 17 | +Haskell Language Server |
| 18 | +---- |
| 19 | + |
| 20 | +When using Haskell Language Server with Visual Studio Code, you may find that |
| 21 | +`HLINT annotations are ignored <https://github.com/haskell/haskell-language-server/issues/638>`_. |
| 22 | + |
| 23 | +To work around this, you may run the script ``./scripts/reconfigure-hlint.sh`` to generate a ``.hlint.yaml`` |
| 24 | +file with HLINT ignore rules derived from the source code. |
| 25 | + |
| 26 | +Testing |
| 27 | +==== |
| 28 | + |
| 29 | +``cardano-node`` is essentially a container which implements several components such networking, consensus, and storage. These components have individual test coverage. The node goes through integration and release testing by Devops/QA while automated CLI tests are ongoing alongside development. |
| 30 | + |
| 31 | +Developers on ``cardano-node`` can `launch their own testnets <doc/getting-started/launching-a-testnet.md>`_ or `run the chairman tests <doc/getting-started/running-chairman-tests.md>`_ locally. |
| 32 | + |
| 33 | +Debugging |
| 34 | +==== |
| 35 | + |
| 36 | +Pretty printing CBOR encoded files |
| 37 | +---- |
| 38 | + |
| 39 | +It may be useful to print the on chain representations of blocks, delegation certificates, txs and update proposals. There are two commands that do this (for any cbor encoded file): |
| 40 | + |
| 41 | +To pretty print as CBOR: |
| 42 | +``cabal exec cardano-cli -- pretty-print-cbor --filepath CBOREncodedFile`` |
| 43 | + |
| 44 | +Validate CBOR files |
| 45 | +---- |
| 46 | + |
| 47 | +You can validate Byron era blocks, delegation certificates, txs and update proposals with the ``validate-cbor`` command. |
| 48 | + |
| 49 | +``cabal exec cardano-cli -- validate-cbor --byron-block 21600 --filepath CBOREncodedByronBlockFile`` |
| 50 | + |
| 51 | +Updating dependencies |
| 52 | +==== |
| 53 | + |
| 54 | +... from Hackage |
| 55 | +---- |
| 56 | + |
| 57 | +Updating package dependencies from Hackage should work like normal in a Haskell project. |
| 58 | +The most important thing to note is that we pin the ``index-state`` of the Hackage package index in ``cabal.project``. |
| 59 | +This means that cabal will always see Hackage “as if” it was that time, ensuring reproducibility. |
| 60 | +But it also means that if you need a package version that was released *after* that time, you need to bump the ``index-state`` (and to run ``cabal update`` locally). |
| 61 | + |
| 62 | +Because of how we use Nix to manage our Haskell build, whenever you do this you will also need to pull in the Nix equivalent of the newer ``index-state``. |
| 63 | +You can do this by running ``nix flake lock --update-input hackageNix``. |
| 64 | + |
| 65 | +... from the Cardano package repository |
| 66 | +---- |
| 67 | + |
| 68 | +Many Cardano packages are not on Hackage and are instead in the `Cardano package repository <https://github.com/input-output-hk/cardano-haskell-packages>`__, see the README for (lots) more information. |
| 69 | +Getting new packages from there works much like getting them from Hackage. |
| 70 | +The differences are that it has an independent ``index-state``, and that there is a different Nix command you need to run afterwards: ``nix flake lock --update-input CHaP``. |
| 71 | + |
| 72 | +Using unreleased versions of dependencies |
| 73 | +~~~~ |
| 74 | + |
| 75 | +Sometimes we need to use an unreleased version of one of our dependencies, either to fix an issue in a package that is not under our control, or to experiment with a pre-release version of one of our own packages. |
| 76 | +You can use a ``source-repository-package`` stanza to pull in the unreleased version. |
| 77 | +Try only to do this for a short time, as it does not play very well with tooling, and will interfere with the ability to release the node itself. |
| 78 | + |
| 79 | +For packages that we do not control, we can end up in a situation where we have a fork that looks like it will be long-lived or permanent (e.g. the maintainer is unresponsive, or the change has been merged but not released). |
| 80 | +In that case, release a patched version to the `Cardano package repository <https://github.com/input-output-hk/cardano-haskell-packages>`__, which allows us to remove the ``source-repository-package`` stanza. |
| 81 | +See the README for instructions. |
| 82 | + |
| 83 | +Releasing a version of the node |
| 84 | +==== |
| 85 | + |
| 86 | +(There is much more to say here, this is just a small fragment) |
| 87 | + |
| 88 | +... to the Cardano package repository |
| 89 | +---- |
| 90 | + |
| 91 | +When releasing a new version of the node, it and the other packages in this repository should be released to the `Cardano package repository <https://github.com/input-output-hk/cardano-haskell-packages>`__. |
| 92 | +See the README for instructions, including a script to automate most of the process. |
| 93 | +Please note that libraries need bounds on the version of their dependencies to avoid bitrot and be effectively reusable. |
| 94 | + |
| 95 | +Workbench: a local cluster playground |
| 96 | +==== |
| 97 | + |
| 98 | +You can quickly spin up a local cluster (on Linux and Darwin), based on any of a wide variety of configurations, and put it under a transaction generation workload -- using the ``workbench`` environment: |
| 99 | + |
| 100 | +1. Optional: choose a workbench profile: |
| 101 | + - ``default`` stands for a light-state, 6-node cluster, under saturation workload, indefinite runtime |
| 102 | + - ``ci-test`` is the profile run in the node CI -- very light, just two nodes and short runtime |
| 103 | + - ``devops`` is an unloaded profile (no transaction generation) with short slots -- ``0.2`` sec. |
| 104 | + - ..and many more -- which can be either: |
| 105 | + - listed, by ``make ps`` |
| 106 | + - observed at their point of definition: `nix/workbench/profiles/prof1-variants.jq <https://github.com/input-output-hk/cardano-node/tree/master/nix/workbench/profiles/prof1-variants.jq#L333-L526>`_ |
| 107 | +2. Optional: select mode of operation, by optionally providing a suffix: |
| 108 | + - default -- no suffix -- just enter the workbench shell, allowing you to run ``start-cluster`` at any time. Binaries will be built locally, by ``cabal``. |
| 109 | + - ``autostay`` suffix -- enter the workbench shell, start the cluster, and stay in the shell afterwards. Binaries will be built locally, by ``cabal``. |
| 110 | + - ``autonix`` suffix -- enter the workbench shell, start the cluster. All binaries will be provided by the Nix CI. |
| 111 | + - ..there are other modes, as per `lib.mk <https://github.com/input-output-hk/cardano-node/tree/master/lib.mk>`_ |
| 112 | +3. Enter the workbench shell for the chosen profile & mode: |
| 113 | + ``make <PROFILE-NAME>`` or ``make <PROFILE-NAME>-<SUFFIX>`` (when there is a suffix). |
| 114 | +4. Optional: start cluster: |
| 115 | + Depending on the chosen mode, your cluster might already start, or you are expected to start it yourself, using ``start-cluster``. |
| 116 | + |
| 117 | +The workbench services are available only inside the workbench shell. |
| 118 | + |
| 119 | +Using Cabal |
| 120 | +---- |
| 121 | + |
| 122 | +By default, all binaries originating in the ``cardano-node`` repository are available to ``cabal build`` and ``cabal run``, unless the workbench was entered using one of the pure ``*nix`` modes. Note that in all cases, the dependencies for the workbench are supplied though Nix and have been built/tested on CI. |
| 123 | + |
| 124 | +**Dependency localisation** -or- *Cabal&Nix for painless cross-repository work* |
| 125 | +---- |
| 126 | + |
| 127 | +The Cabal workflow described above only extends to the repository-local packages. Therefore, ordinarily, to work on ``cardano-node`` dependencies in the context of the node itself, one needs to go through an expensive multi-step process -- with committing, pushing and re-pinning of the dependency changes. |
| 128 | + |
| 129 | +The **dependency localisation** workflow allows us to pick a subset of leaf dependencies of the ``cardano-node`` repository, and declare them *local* -- so they can be iterated upon using the ``cabal build`` / ``cabal run`` of ``cardano-node`` itself. This cuts development iteration time dramatically and enables effective cross-repo development of the full stack of Cardano packages. |
| 130 | + |
| 131 | +Without further ado (**NOTE**: *the order of steps is important!*): |
| 132 | + |
| 133 | +1. Ensure that your ``cardano-node`` checkout is clean, with no local modifications. Also, ensure that you start outside the node's Nix shell. |
| 134 | +2. Check out the repository with the dependencies, *beside* the ``cardano-node`` checkout. You have to check out the git revision of the dependency used by your ``cardano-node`` checkout -- as listed in ``cardano-node/cabal.project``. |
| 135 | + - we'll assume the ``ouroboros-network`` repository |
| 136 | + - ..so a certain parent directory will include checkouts of both ``ouroboros-network`` and ``cardano-node``, at the same level |
| 137 | + - ..and the git revision checked out in ``ouroboros-network`` will match the version of the ``ouroboros-network`` packages used currently |
| 138 | + - Extra point #1: you can localise/check out several dependency repositories |
| 139 | + - Extra point #2: for the dependencies that are not listed in ``cabal.project`` of the node -- how do you determine the version to check out? You can ask the workbench shell: |
| 140 | + 1. Temporarily enter the workbench shell |
| 141 | + 2. Look for the package version in ``ghc-pkg list`` |
| 142 | + 3. Use that version to determine the git revision of the dependency's repository (using a tag or some special knowledge about the version management of said dependency). |
| 143 | +3. Enter the workbench shell, as per instructions in previous sections -- or just a plain Nix shell. |
| 144 | +4. Ensure you can build ``cardano-node`` with Cabal: ``cabal build exe:cardano-node``. If you can't something else is wrong. |
| 145 | +5. Determine the *leaf dependency set* you will have to work on. The *leaf dependency set* is defined to include the target package you want to modify, and its reverse dependencies -- that is, packages that depend on it (inside the dependency repository). |
| 146 | + - let's assume, for example, that you want to modify ``ouroboros-consensus-shelley`` |
| 147 | + - ``ouroboros-consensus-shelley`` is not a leaf dependency in itself, since ``ouroboros-consensus-cardano`` (of the same ``ouroboros-network`` repository) depends on it -- so the *leaf dependency set* will include both of them. |
| 148 | + - you might find out that you have to include a significant fraction of packages in ``ouroboros-network`` into this *leaf dependency set* -- do not despair. |
| 149 | + - if the *leaf dependency set* is hard to determine, you can use ``cabal-plan`` -- which is included in the workbench shell (which you, therefore, have to enter temporarily): |
| 150 | + .. code-block:: console |
| 151 | +
|
| 152 | + [nix-shell:~/cardano-node]$ cabal-plan dot-png --revdep ouroboros-consensus-shelley |
| 153 | +
|
| 154 | + This command will produce a HUGE ``deps.png`` file, which will contain the entire chart of the project dependencies. The important part to look for will be the subset of packages highlighted in red -- those, which belong to the ``ouroboros-network`` repository. This will be the full *leaf dependency set*. |
| 155 | +6. Edit the ``cardano-node/cabal.project`` as follows: |
| 156 | + - for the *leaf dependency set* in the very beginning of the ``cabal.project``, add their relative paths to the ``packages:`` section, e.g.: |
| 157 | + .. code-block:: console |
| 158 | +
|
| 159 | + packages: |
| 160 | + cardano-api |
| 161 | + cardano-cli |
| 162 | + ... |
| 163 | + trace-resources |
| 164 | + trace-forward |
| 165 | + ../ouroboros-network/ouroboros-consensus-shelley |
| 166 | + ../ouroboros-network/ouroboros-consensus-cardano |
| 167 | +
|
| 168 | +7. The two packages have now became **local** -- when you try ``cabal build exe:cardano-node`` now, you'll see that Cabal starts to build these dependencies you just localised. Hacking time! |
| 169 | + |
| 170 | +Hoogle |
| 171 | +---- |
| 172 | + |
| 173 | +The workbench shell provides ``hoogle``, with a local database for the full set of dependencies: |
| 174 | + |
| 175 | +.. code-block:: console |
| 176 | +
|
| 177 | + [nix-shell:~/cardano-node]$ hoogle search TxId |
| 178 | + Byron.Spec.Ledger.UTxO newtype TxId |
| 179 | + Byron.Spec.Ledger.UTxO TxId :: Hash -> TxId |
| 180 | + Cardano.Chain.UTxO type TxId = Hash Tx |
| 181 | + Cardano.Ledger.TxIn newtype TxId crypto |
| 182 | + Cardano.Ledger.TxIn TxId :: SafeHash crypto EraIndependentTxBody -> TxId crypto |
| 183 | + Cardano.Ledger.Shelley.API.Types newtype TxId crypto |
| 184 | + Cardano.Ledger.Shelley.API.Types TxId :: SafeHash crypto EraIndependentTxBody -> TxId crypto |
| 185 | + Cardano.Ledger.Shelley.Tx newtype TxId crypto |
| 186 | + Cardano.Ledger.Shelley.Tx TxId :: SafeHash crypto EraIndependentTxBody -> TxId crypto |
| 187 | + Ouroboros.Consensus.HardFork.Combinator data family TxId tx :: Type |
| 188 | + -- plus more results not shown, pass --count=20 to see more |
| 189 | +
|
0 commit comments