refactor(domain): turn header into an immutable value type#364
refactor(domain): turn header into an immutable value type#364fpelliccioni wants to merge 1 commit into
Conversation
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (49)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The old header inherited from header_basis, mixed in hash_memoizer to cache the block hash, and carried a mutable `validation` struct holding height and median_time_past stamped from outside. The cache was a thread hazard, the inheritance leaked basis internals, and the validation struct was a side-channel for height/MTP that the value type should never own. Replace it with two interchangeable value types selected at compile time via `KTH_USE_HEADER_MEMBERS`: - header_raw (default): 80-byte contiguous storage, fields decoded on access. Wins on the IBD hot path — faster deserialization, zero-copy raw access for wire-handling code. - header_members: traditional struct, field-per-member. Wins on repeated full-record access (wallets, explorers). Both expose the same surface plus a free function `chain::hash(header)` in lieu of the cached `header.hash()` member. The validation side-channel is gone: block_pool and branch now read height and MTP off the block's chain_state, which the validator already populates. block_organizer no longer stamps the header. C-API regenerated via kth-tools (no hand edits). The generator picks up `chain::hash(header const&)` automatically thanks to a new `extra_namespaces=['kth::domain::chain']` on the header config, so `kth_chain_header_hash` is exposed as a normal accessor. Caught while wiring up the tests, fixed in passing: - block_entry::parent() returned `hash_digest const&` but the new header decodes previous_block_hash from raw bytes into a temporary — every caller was holding a dangling reference. - Same dangle in header_organizer.cpp and internal_database test.
bbc6e0a to
89612e1
Compare
Summary
Reshape
chain::headerinto an immutable value type, then propagate the change through every layer that consumed the old surface.Domain change
header_basisbase +hash_memoizermixin + mutableheader.validationstruct (a side-channel that callers used to stamp height / median_time_past from outside).KTH_USE_HEADER_MEMBERS:header_raw(default): 80-byte contiguous storage with fields decoded on access. Wins on the IBD hot path — faster construction-from-bytes (~1.5 ns) and ~17% faster wire deserialization than the members variant per the bench shipped here.header_members: traditional field-per-member. Wins only on the "read every field" path.header.hash()member is gone. There is now a free functionchain::hash(header)that both impls cooperate with.previous_block_hash()andmerkle()returnhash_digestby value on the raw impl (decoded from the byte buffer), uniform with the members impl.Propagation through the rest of the codebase
Every layer that touched the old header had to move with it.
blockchain:
block_poolandbranchno longer read height / MTP fromheader.validation; they now read them from the block'schain_state, which the validator populates.block_organizerno longer stamps the header.block_entry::parent()had to change from returninghash_digest const&to returning by value, because the new accessor produces a temporary — every caller that held a reference (auto const&inheader_organizer.cpp, ininternal_databasetest) had to drop the reference.validate_header::check()and::accept()precompute the hash and pass it down. Testsblock_entry/block_pool/branchare rewritten: 6-arg header ctor in place ofset_*mutators,chain_stateset up where height is actually needed.database:
header_indexno longer pullsproof()fromheader_basis::; it lives onheaderitself now. Multipleheader.hash()call sites switch tochain::hash(header).network:
protocols_corocall sites forblock.header().hash()switch tochain::hash(...).node:
full_node,header_list,reservation, and the test utility follow the same pattern.header_list::check()precomputes the hash for the newheader.check(hash, retarget)signature.C-API: regenerated end-to-end by the generator in
../kth-tools; no hand edits tosrc/c-api/. The generator's free-function sweep is extended tokth::domain::chainsochain::hash(header const&)is picked up automatically askth_chain_header_hash. The setters andhash_poware dropped — header is immutable and BCH/BTC have no separate PoW hash. The c-api test file is updated to construct headers via the ctor and to feedkth_chain_header_hashintois_valid_proof_of_work.domain itself:
block_basis,chain_state,message::header(s),property_tree, and the relevant tests are updated to usechain::hash(...)and the 6-arg ctor.Notes
Old files (
header.cpp,header_basis.{hpp,cpp},hash_memoizer.hpp, the originalmessage/header.{hpp,cpp}) are renamed to.disabledso any straggler trips the compiler instead of silently linking against the legacy code path. Removed in a follow-up commit once the dust settles.Test plan