Skip to content

Commit

Permalink
Merge branch 'main' into amesgen/checkpointing-abstract
Browse files Browse the repository at this point in the history
  • Loading branch information
facundominguez authored Jan 24, 2024
2 parents bd7e442 + 706c4b1 commit a66b9ad
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 23 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
ghc: ["8.10.7", "9.6.3"]
ghc: ["8.10.7", "9.6.4"]
cabal: ["3.10.1.0"]
os: [ubuntu-latest]
env:
Expand Down Expand Up @@ -172,7 +172,7 @@ jobs:
if: |
github.event_name == 'push'
&& github.ref == 'refs/heads/main'
&& matrix.ghc=='9.6.3'
&& matrix.ghc=='9.6.4'
run: |
cabal build --dry-run --enable-tests all
./scripts/docs/haddocks.sh
Expand All @@ -182,7 +182,7 @@ jobs:
if: |
github.event_name == 'push'
&& github.ref == 'refs/heads/main'
&& matrix.ghc=='9.6.3'
&& matrix.ghc=='9.6.4'
uses: actions/upload-artifact@v4
with:
name: haddocks
Expand Down
11 changes: 10 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ We have two types of documentation:
- Markdown files, which can be found in the [docs](docs/website/contents)
directory. They contain information that is not strictly related to the code
itself, such as getting started guides, references, tutorials, etc.

They are rendered at the [Consensus
website](https://ouroboros-consensus.cardano.intersectmbo.org).
- [Haddock][haddock-site] comments. They contain more low level information
about the code and should be used as a reference, although we aim to provide
some context navigation (cross referencing modules) on the module
descriptions.

When starting to work on Consensus, we recommend to take a look at the following
resources:

- [Preflight guide](https://ouroboros-consensus.cardano.intersectmbo.org/docs/for-developers/PreflightGuide)
- [Glossary](https://ouroboros-consensus.cardano.intersectmbo.org/docs/for-developers/Glossary)

When adding or improving documentation about the implementation, it is
preferable to add haddock comments since they are closer to the code. However
not all documentation can be placed inside haddock comments, and in such cases
Expand Down Expand Up @@ -159,7 +168,7 @@ and improvements are always welcome.

## Formatting the code

We use `stylish-haskell` 0.14.5.0 for Haskell code formatting.
We use `stylish-haskell` 0.14.6.0 for Haskell code formatting.

Either enable editor integration or call the script used by CI itself:

Expand Down
181 changes: 181 additions & 0 deletions docs/website/contents/for-developers/PreflightGuide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# Preflight guide

> "What I Wish I Knew When Working In Consensus"
This document lists possible steps in getting familiar with the core of the Cardano universe with a focus on topics that are important for the daily life of a Consensus developer.

Every step has a clear **goal** as well as optional ideas for other activities.

This document contains various footnotes with additional information that can be safely skipped on a first pass.

If you have ideas for further steps, first check [this epic][preflight epic] to compare it with existing ideas, and then create a PR!

## Setting up a local node

The [cardano-node][] (usually just called "node") is the most important consumer[^other-consensus-consumers] of the Consensus and Storage layer maintained by the Consensus team.
It is *the* way to get a full copy of "the" blockchain for any given network[^cardano-node-purpose], in particular and most importantly, for **mainnet**. This process is called "syncing".

Having a local copy of the node is not absolutely essential for your daily work, but it can be useful in several cases:

- Assessing a change for correctness and performance problems by using the entire multi-year history of Cardano as a test case.
- Quickly gathering empirical statistics of quantities of interest, like minimum/average/maximum size/validation time/frequency of blocks.
- Directly accessing any on-chain data, like the current protocol version, stake distribution or UTxO size.

### Disclaimer

- The node is currently relatively resource-intensive[^resource-relative], see the minimum system requirements on the [node release page][].
- It uses a lot of memory, and the memory requirements are growing as the chain evolves[^utxo-hd].
- It inherently requires a lot of disk space (as of January 2024, 150GB).
- During syncing, it is quite CPU-intensive (albeit mostly only on a single core).
Once syncing is done, it is very light on CPU usage.
- You do not need to run the node at all times.
The stored blockchain can also be consumed by other developer tools that are independent of the node.
- Syncing can take multiple days (full sync in December 2023 on a decently powerful server: 2 days).
Unless your network connection is very slow compared to your CPU, the bottleneck is likely your CPU.
- It is safe to cleanly interrupt syncing, eg via <kbd>Ctrl</kbd> + <kbd>C</kbd>.
The node is able to gracefully resume on restart.

### Running the node

First, get a [cardano-node][] binary, see the README, eg via Nix, binary from the releases or compiling locally, depending on preferences and context.

A basic invocation looks like this:

```shell
./result/bin/cardano-node \
run \
--config /path/to/mainnet-config.yaml \
--database-path /path/to/db-mainnet \
--topology /path/to/mainnet-topology.json \
--host-addr 0.0.0.0 --port 3001 \
--socket-path /path/to/node.socket
```

- `--config`: Get the default Cardano mainnet configuration file [here][cardano mainnet conf].
- The logging system supports human-readable or JSON output (look for `ScText`/`ScJson`).
`ScJson` sometimes contains more information, and it can be handy for automatic processing via eg `jq`.
- Note that Genesis files are still mutable as long as their corresponding era is still in development (like Conway as of early 2024), so your configuration file might need changes once you update your node.
- `--topology`: This file defines how/when the node will connect to other nodes.
Get the default [here][cardano mainnet topo].

While syncing, it makes sense to set the valency, ie the number of nodes sampled from the given DNS name to connect to, to `1` for better performance.[^genesis-syncing]

Make sure to store the log output somewhere.

### Syncing to mainnet

Now you are ready to start syncing to mainnet!

During this long process, you can stare at the log output, and eg look for lines containing `Chain extended` or `AddedToCurrentChain`, which (at least) mention the slot number of the most recently added block.
Bonus points for a plot of your sync progress over time!

### Syncing faster 🚀

As seen above, syncing is relatively slow, and you might be in a situation where you haven't caught up to mainnet in maybe a couple of months, but don't want to wait several hours.
Here are two options:

- If do not mind a little extra clutter, it's possible to sync to mainnet in about two hours by using the [Mithril client][].
See [here][Mithril instructions] for instructions.
- Maybe someone you know has a very recent local copy of the mainnet ChainDB.
If you are sure you *really* trust them, ask them to send you their ChainDB (or at least the missing parts) via eg [Magic Wormhole][].

## Understanding ledger snapshots and using db-analyser

You need a local ChainDB for this step, see the previous step.

[db-analyser][] is a tool maintained by the Consensus team to gather information and investigate problems (especially performance-related) by analyzing a local ChainDB, providing a variety of analysis passes.

### Ledger snapshots

A *ledger snapshot* is the CBOR serialization of the (extended[^extended-ledger-state]) *ledger state*, which represents the summary of all blocks up to a specific point[^glossary], the tip point or point of the last applied block, that is necessary to judge the validity of any block extending the last applied block.
Here, "validity" refers most prominently to the ledger rules ("Does this person actually have enough money to make that payment?") of the [Cardano ledger].
On disk, the file name of a ledger snapshot usually contains the slot number of its tip point.

### Running db-analyser passes

Most [db-analyser][] passes need a ledger snapshot for the specified starting slot.
Read the [db-analyser][] documentation up to the [the corresponding example][db-analyser snapshot] to create a ledger snapshot for slot `4492800`[^first-shelley-slot].

Starting from there (using `--analyse-from 4492800`), try the following two db-analyser passes:

- `--show-slot-block-no --num-blocks-to-process 100`:
You will see that many slots do not contain a block; our Consensus protocols involve a _leader schedule_[^glossary] that determines which slots are allowed to contain blocks.
On average, there will be a block every $1/f$ slots, where $f$ is the _active slot coefficient_[^glossary].
On mainnet, we have $f=1/20$.
- `--benchmark-ledger-ops --num-blocks-to-process 1000`:
Look for the `mut_headerApply` and `mut_blockApply` columns, which are the bulk of the time that is spent when validating headers and blocks, respectively; in order to get a rough sense for these durations, as they are relevant in lots of situations.

Feel free to run other passes that sound interesting to you.

### Reusing ledger snapshots

The node regularly creates ledger snapshots while running.
You can reuse these snapshots in db-analyser, and vice versa.

> ‼️ Note that the format of ledger snapshots can change with every new ledger release, so in order for this to work, make sure that your db-analyser and your node use the same ledger version.
> Some ways to achieve this:
> - Click on the [release page][node release page] corresponding to your node, expand the "Individual packages' changelogs" section, and then check out the corresponding `ouroboros-consensus-cardano` release tag in the Consensus repo.
> - If you used Nix to get the `cardano-node` binary, you can use `nix build .#db-analyser` to get a compatible db-analyser, assuming you are in the root of the `cardano-node` repo.
>
> You might also run into this when you update the node to a newer version.
> The node will automatically detect this situation, and create a new ledger state starting from Genesis.[^apply-vs-reapply]
Use a ledger snapshot of your local node (make sure to add the `_db-analyser` suffix[^snapshot-suffix]) to run the two db-analyser passes again, but now starting at the slot of your ledger snapshot.

- The pattern of filled/unfilled slots will look very different to what you saw at the beginning of Shelley above.
This is due to the usage of _transitional Praos_ (TPraos) at the beginning of Shelley, where the leader schedule gradually transitioned from being fully centralized to fully decentralized.
It has been fully decentralized for several years now.
- Comparing the benchmarking results for block validation times, you should see that validating a typical block takes much longer today.
This is mainly due to larger allowed block sizes and this size being actually used, as well as more complex ledger rules (most prominently, Plutus smart contracts).

<!-- Footnotes -->

[^other-consensus-consumers]: Other important consumers include:

- [cardano-cli][], a CLI tool allowing to query various information about the current state of a running node, as well as submitting transactions.
- Indexers like [cardano-db-sync][] or [kupo][] store certain historical information (like old transactions) in an easily queryable format (in contrast to the node, which, by design, does not store information in ways that are unnecessary for its core responsibilities).
- Other services or tools that need to communicate with nodes, like [hydra][] or [ogmios][].

[^cardano-node-purpose]: Note however that this is not its only purpose; it is also required to actively participate in the ongoing evolution of any Cardano-based blockchain.

[^utxo-hd]: The main reason for this is that the ledger state, ie the aggregated information necessary to validate blocks, is currently fully stored in memory.
The Consensus team is currently working on *UTxO HD*, a solution to move the ledger state to disk.

[^resource-relative]: Cardano is not a huge outlier in either direction, there are many examples for blockchains that are either much less resource-intensive (due to very low activity or new age, or due to very fancy cryptography, like Mina) or much more resource-intensive (due to very old age and large accumulated history, like Bitcoin, or a hyperfocus on performance, like [Solana](https://docs.solana.com/running-validator/validator-reqs#hardware-recommendations)).

[^genesis-syncing]: As of early 2024, syncing is a fully trusted process; if any node you are syncing from is adversarial, you might end up on an adversarial chain.
There is an ongoing effort to implement *Ouroboros Genesis* in order to reduce this strong trust assumption; in particular, it will involve reaching out to lots of nodes while syncing.

[^glossary]: See the [Glossary][].

[^extended-ledger-state]: A ledger snapshot also contains the _header state_ in addition to the ledger state.
As a rough idea, this is the state maintained by Consensus protocol (in our case: Praos), and much more lightweight than the ledger state both in size and in time it takes to update.
An "extended" ledger state is a ledger state plus the header state, but people sometimes/often drop the "extended" prefix, especially for ledger snapshots, as there are no "unextended" ledger snapshots.

[^first-shelley-slot]: This is the first "Shelley" slot, see [here](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0059/feature-table.md).
All previous slots were "Byron" slots, which is a legacy era that is largely irrelevant for our work, except in the very annoying case where it isn't.

[^apply-vs-reapply]: It will be much faster than syncing from scratch, as the blocks are only _reapplied_ instead of _applied_.
This means that certain checks (in particular, evaluating smart contracts) are skipped, which is sound as we know that the blocks were already applied/validated fully previously.

[^snapshot-suffix]: db-analyser only ever reads/writes snapshots with a `_db-analyser` suffix in the file name, eg `4492800_db-analyser`.
The node itself will create snapshots without a suffix (eg `4492800`), but can also read snapshots with any suffix.
Crucially, the node won't ever *delete* snapshots with a suffix, as opposed to unsuffixed ones, which are periodically garbage-collected, as well as deleted if the node can't decode them.

[cardano-node]: https://github.com/IntersectMBO/cardano-node
[cardano-cli]: https://github.com/IntersectMBO/cardano-cli
[cardano-db-sync]: https://github.com/IntersectMBO/cardano-db-sync
[kupo]: https://github.com/cardanosolutions/kupo
[hydra]: https://github.com/input-output-hk/hydra
[ogmios]: https://github.com/CardanoSolutions/ogmios
[node release page]: https://github.com/IntersectMBO/cardano-node/releases
[cardano mainnet conf]: https://github.com/IntersectMBO/cardano-node/blob/master/configuration/cardano/mainnet-config.yaml
[cardano mainnet topo]: https://github.com/IntersectMBO/cardano-node/blob/master/configuration/cardano/mainnet-topology.json
[Mithril client]: https://mithril.network/doc
[Mithril instructions]: https://mithril.network/doc/manual/getting-started/bootstrap-cardano-node
[Magic Wormhole]: https://github.com/magic-wormhole/magic-wormhole
[db-analyser]: https://github.com/IntersectMBO/ouroboros-consensus/blob/main/ouroboros-consensus-cardano/README.md#db-analyser
[Cardano ledger]: https://github.com/IntersectMBO/cardano-ledger
[Glossary]: https://ouroboros-consensus.cardano.intersectmbo.org/docs/for-developers/Glossary
[db-analyser snapshot]: https://github.com/IntersectMBO/ouroboros-consensus/blob/main/ouroboros-consensus-cardano/README.md#saving-a-snapshot
[preflight epic]: https://github.com/IntersectMBO/ouroboros-consensus/issues/887
1 change: 1 addition & 0 deletions docs/website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const sidebars = {
'for-developers/QueryVersioning',
'for-developers/BootstrapPeersIER',
'for-developers/TechnicalReports',
'for-developers/PreflightGuide',
]
},
]
Expand Down
54 changes: 45 additions & 9 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions nix/haskell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let
};
hsPkgs = haskell-nix.cabalProject {
src = ./..;
compiler-nix-name = "ghc963";
compiler-nix-name = "ghc964";
flake.variants = {
ghc810 = { compiler-nix-name = lib.mkForce "ghc8107"; };
};
Expand All @@ -34,9 +34,6 @@ let
extraSrcFiles = [ "golden/${n}/**/*" ];
}) [ "byron" "shelley" "cardano" ]);
}
({ lib, pkgs, ... }: lib.mkIf pkgs.stdenv.hostPlatform.isWindows {
reinstallableLibGhc = false;
})
];
flake.variants = {
noAsserts = {
Expand Down
2 changes: 1 addition & 1 deletion nix/shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ hsPkgs.shellFor {
# This is the place for tools that are required to be built with the same GHC
# version as used in hsPkgs.
tools = lib.mapAttrs (_: t: t // { index-state = pkgs.tool-index-state; }) {
haskell-language-server = { version = "2.5.0.0"; };
haskell-language-server = { version = "2.6.0.0"; };
};

shellHook = ''
Expand Down
Loading

0 comments on commit a66b9ad

Please sign in to comment.