Add Cryptarchia v1 Bootstrap and Synchronization specification

Raw specification transcribed from source document covering:
- Bootstrap Protocol for new nodes joining the network
- Chain Synchronization mechanisms
- Fork resolution and chain selection rules
This commit is contained in:
Cofson
2025-12-21 17:10:17 +01:00
parent b2f35644a4
commit a5a37c5d5e

View File

@@ -0,0 +1,452 @@
---
title: CRYPTARCHIA-V1-BOOTSTRAPPING-SYNCHRONIZATION
name: Cryptarchia v1 Bootstrapping & Synchronization
status: raw
category: Standards Track
tags: nomos, cryptarchia, bootstrapping, synchronization, consensus
editor: Youngjoon Lee <youngjoon@status.im>
contributors:
- David Rusu <david@status.im>
- Giacomo Pasini <giacomo@status.im>
- Álvaro Castro-Castilla <alvaro@status.im>
- Daniel Sanchez Quiros <daniel@status.im>
---
## Abstract
This document specifies the bootstrapping and synchronization protocol
for Cryptarchia v1 consensus.
When a new node joins the network or a previously-bootstrapped node has been offline,
it MUST catch up with the most recent honest chain
by fetching missing blocks from peers before listening for new blocks.
The protocol defines mechanisms for setting fork choice rules,
downloading blocks, and handling orphan blocks
while mitigating long range attacks.
## Semantics
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in RFC 2119.
## Introduction
When a new node joins the network or a previously-bootstrapped node has been offline
for a while,
it cannot follow the most recent honest chain solely by receiving only new blocks
because those new blocks cannot be added to the block tree
that does not have their parent block.
These nodes MUST first catch up with the most recent honest chain
by fetching missing blocks from their peers
before they start listening for new blocks.
This document specifies a protocol for nodes to bootstrap with the honest chain
efficiently while mitigating long range attacks.
It also defines how to handle the case which the node falls behind
after the bootstrapping is complete.
This protocol adheres to the key invariant:
We MUST never roll back blocks that are deeper than the latest immutable block
$B_\text{imm}$ in the local chain $c_{loc}$,
as defined in Cryptarchia v1 Protocol Specification.
## Overview
This protocol defines the bootstrapping mechanism
that covers all of the following cases:
- From the **Genesis** block
- From the **checkpoint** block obtained from a trusted checkpoint provider
- From the **local block tree**
(with $B_\text{imm}$ newer than the Genesis and the checkpoint)
Additionally, the protocol defines the synchronization mechanism
that handles orphan blocks while listening for new blocks
after the bootstrapping is completed.
The protocol consists of the following key components:
- Determining the fork choice rule (Bootstrap or Online) at startup
- Switching the fork choice rule from Bootstrap to Online
- Downloading blocks from peers
Upon startup, a node **determines the fork choice rule**,
as defined in Setting the Fork Choice Rule.
If the Bootstrap rule is selected, it is maintained for the Prolonged Bootstrap Period,
after which the node switches to the Online rule.
Using the fork choice rule chosen, the node **downloads blocks**
to catch up with the tip of the local chain $c_{loc}$ of each peer.
After downloading is done, the node starts **listening for new blocks**.
Upon receiving a new block, the node validates and adds it to its local block tree.
If the ancestors of the block are missing from the local block tree,
the node downloads missing ancestors using the same mechanism as above.
## Protocol
### Constants
| Constant | Name | Description | Value |
|----------|------|-------------|-------|
| $T_\text{offline}$ | Offline Grace Period | A period during which a node can be restarted without switching to the Bootstrap rule. | 20 minutes |
| $T_\text{boot}$ | Prolonged Bootstrap Period | A period during which Bootstrap fork choice rule must be continuously used after Initial Block Download is completed. This gives nodes additional time to compare their synced chain with a broader set of peers. | 24 hours |
| $s_\text{gen}$ | Density Check Slot Window | A number of slots used by density check of Bootstrap rule. This constant is defined in Cryptarchia Fork Choice Rule - Definitions. | $\lfloor\frac{k}{4f}\rfloor$ (=4h30m) |
### Setting the Fork Choice Rule
Upon startup, a node sets the fork choice rule to the **Bootstrap** rule
in one of the following cases.
Otherwise, the node uses the **Online** fork choice rule.
- **A node is starting with $B_\text{imm}$ set to the Genesis block
or from a checkpoint block.**
The node is setting its latest immutable block $B_\text{imm}$
to the Genesis or a checkpoint,
which clearly indicates that the node intends to catch up with the subsequent blocks.
Regardless of how many subsequent blocks remain,
the node SHOULD use the Bootstrap rule to mitigate long range attacks.
- **A node is restarting after being offline longer than $T_\text{offline}$ (20 minutes).**
Unlike starting from Genesis or checkpoint, in the case where a node is restarted
while preserving its existing block tree,
the node MUST choose a fork choice rule depending on how long it has been offline.
If it is certain that a node has been offline longer than the offline grace period
$T_\text{offline}$ since it last used the Online rule,
the node uses the Bootstrap rule upon startup.
Otherwise, it starts with the Online rule.
Details of $T_\text{offline}$ are described in Offline Grace Period.
A recommended way how to measure the offline duration
is introduced in Offline Duration Measurement.
- **A node operator set the Bootstrap rule explicitly (e.g., by `--bootstrap` flag).**
In any case where the node operator is clearly aware that the node has fallen behind
by more than $k$ blocks,
they SHOULD be able to start the node with the Bootstrap rule.
For example, the operator may obtain the latest block height
from another trusted operator
and realize that their node has fallen significantly behind due to some issue.
### Initial Block Download
If peers for Initial Block Download (IBD) are configured,
a node performs IBD by downloading blocks to catch up with the tip
of the local chain $c_{loc}$ of each peer
using the fork choice rule chosen in Setting the Fork Choice Rule.
Blocks are downloaded in parent-to-child order,
as defined in the Downloading Blocks mechanism.
This mechanism applies not only when a node starts from the Genesis block,
but also when it already has the local block tree (or a checkpoint block).
```python
def initial_block_download(peers, local_tree):
# In real implementation, these downloadings can be run in parallel.
# Also, any optimization can be applied to minimize downloadings,
# such as grouping peers by tip.
for peer in peers:
download_blocks(local_tree, peer, target_block=None)
```
The downloaded blocks are validated and added to the local block tree
using the fork choice rule determined above.
According to Cryptarchia v1 Protocol Specification - Block Header Validation,
the downloaded blocks are validated and added to the local block tree
using the fork choice rule determined above.
If all IBD peers become unavailable before the node catches up
with at least one of the IBD peers,
the node is terminated with an error,
allowing the operator to restart the node with other IBD peers.
If downloading is done successfully,
the node starts listening for new blocks as described in Listening for New Blocks.
### Prolonged Bootstrap Period
After Initial Block Download is completed,
a node MUST maintain the Bootstrap fork choice rule during the Bootstrap Period $T_\text{boot}$,
if the node chose the Bootstrap rule at Setting the Fork Choice Rule.
The purpose of the Prolonged Bootstrap Period is giving a syncing node
additional time
to compare its synced chain with a broader set of peers.
In other words, it provides the node with an opportunity
to connect to different peers
and verify whether they are on the same chain.
If the syncing node has downloaded blocks only from peers within an isolated network,
the result of Initial Block Download may not reflect the honest chain
followed by the majority of the entire network.
To resolve such situations, the node SHOULD continue using the Bootstrap rule
while discovering additional peers,
allowing it to switch to a better chain if one is found.
Theoretically, the Bootstrap rule should be prolonged
until the node has seen a sufficient number of blocks
beyond the $s_\text{gen}$ slot window,
which is required for the density check of the Bootstrap rule to be meaningful.
However, if the node has seen a fork longer than $k$ blocks
from its divergence block during Initial Block Download,
it means that the node has already seen more slots than $s_\text{gen}$
with very high probability, considering the small size of $s_\text{gen} = k/(4f)$.
If the node has never seen any fork longer than $k$ blocks,
it means that all forks could have been handled by the longest chain rule,
which is part of the Bootstrap rule.
Therefore, this protocol does not explicitly wait $s_\text{gen}$ slots
after Initial Block Download.
In other words, the protocol does not use $s_\text{gen}$
to configure the Prolonged Bootstrap Period.
This protocol configures the Bootstrap Period to 24 hours.
A timer MUST be started when Listening for New Blocks is started
after Initial Block Download is completed.
Once the timer is completed, the fork choice rule is switched to the Online rule.
### Listening for New Blocks
Once Initial Block Download is complete and Prolonged Bootstrap Period is started,
a node starts listening for new blocks relayed by its peers.
Upon receiving a new block,
the node tries to validate and add it to its local block tree,
as defined in Cryptarchia v1 Protocol Specification - Chain Maintenance.
If the parent of the block is missing from the local block tree,
the block cannot be fully validated and added.
These blocks are called *orphan blocks*.
To handle an orphan block,
the node downloads missing blocks from a randomly selected peer,
as described in Downloading Blocks.
If the request fails, the node MAY retry with different peers
before abandoning the orphan block.
The retry policy can be configured by implementers.
Note that downloading missing blocks does not need to be triggered
if it is clear that the orphan block is in a fork
diverged before the latest immutable (committed) block,
as the node MUST never revert immutable blocks.
```python
def listen_and_process_new_blocks(fork_choice: ForkChoice,
local_tree: Tree,
peers: List[Node]):
for block in listen_for_new_blocks():
try:
# Run the chain maintenance defined in the Cryptarchia spec.
local_tree.on_block(block, fork_choice)
except InvalidBlock:
continue
except ParentNotFound:
# Ignore the orphan block proactively,
# if it's clear that the orphan block is in a fork
# behind the latest immutable block
# because immutable blocks should never be reverted.
# This check doesn't cover all cases, but the uncovered cases
# will be handled by the Cryptarchia block validation
# during the `download_blocks` below.
if block.height <= local_tree.latest_immutable_block().height:
continue
# In real implementation, downloading can be run in background
# with the retry policy.
download_blocks(local_tree, random.choice(peers),
target_block=block.id)
```
### Downloading Blocks
For performing Initial Block Download and handling orphan blocks
while Listening for New Blocks,
a node sends a `DownloadBlocksRequest` to a peer,
which MUST respond with blocks in parent-to-child order.
This communication should be implemented based on Libp2p streaming.
#### Libp2p Protocol ID
- Mainnet: `/nomos/cryptarchia/sync/1.0.0`
- Testnet: `/nomos-testnet/cryptarchia/sync/1.0.0`
```python
class DownloadBlocksRequest:
# Ask blocks up to the target block.
# The response may not contain the target block
# if the responder limits the number of blocks returned.
# In that case, the requester must repeat the request.
target_block: BlockId
# To allow the peer to determine the starting block to return.
known_blocks: KnownBlocks
class KnownBlocks:
local_tip: BlockId
latest_immutable_block: BlockId
# Additional known blocks.
# A responder will reject a request if this list contains more than 5.
additional_blocks: list[BlockId]
class DownloadBlocksResponse:
# A stream of blocks in parent-to-child order.
# The max number of blocks to be returned can be limited by implementers.
# A requester can read the stream until the stream returns "NoMoreBlock".
blocks: Stream[Block | "NoMoreBlock"]
```
The responding peer uses `KnownBlocks` to determine the optimal starting block
for the response stream, aiming to minimize the number of blocks to be returned.
The requesting node can include any block it believes could assist in this process
to the `KnownBlocks.additional_blocks`.
To avoid spamming responders,
the size of `KnownBlocks.additional_blocks` is limited to 5.
The responding peer finds the latest common ancestor (i.e. LCA)
between the `target_block` and each of the known blocks.
Then, it returns a stream of blocks, starting from the highest LCA.
To mitigate malicious downloading requests,
the peer limits the number of blocks to be returned.
The detailed implementation is up to implementers,
depending on their internal architecture (e.g. storage design).
The requesting node SHOULD repeat `DownloadBlocksRequest`s
by updating the `KnownBlocks` in order to download the next batches of blocks.
The following code shows how the requesting node can be implemented.
```python
def download_blocks(local_tree: Tree, peer: Node,
target_block: Optional[BlockId]):
latest_downloaded: Optional[Block] = None
while True:
# Fetch the peer's tip if target is not specified.
target_block = target_block if target_block is not None else peer.tip()
# Don't start downloading if target is already in local.
if local_tree.has(target_block):
return
req = DownloadBlocksRequest(
# If target_block is None, specify the current peer's tip
# each time when we build DownloadBlocksRequest,
# so that we can catch up with the most recent peer's tip.
target_block=target_block,
known_blocks=KnownBlocks(
local_tip=local_tree.tip().id,
latest_immutable_block=local_tree.latest_immutable_block().id,
# Provide the latest downloaded block as well
# to avoid downloading duplicate blocks
additional_blocks=[latest_downloaded.id]
if latest_downloaded is not None else [],
)
)
resp = send_request(peer, req)
for block in resp.blocks():
latest_downloaded = block
try:
# Run the chain maintenance defined in the Cryptarchia spec.
local_tree.on_block(block)
# Early stop if the target has been reached.
if block == req.target_block:
break
except:
return
```
If the node is continuing from a previous `DownloadBlocksRequest`,
it is important to include the latest downloaded block
to the `KnownBlocks.additional_blocks` to avoid downloading duplicate blocks.
If the requesting node is downloading blocks up to the peer's tip $c_{loc}$
(e.g. Initial Block Download) by repeating `DownloadBlocksRequest`s,
the $c_{loc}$ may switch between requests.
The algorithm described above also handles this case
by specifying the most recent peer's tip each time
when a `DownloadBlocksRequest` is constructed.
### Bootstrapping from Checkpoint
Instead of bootstrapping from the Genesis block or from the local block tree,
a node can choose to bootstrap the honest chain
starting from a checkpoint block obtained from a trusted checkpoint provider.
In this case, the node fully trusts the checkpoint provider
and considers blocks deeper than the checkpoint block as immutable
(including the checkpoint block itself).
A trusted checkpoint provider exposes a HTTP endpoint,
allowing nodes to download the checkpoint block and the corresponding ledger state.
The details are defined in Checkpoint Provider HTTP API.
The bootstrapping node imports the downloaded checkpoint block and ledger state
before starting bootstrapping.
The imported checkpoint block is used as the latest immutable block $B_{imm}$
and the local chain tip $c_{loc}$.
Starting from the checkpoint block,
the same Initial Block Download is used to download blocks
up to the tip of the local chain of each peer.
As defined in Setting the Fork Choice Rule,
the Bootstrap fork choice rule MUST be used upon startup.
If it turns out that none of the peers' local chains are connected
to the checkpoint block,
the node is terminated with an error,
allowing the node operator to select a new checkpoint.
## Details
### Offline Grace Period
The offline grace period $T_\text{offline}$ is a period during which
a node can be restarted without switching to the Bootstrap rule.
This protocol configures $T_\text{offline}$ to 20 minutes.
Here are the advantages and disadvantages of a short period:
**Advantages:**
- Limits chances for malicious peers to build long alternative chains
beyond the scope of the Online rule.
- Conservatively enables the Bootstrap rule to handle long forks.
**Disadvantages:**
- Even a short offline duration can too sensitively trigger the Bootstrap rule,
which then lasts for the long Prolonged Bootstrap Period.
The following example explains why $T_\text{offline}$ should not be set too long:
- A local node stopped in the following situation.
A malicious peer is building a fork which is now a little shorter ($k - d$)
than the honest chain.
- The local node has been offline shorter than $T_\text{offline}$ and just restarted.
As defined in this protocol, the Online fork choice rule is used
because the offline duration is short.
- During the offline duration, the malicious peer made its fork longer
by adding $k - d$ blocks.
Now the fork is in the same length as the honest chain.
- If the malicious peer sends the fork to the restarted node
faster than the honest peer,
the restarted node will commit to the fork because it has $k$ new blocks.
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
## References
### Normative
- [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt)
\- Key words for use in RFCs to Indicate Requirement Levels
- [Cryptarchia v1 Protocol Specification](https://nomos-tech.notion.site/Cryptarchia-v1-Protocol-Specification-21c261aa09df810cb85eff1c76e5798c)
\- Parent protocol specification
- [Cryptarchia Fork Choice Rule](https://nomos-tech.notion.site/Cryptarchia-Fork-Choice-Rule)
\- Fork choice rule specification
### Informative
- [Cryptarchia v1 Bootstrapping & Synchronization](https://nomos-tech.notion.site/Cryptarchia-v1-Bootstrapping-Synchronization-1fd261aa09df81ac94b5fb6a4eff32a6)
\- Original bootstrapping and synchronization documentation
- [Libp2p Streaming](https://docs.libp2p.io/)
\- Peer-to-peer networking library