Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
590 changes: 549 additions & 41 deletions zaino-state/src/chain_index/encoding.rs

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions zaino-state/src/chain_index/finalised_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,10 @@ use tracing::info;
use zebra_chain::parameters::NetworkKind;

use crate::{
chain_index::{source::BlockchainSourceError, types::GENESIS_HEIGHT},
chain_index::{
finalised_state::db::v1::DB_VERSION_V1, source::BlockchainSourceError,
types::GENESIS_HEIGHT,
},
config::BlockCacheConfig,
error::FinalisedStateError,
BlockHash, BlockMetadata, BlockWithMetadata, ChainWork, Height, IndexedBlock, StatusType,
Expand Down Expand Up @@ -251,7 +254,7 @@ impl ZainoDB {
///
/// ## Version selection rules
/// - `cfg.db_version == 0` targets `DbVersion { 0, 0, 0 }` (legacy layout).
/// - `cfg.db_version == 1` targets `DbVersion { 1, 0, 0 }` (current layout).
/// - `cfg.db_version == 1` targets the latest v1 DB version (`DB_VERSION_V1`).
/// - Any other value returns an error.
///
/// ## Migrations
Expand Down Expand Up @@ -282,11 +285,7 @@ impl ZainoDB {
minor: 0,
patch: 0,
},
1 => DbVersion {
major: 1,
minor: 0,
patch: 0,
},
1 => DB_VERSION_V1,
x => {
return Err(FinalisedStateError::Custom(format!(
"unsupported database version: DbV{x}"
Expand Down
13 changes: 9 additions & 4 deletions zaino-state/src/chain_index/finalised_state/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,23 @@ Date: 2026-01-27
--------------------------------------------------------------------------------

Summary
- Minor version bump to reflect updated compact block API contract (streaming + pool filtering semantics).
- No schema or encoding changes; metadata-only migration updates persisted DB version marker.
- BlockHeaderData v2 introduced (internally using new BlockIndex::V2 format); because relevant tables (notably `headers` / `BlockHeaderData`) use
variable-length encodings existing tables are updated in-place: DB values may contain either v1 or v2 `BlockHeaderData` entries.
- Recorded on-disk schema text was clarified; migration refreshes persisted `DbMetadata.schema_hash`
so the metadata matches the repository's schema contract.
- Updated compact block API contract (streaming + pool filtering semantics).

On-disk schema
- Layout:
- No changes.
- Updated [`BlockHeaderData`] table by introducing [`BlockHeaderData::V2`] (and internally [`BlockIndex::V2`]), this table may now hold either V1 or V2
[`BlockHeaderData`] structs, with serde handled internally.
- Tables:
- Added: None.
- Removed: None.
- Renamed: None.
- Encoding:
- Keys: No changes.
- Values: No changes.
- Values: Introduced `[BlockHeaderData::V2]`.
- Checksums / validation: No changes.
- Invariants:
- No changes.
Expand All @@ -142,6 +146,7 @@ Migration
- Backfill: None.
- Completion criteria:
- DbMetadata.version updated from 1.0.0 to 1.1.0.
- DbMetadata.schema_hash updated to match repository `DB_SCHEMA_V1_HASH`.
- DbMetadata.migration_status reset to Empty.
- Failure handling:
- Idempotent: re-running re-writes the same metadata; no partial state beyond metadata.
Expand Down
38 changes: 25 additions & 13 deletions zaino-state/src/chain_index/finalised_state/capability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,16 +336,20 @@ impl DbMetadata {
impl ZainoVersionedSerde for DbMetadata {
const VERSION: u8 = version::V1;

fn encode_body<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.version.serialize(&mut *w)?;
write_fixed_le::<32, _>(&mut *w, &self.schema_hash)?;
self.migration_status.serialize(&mut *w)
fn encode_latest<W: Write>(&self, w: &mut W) -> io::Result<()> {
Self::encode_v1(self, w)
}

fn decode_latest<R: Read>(r: &mut R) -> io::Result<Self> {
Self::decode_v1(r)
}

fn encode_v1<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.version.serialize_with_version(&mut *w, 1)?;
write_fixed_le::<32, _>(&mut *w, &self.schema_hash)?;
self.migration_status.serialize_with_version(&mut *w, 1)
}

fn decode_v1<R: Read>(r: &mut R) -> io::Result<Self> {
let version = DbVersion::deserialize(&mut *r)?;
let schema_hash = read_fixed_le::<32, _>(&mut *r)?;
Expand Down Expand Up @@ -476,16 +480,20 @@ impl DbVersion {
impl ZainoVersionedSerde for DbVersion {
const VERSION: u8 = version::V1;

fn encode_body<W: Write>(&self, w: &mut W) -> io::Result<()> {
write_u32_le(&mut *w, self.major)?;
write_u32_le(&mut *w, self.minor)?;
write_u32_le(&mut *w, self.patch)
fn encode_latest<W: Write>(&self, w: &mut W) -> io::Result<()> {
Self::encode_v1(self, w)
}

fn decode_latest<R: Read>(r: &mut R) -> io::Result<Self> {
Self::decode_v1(r)
}

fn encode_v1<W: Write>(&self, w: &mut W) -> io::Result<()> {
write_u32_le(&mut *w, self.major)?;
write_u32_le(&mut *w, self.minor)?;
write_u32_le(&mut *w, self.patch)
}

fn decode_v1<R: Read>(r: &mut R) -> io::Result<Self> {
let major = read_u32_le(&mut *r)?;
let minor = read_u32_le(&mut *r)?;
Expand Down Expand Up @@ -565,7 +573,15 @@ impl fmt::Display for MigrationStatus {
impl ZainoVersionedSerde for MigrationStatus {
const VERSION: u8 = version::V1;

fn encode_body<W: Write>(&self, w: &mut W) -> io::Result<()> {
fn encode_latest<W: Write>(&self, w: &mut W) -> io::Result<()> {
Self::encode_v1(self, w)
}

fn decode_latest<R: Read>(r: &mut R) -> io::Result<Self> {
Self::decode_v1(r)
}

fn encode_v1<W: Write>(&self, w: &mut W) -> io::Result<()> {
let tag = match self {
MigrationStatus::Empty => 0,
MigrationStatus::PartialBuidInProgress => 1,
Expand All @@ -576,10 +592,6 @@ impl ZainoVersionedSerde for MigrationStatus {
write_u8(w, tag)
}

fn decode_latest<R: Read>(r: &mut R) -> io::Result<Self> {
Self::decode_v1(r)
}

fn decode_v1<R: Read>(r: &mut R) -> io::Result<Self> {
match read_u8(r)? {
0 => Ok(MigrationStatus::Empty),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@
#
# 1. headers ― H -> StoredEntryVar<BlockHeaderData>
# Key : BE height
# Val : 0x01 + BlockHeaderData
# Val : 0x01/0x02 + BlockHeaderData
# BlockHeaderData V1 body =
# BlockIndex + BlockData
# BlockIndex = B hash B parent_hash U256 chain_work
# Option<H> height
# BlockIndex V1 + BlockData
#
# BlockHeaderData V2 body =
# BlockIndex V2 + BlockData
#
# BlockIndex V2 body = B hash B parent_hash U256 chain_work H height
# BlockIndex V1 body = B hash B parent_hash U256 chain_work Option<H> height
#
# BlockData = LE(u32) version
# LE(i64) unix_time
# B merkle_root
Expand Down Expand Up @@ -91,11 +96,14 @@
# Val : 0x01 + CS len + raw event bytes (multiple entries may share the key)
#
# 10. metadata ― "metadata" (ASCII) -> StoredEntryFixed<DbMetadata> (singleton)
# DbMetadata V1 body =
# [32] schema_hash
# LE(i64) created_unix_ts
# LE(u32) pruned_tip
# LE(u32) network (Zcash main = 0, test = 1, regtest = 2)
# Val : 0x01 + DbMetadata V1 body + [32] checksum
# DbMetadata V1 body =
# DbVersion version
# 32-byte schema_hash
# MigrationStatus migration_status
#
# DbVersion = LE(u32) major LE(u32) minor LE(u32) patch
# MigrationStatus = u8 enum (0 = Empty, 1 = InProgress, 2 = Completed, 3 = Failed)
#
# ─────────────────────────── Environment settings ─────────────────────────────
# LMDB page-size: platform default
Expand Down
15 changes: 7 additions & 8 deletions zaino-state/src/chain_index/finalised_state/db/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ use tracing::{error, info, warn};
/// compile-time. The path is relative to this source file.
///
/// 1. Bring the *exact* ASCII description of the on-disk layout into the binary at compile-time.
pub(crate) const DB_SCHEMA_V1_TEXT: &str = include_str!("db_schema_v1_0.txt");
pub(crate) const DB_SCHEMA_V1_TEXT: &str = include_str!("db_schema_v1.txt");

/*
2. Compute the checksum once, outside the code:

$ cd zaino-state/src/chain_index/finalised_state/db
$ b2sum -l 256 db_schema_v1_0.txt
bc135247b46bb46a4a971e4c2707826f8095e662b6919d28872c71b6bd676593 db_schema_v1_0.txt
$ b2sum -l 256 db_schema_v1.txt
=> [HASH] db_schema_v1.txt

Optional helper if you don’t have `b2sum`:

Expand All @@ -95,8 +95,7 @@ pub(crate) const DB_SCHEMA_V1_TEXT: &str = include_str!("db_schema_v1_0.txt");

3. Turn those 64 hex digits into a Rust `[u8; 32]` literal:

echo bc135247b46bb46a4a971e4c2707826f8095e662b6919d28872c71b6bd676593 \
| sed 's/../0x&, /g' | fold -s -w48
$ echo [HASH] | sed 's/../0x&, /g' | fold -s -w48

*/

Expand All @@ -105,14 +104,14 @@ pub(crate) const DB_SCHEMA_V1_TEXT: &str = include_str!("db_schema_v1_0.txt");
/// This value is compared against the schema hash stored in the metadata record to detect schema
/// drift without a corresponding version bump.
pub(crate) const DB_SCHEMA_V1_HASH: [u8; 32] = [
0xbc, 0x13, 0x52, 0x47, 0xb4, 0x6b, 0xb4, 0x6a, 0x4a, 0x97, 0x1e, 0x4c, 0x27, 0x07, 0x82, 0x6f,
0x80, 0x95, 0xe6, 0x62, 0xb6, 0x91, 0x9d, 0x28, 0x87, 0x2c, 0x71, 0xb6, 0xbd, 0x67, 0x65, 0x93,
0x8f, 0x21, 0x66, 0xbe, 0xfd, 0x8b, 0x98, 0xc9, 0x41, 0x47, 0x20, 0x36, 0x66, 0x3b, 0xda, 0xc9,
0x63, 0x8d, 0x60, 0x17, 0x0a, 0xc7, 0x89, 0x41, 0xef, 0x4e, 0x46, 0x40, 0xb2, 0x6c, 0x22, 0xc2,
];

/// *Current* database V1 version.
pub(crate) const DB_VERSION_V1: DbVersion = DbVersion {
major: 1,
minor: 0,
minor: 1,
patch: 0,
};

Expand Down
Loading