Purpose and Scope
This document describes the ancient store subsystem (commonly referred to as the “freezer”) in go-stablenet and how it manages the storage lifecycle of historical blockchain data. The ancient store is an append-only archive storage layer that separates and preserves old block data in order to optimize performance and disk usage of the active database. This page covers:- Ancient store architecture and its separation of roles from the active database
- Data migration flow from the active store to the ancient store
- Ancient store operations (read, write, truncate)
- Chain rewind handling when frozen data exists
- Importing and exporting historical data using the Era1 format
For caching and snapshots, see Caching and Snapshots.
Ancient Store Architecture
The ancient store is a dedicated storage for historical blockchain data that has become immutable.This layer is designed to improve performance and disk efficiency with the following characteristics:
- Append-only write model
- Sequential access by block number
- Physical and logical separation from the active key-value database
- Minimized random-access cost for old data
Storage Layers
Blockchain data is divided into two main layers:- Active Database
Recent blocks, state (tries), headers, transaction indices, and other data
that require frequent random access and writes - Ancient Store
Blocks, receipts, and total difficulty data that are sufficiently old and no longer mutable
Database Interface
Theethdb.Database interface provides a unified access point for both the active and ancient stores:
| Method | Description | Storage Layer |
|---|---|---|
Ancients() | Returns the number of frozen blocks | Ancient store |
TruncateHead(n) | Removes ancient data after block n | Ancient store |
Get(key) / Put(key, val) | Key-value read/write | Active database |
NewBatch() | Create a batch write | Active database |
Data Lifecycle and Migration
Block Data States
Blockchain data transitions through the following stages depending on block age and state availability:- Active State
Recent blocks that must support state (trie) access and rewinds - Transitional State
State is no longer needed, but data has not yet moved to the ancient store - Frozen State
State access is no longer required; data is considered immutable and stored in the ancient store
Freezer Threshold
The freezer threshold defines the point at which blocks are migrated to the ancient store.Blocks below this threshold are considered ineligible for state recovery during rewinds. Key considerations:
- State availability
Blocks requiring state (tries) must remain in the active database TriesInMemoryconstant
Typically, the most recent ~128 blocks are kept in the active DB- Snap synchronization
During snap sync, the pivot block may affect the freezer boundary - Full synchronization
Once state is no longer required, old blocks are migrated sequentially
Ancient Store Operations
Reading Ancient Data
When accessing old blocks, the BlockChain logic transparently reads data from the ancient store. From the perspective of higher layers, there is no need to explicitly distinguish whether data resides in the active DB or the ancient store.Writing and Truncation
Modifications to the ancient store occur only in limited scenarios:- Chain rewind (
SetHead)
When rewinding below the frozen threshold - Historical data import
When injecting past data via Era1 archives
TruncateHead removes data after a given block number from the ancient store.
Chain Rewind with Ancient Data
Rewind Process
When rewinding the chain (SetHead, SetHeadWithTimestamp),special handling is required for frozen data.
| Scenario | Active DB Action | Ancient Store Action |
|---|---|---|
| Target above freezer threshold | Delete active blocks/headers | None |
| Target below freezer threshold | Delete all active blocks | Truncate ancient store |
| Rewind to genesis | Reset active DB | Remove all ancient data |
setHeadBeyondRoot flow.
Handling Missing State
During rewind, the system must locate a block with available state:- Check
HasState(root)orstateRecoverable(root) - If state is missing, move to the parent block
- Rewinds below the snap pivot are prohibited
- If recoverable, attempt
triedb.Recover(root)
Safety of Ancient Truncation
Ancient truncation follows strict safety rules:- Executed via a single
TruncateHeadcall - Active DB cleanup performed first
- Hash/number mappings of removed blocks deleted
- Chain head markers updated atomically
Importing and Exporting Historical Data
Era1 Archive Format
go-stablenet uses the Era1 format to bundle historical blockchain data.| Component | Content | Purpose |
|---|---|---|
| Era Archive | ~8192 blocks | Sequential storage unit |
| Block Data | Header, Body, Tx | Block reconstruction |
| Receipts | Transaction receipts | Execution result verification |
| Total Difficulty | Cumulative difficulty | Chain weight calculation |
| Root Hash | Era Merkle root | Integrity verification |
Import Process
ImportHistory writes Era1 archives directly into the ancient store.Since the active DB is bypassed, this enables fast bootstrapping.
Export Process
ExportHistory packages existing chain data into the Era1 format for external storage or distribution.
Direct Ancient Store Initialization
When attaching an external ancient store to an empty node, automatic initialization is performed at startup. This is useful for:- Fast initialization from a trusted archive
- Physical separation of ancient and active data
- Disaster recovery setups
Integration with BlockChain
BlockChain Structure Fields
Ancient Store Query Patterns
| Operation | Implementation | Ancient Check |
|---|---|---|
| Get block by number | Branch on Ancients() | Yes |
| Header lookup | Active → ancient fallback | Implicit |
| Chain continuity check | Verify ancient boundary | Yes |
| State availability check | Ancient blocks have no state | Yes |
Interaction with Snap Synchronization
- Snap pivot block may lie at the ancient boundary
- Receipt chains are filled via
InsertReceiptChain currentSnapBlockandcurrentBlockmay diverge- Snap insertion below the boundary is prohibited
Maintenance Operations
Disk Space Management
Because the ancient store can occupy a large portion of disk space, block count and disk usage should be continuously monitored.Database Corruption Recovery
Possible causes:- Abnormal shutdown during truncation
- Filesystem errors
- Manual file modification
- Verify ancient count and head at startup
- Automatically truncate on mismatch
- Manually recover using
SetHeadif necessary
Best Practices
Operational Guidelines
- The ancient store can be backed up while running
- Consider placing it on a separate disk for I/O isolation
- Monitor ancient block count and disk usage separately
- Ancient data is immutable and removed only via truncation
Performance Considerations
| Aspect | Recommendation | Rationale |
|---|---|---|
| Ancient location | Disk with strong sequential read performance | Append-only access pattern |
| Active DB | Disk with strong random I/O performance | Frequent reads/writes |
| Memory | Minimal caching | Low access frequency |
| Synchronization | Full sync fills naturally | Snap requires separate receipts |

