# Checkpoint Sync in Ream
Date: 2025-05-31
By: Varun Doshi
## Primer on Ethereum Primitives
**Slot**: This is a fundamental unit in Ethereum. One slot is exactly equal to `12 seconds`. One Ethereum block is built in a single slot (however this may change in the future).
```jsx
1 slot = 12 seconds
```
**Epoch**: A collection of 32 consecutive slots, lasting approximately `6.4 minutes`. In an epoch, there are 32 assigned block proposers and everyone else is known as an **attester**, assigned to vote on proposed blocks once per epoch.
```jsx
1 epoch = 32 slots
```
**Checkpoint**: Checkpoints are special markers that occur at the beginning of each epoch, serving as reference points for Ethereum's finality mechanism. So the first slot of each epoch is a checkpoint.

The ETH2 finality process is defined as follows:
1. If > 2/3rds of validators vote correctly on the chain head during an epoch, we call the last epoch **justified.**
2. If two epochs in a row are justified, the `current_epoch - 2` is considered **finalized.**
## Syncing in Ethereum
Syncing is the process by which a node downloads and verifies consensus data including beacon blocks, attestations, validator states, and finality information. The syncing process ensures your node has an accurate, up-to-date view of the Ethereum network.
There are a few different types of syncing, but for the purposes of this note we will only focus on Checkpoint Sync.
**Checkpoint Sync** fetches data from a recent Checkpoint instead of from Genesis (start of Ethereum).
This means instead of downloading and verifying the entire chain history, the node starts from a known-good state and only syncs forward from that point.
- Checkpoint Sync starts using a a recent checkpoint provided by a trusted source which may be user provided or using one from the list of community checkpoint providers.
- The node is provided with or discovers a trusted recent **checkpoint block**—a block that has already been finalized by the network.
- The node downloads the corresponding **state, block and blobs**.
- It then fetches the next blocks ideally from the P2P layer, verifying each block as they it is received. This part is the same as it would be in Full Sync.

## Weak Subjectivity
A PoS node that has been offline for an extended period faces a risk when it comes back online:
- It may see **multiple conflicting chains** that look equally valid due to malicious validators or long-range attacks.
- Since finality is based on validator attestations rather than resource expenditure (such as in PoW), the node cannot determine which chain is canonical just by looking at it.
> *If 33% of validators withdraw their stake but continue to attest and produce blocks, they might generate an alternative fork that conflicts with the canonical chain. New nodes or nodes that have been offline for a long time might not be aware that these attacking validators have withdrawn their funds, so attackers could trick them into following an incorrect chain.*
>
Weak subjectivity checkpoints are state roots that all nodes on the network agree belong in the canonical chain. They serve the same "universal truth" purpose as genesis blocks, except that they do not sit at the genesis position in the blockchain.
The checkpoints act as revert limits because blocks located before weak-subjectivity checkpoints cannot be changed. This undermines long-range attacks simply by defining long-range forks to be invalid as part of the mechanism design.
The idea for Weak Subjectivity checks in Ream is as follows:

If you would like to deep dive, [Vitalik Buterin has a detailed post](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity) about the same.
## Checkpoint Sync in Ream
Currently, I’ve implemented the initial trusted checkpoint setup and weak subjectivity check in Ream. We are working on implementing Forward Sync and Backfill.
Users can start the node using Checkpoint Sync with the following command:
```powershell
cargo run beacon_node --data-dir <PATH_TO_FOLDER> --network mainnet
```
There are a few different options here:
- `--purge-db`: In case you would like to have a fresh start, this flag will clean up any existing data in the `--data-dir` folder. Without this flag, the node will start sync from the latest state in `--data-dir` or from the most recent checkpoint if no data is present.
- `--weak-subjectivity-checkpoint <0xblock root:epoch>` : To pass in a Weak Subjectivity Checkpoint. This will ensure that in case of a fresh sync, it will not do so from a state older that this checkpoint. Format is `0xblock_root:epoch`.
- `--checkpoint-sync-url <RPC>`: To pass in a trusted RPC yourself. If not provided, the node will fetch the latest finalized checkpoint from the [community checkpoint providers](https://eth-clients.github.io/checkpoint-sync-endpoints/) and use that as the starting point.
On running the command, we get the following logs:
```jsx
ream git:(master) cargo run beacon_node --data-dir dbb --network mainnet
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.36s
Running `target/debug/ream beacon_node --data-dir dbb --network mainnet`
2025-06-01T09:25:53.612902Z INFO ream: starting up beacon node...
2025-06-01T09:25:53.705788Z INFO ream: ream database initialized
2025-06-01T09:25:53.706397Z INFO ream_checkpoint_sync: Initiating checkpoint sync
2025-06-01T09:25:53.706404Z INFO ream_checkpoint_sync: Fetching finalized block...
2025-06-01T09:25:55.344646Z INFO ream_checkpoint_sync: Downloaded block: 22608857 with root: 0x88e5383e9ca31fa9b8a8a5de20ae60ef6aae5f7850bec01039b7aadda097ad8e. Slot: 11828736
2025-06-01T09:25:55.344684Z INFO ream_checkpoint_sync: Fetching blobs...
2025-06-01T09:25:58.727867Z INFO ream_checkpoint_sync: Downloaded blobs for block: 22608857
2025-06-01T09:25:58.727885Z INFO ream_checkpoint_sync: Fetching initial state...
2025-06-01T09:30:39.628413Z INFO ream_checkpoint_sync: Downloaded state with root: 0xb0c1583f327e4e77e88d75333d51871c8cfc8f9915bc2b0eac13f09d6c874bde. Slot: 11828736
2025-06-01T09:36:57.416290Z INFO ream_checkpoint_sync: Initial sync complete
2025-06-01T09:36:57.544516Z INFO ream: Database Initialization completed
```
So in my case, I will use the following state and block as my base for syncing ahead:
```jsx
Slot : 11828736
Block Root : 0x88e5383e9ca31fa9b8a8a5de20ae60ef6aae5f7850bec01039b7aadda097ad8e
State Root : 0xb0c1583f327e4e77e88d75333d51871c8cfc8f9915bc2b0eac13f09d6c874bde
```