From 9ebf2d81d1a4fc0ff17d67f50f1deee196dcf297 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:00:09 -0500 Subject: [PATCH] Add NOMOS-FORK-CHOICE documentation --- nomos/raw/fork-choice.md | 165 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 nomos/raw/fork-choice.md diff --git a/nomos/raw/fork-choice.md b/nomos/raw/fork-choice.md new file mode 100644 index 0000000..674bea0 --- /dev/null +++ b/nomos/raw/fork-choice.md @@ -0,0 +1,165 @@ +--- +title: NOMOS-FORK-CHOICE +name: Nomos Fork Choice +status: raw +tags: nomos +editor: +contributors: +- Jimmy Debe +--- + +## Abstract + +This document describes the consensus mechanism of fork choice rule, +followed by nodes in the Cryptarchia protocol. +Cryptarchia implements two fork choice rules, +one during node bootstrapping +and the second fork choice once a node is connected to the network. + +## Background/Motivation + +In blockchain networks, +the consensus process may encounter multiple competing branches(forks) of the blockchain state. +A Nomos node maintains a local copy of the blockchain state and +connects to a set of peers to download new blocks. + +During bootstrapping, Cryptarchia v1 implements [Ouroboros Genesis](https://eprint.iacr.org/2018/378.pdf) and +[Ouroboros Praos](https://eprint.iacr.org/2017/573.pdf) for the fork choice mechanism. +These translate to two fork choice rules, +bootstrap rule and online rule. +This approach is meant to help nodes defend against malicious peers feeding false chains to download. +This calls for a more expensive fork choice rule that can differentiate between malicious long-range attacks and +the honest chain. + +### The Long Range Attack + +The protocol has time window for a node, who is the **lottery** leader winner, +to complete a new block. +Nodes with more stake have a higher probability of being selected thorigh the **lottery**. +The **lottery difficulty** is determined by protocol parameters and the node's stake. +The leadership lottery difficulty will adjust dynamically based on the total stake is participating in consensus. +The scenario, which NOMOS-FORK-CHOICE solves, +is when an adversary forks the chain and +generates a very sparse branch where he is the only winner for an epoch. +This fork would be very sparse since the attacker does not control a large amount of stake initially. + +Each epoch, +the lottery difficulty is adjusted based on participation in the previous epoch to maintain a target block rate. +When this happens on the adversary’s chain, +the lottery difficulty will plummet and +he will be able to produce a chain that has similar growth rate to the main chain. +The advantage is that his chain is more efficient. +Unlike the honest chain, +which needs to deal with unintentional forks caused by network delays, +the adversary’s branch has no wasted blocks. + +With this advantage, +the adversary can eventually make up for that sparse initial period and +extend his fork until it’s longer than the honest chain. +He can then convince bootstrapping nodes to join his fork where he has had a monopoly on block rewards. + +#### Genesis Fork Choice Rule Mitigation + +When the honest branch and the adversary branch are in the period immediately following the fork, +the honest chain is dense and +the adversary’s fork will be quite sparse. +If an honest node had seen the adversary’s fork in that period, +it would not have followed this fork since the honest chain would be longer, +so selecting the fork using the longest chain rule is fine for a short range fork. + +If an honest node sees the adversary’s fork after he’s completed the attack, +the longest chain rule is no longer enough to protect them. +Instead, the node can look at the density of both chains in that short period after they diverge and +select the chain with the higher density of blocks. + +#### Praos Fork Choice Rule Mitigation + +Under two assumptions: + +1. A node has successfully bootstrapped and found the honest chain. +2. Nodes see honest blocks reasonably quickly. + +Nodes will remain on the honest chain if they reject forks that diverge further back than $k$ blocks, +without further inspection. +In order for an adversary to succeed, +they would need to build a $k$-deep chain faster then the time it takes the honest nodes to grow the honest chain by $k$ blocks. +The adversary must build this chain live, +alongside the honest chain. +They cannot build this chain after-the-fact, +since online nodes will be rejecting any fork that diverges before their $k$-deep block. + +## Specification + +The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, +“SHOULD NOT”, “RECOMMENDED”, “MAY”, and +“OPTIONAL” in this document are to be interpreted as described in [2119](https://www.ietf.org/rfc/rfc2119.txt). + +### Definitions + +- $k$ : safety parameter, i.e. the depth at which a block is considered immutable +- $s_{gen}$ : sufficient time measured in slots to measure the density of block production with enough statistical significance. + +In practice, $s_{gen} = \frac{k}{4f}$, where $f$ is the active slot coefficient from the leader lottery, +see [Theorem 2 of Badertscher et al., 2018 “Ouroborus Genesis”](https://eprint.iacr.org/2018/378.pdf)*)* + +### Bootstrap Fork Choice Rule + +During bootstrapping, the Ouroboros Genesis fork choice rule (`maxvalid-bg`) + +```python + +def bootstrap_fork_choice(c_local, forks, k, s_gen): + c_max = c_local + for c_fork in forks: + depth_max, depth_fork = common_prefix_depth(c_max, c_fork): + if depth_max <= k: + # the fork depth is less than our safety parameter `k`. It's safe + # to use longest chain to decide the fork choice. + if depth_max < depth_fork + # strict inequality to ensure to choose first-seen chain as the tie break + c_max = c_fork + else: + # here the fork depth is larger than our safety parameter `k`. + # It's unsafe to use longest chain here, instead check the density + # of blocks immediately after the divergence. + if density(c_max, depth_max, s_gen) < density(c_fork, depth_fork, s_gen): + # The denser chain immediately after the divergence wins. + c_max = c_fork + +``` + +### Online Fork Choice Rule + +When `bootstrap-rule` is complete, +a node SHOULD switch to the `online-rule`, +see [CRYPTARCHIA-V1-BOOTSTRAPPING-SYNCHRONIZATION]() for more infomation on bootstrapping. +With the `online-rule` flag, +the node SHOULD now reject any forks that diverge further back than $k$ blocks. + +```python +def online_fork_choice(c_local, forks, k): + c_max = c_local + for c_fork in forks: + depth_max, depth_fork = common_prefix_depth(c_max, c_fork): + if depth_max <= k: + # the fork depth is less than our safety parameter `k`. It's safe + # to use longest chain to decide the fork choice. + if depth_max < depth_fork + # strict inequality to ensure to choose first-seen chain as our tie break + c_max = c_fork + else: + # The fork depth is larger than our safety parameter `k`. + # Ignore this fork. + continue + +``` + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## Reference + +- [Ouroboros Genesis](https://eprint.iacr.org/2018/378.pdf) +- [Ouroboros Praos](https://eprint.iacr.org/2017/573.pdf) +-