feat(hot)!: add table for journal hashes#70
Open
Fraser999 wants to merge 1 commit into
Open
Conversation
prestwich
requested changes
May 30, 2026
| table = table.name, | ||
| ?expected, | ||
| "FSI metadata entry missing for known table; falling back to compile-time \ | ||
| expected value. Fires once per open per missing table until a RW open \ |
Member
There was a problem hiding this comment.
I think this info belongs in a comment? 🤔
creates the table and persists its FSI; RO-only consumers of a \
pre-upgrade database will see this on every open."```
| let mut known = [("", FixedSizeInfo::None); NUM_TABLES]; | ||
| for (i, &name) in KNOWN_TABLE_NAMES.iter().enumerate() { | ||
| known[i] = (name, tx.read_fsi_from_table(name)?); | ||
| for (index, table) in STANDARD_TABLES.iter().enumerate() { |
Member
There was a problem hiding this comment.
could rewrite this loop as a try_for_each() ?
| /// Removes a table from the environment as if it had never been created: | ||
| /// drops the named sub-database and erases its FSI metadata entry. Used | ||
| /// by tests to simulate a database written by an older binary that | ||
| /// pre-dates the table. Does not invalidate the in-memory `FsiCache`; |
Member
There was a problem hiding this comment.
we still control all significant running copies of the binaries, so we could choose not to implement migration logic/tests here. worth discussing whether we need this complexity yet
| /// Set the journal hash (keccak256 of the wire-encoded `Journal::V1`). | ||
| /// Leave the method uncalled for block-only nodes that do not produce | ||
| /// a journal - the field defaults to `None`. | ||
| pub const fn journal_hash(mut self, hash: B256) -> Self { |
Member
There was a problem hiding this comment.
nit: usually with_journal_hash or some other verb that indicates mutating
| /// [`queue_raw_create`](crate::model::HotKvWrite::queue_raw_create) so the | ||
| /// same record drives both table creation and backend-side FSI inference. | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| pub struct StandardTable { |
Member
There was a problem hiding this comment.
I don't mind this complexity addition
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Adds a
JournalHashes<BlockNumber => B256>hot table so nodes can re-seed the rolling previous-journal hash across restarts and reorgs (ENG-2017). Hot-only, opt-in per block.Changes
JournalHashes<BlockNumber => B256>plusHotDbRead::get_journal_hashandUnsafeDbWrite::put_journal_hash.ExecutedBlock.journal_hash: Option<B256>+ builder setter.UnifiedStorage::append_blockspersists it in the same hot transaction as headers/bundle.HistoryWrite::unwind_abovedeletes journal hashes alongside change-sets/headers, independent oflast_block_number().STANDARD_TABLESconst insignet-hotas the single source of truth for table creation and MDBX FSI cache seeding.queue_db_initandread_known_fsiboth iterate it.read_known_fsifalls back to compile-time-expected FSI (viaFixedSizeInfo::from_create_args) when an on-disk entry is missing, so RO/RW opens against an older DB succeed.unwind_above(u64::MAX)now short-circuits viachecked_addinstead of overflowingblock + 1(wraps to0in release, panics in debug).From<ExecutedBlock> for BlockDatadestructures explicitly so new fields trip a compile error on the cold side.API breakages
ExecutedBlock::new()removed - useExecutedBlockBuilderinstead.ExecutedBlockgains a new publicjournal_hashfield. Struct-literal construction (ExecutedBlock { header, .. }) and exhaustive destructuring without..will no longer compile.Test plan
cargo t -p signet-hot -p signet-hot-mdbx -p signet-storage --all-featurescargo clippy --workspace --all-targets --all-features -- -D warningscargo clippy --workspace --all-targets --no-default-features -- -D warningscargo +nightly fmt -- --checktest_journal_hash_roundtrip(conformance),open_tolerates_pre_upgrade_db(FSI fallback),append_blocks_persists_journal_hashes/unwind_above_drops_journal_hashes(integration),unwind_above_u64_max_is_noop/unwind_above_below_u64_max_deletes_max_entry(overflow boundary).test_unwind_conformanceupdated to coverJournalHashes.Notes
put_journal_hashhas no consistent-trait wrapper; callers are responsible for pairing writes with a header.unwind_abovecleans both regardless.replay_to_coldsilently discardsjournal_hash(hot-only).PR description drafted by Claude (Opus 4.7, 1M context) via Claude Code.