Skip to content

Commit f34473f

Browse files
authored
nmc(header-chain): retire stale P0-DEFER banners + wire batch add_headers SPV ingest (#594)
header_chain.hpp documented the storage/connect/persist path as an unimplemented P0 "structural skeleton", but P1e (in-memory connect + fork-choice) and P1f (LevelDB persist via connect_locked/persist_entry_locked) landed long ago. Retire the now-false P0/P0-DEFER comments (top STATUS banner first bullet, class doc, init(), tip(), add_header()) so the documented state matches the wired code; keep the genuinely-deferred live-node constant cross-check (PE item4) and the accurate batch note. Also implement add_headers(): the one remaining no-op leg. It now runs each header through the same connect_locked path as add_header() under a single lock, returning the count newly connected -- the natural getheaders batch-ingest entry point for SPV header-sync. coin_smoke.cpp force-compiles the batch path. Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
1 parent 5f47e66 commit f34473f

2 files changed

Lines changed: 26 additions & 17 deletions

File tree

src/impl/nmc/coin/coin_smoke.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ void nmc_coin_p0_smoke()
2424
(void)chain.init();
2525
(void)chain.height();
2626
(void)chain.size();
27+
(void)chain.add_headers(std::vector<BlockHeaderType>{});
2728

2829
BlockHeaderType header;
2930
header.SetNull();

src/impl/nmc/coin/header_chain.hpp

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@
3737
/// (factory) path; the -1 activation-height default is a deliberate
3838
/// fail-closed sentinel for hand-built Params only.
3939
/// STILL DEFERRED (scoped later, NOT a P0 fence):
40-
/// * The header-STORAGE / chain-connection path — a proof that passes the
41-
/// gate is verified but NOT yet persisted (see add_auxpow_header()).
4240
/// * Live cross-check of the pinned constants vs a running .140 namecoind,
4341
/// deferred to the PE item4 soak.
42+
/// (The header-STORAGE / connect / LevelDB-persist path is WIRED -- see
43+
/// connect_locked() + persist_entry_locked(); the prior "not yet persisted"
44+
/// note was retired once P1e/P1f landed.)
4445
/// ==========================================================================
4546

4647
#include "block.hpp"
@@ -940,10 +941,11 @@ inline uint32_t get_next_work_required(
940941

941942
// ─── HeaderChain ─────────────────────────────────────────────────────────────
942943

943-
/// Header-only chain skeleton for embedded NMC. Mirrors the public surface of
944-
/// btc::coin::HeaderChain. P0: the validation internals (difficulty checks,
945-
/// AuxPow checks, LevelDB persistence) are intentionally NOT implemented — the
946-
/// methods below are structural skeletons so call sites compile.
944+
/// Header-only chain for embedded NMC. Mirrors the public surface of
945+
/// btc::coin::HeaderChain. The validation internals are WIRED: AuxPow gate
946+
/// (P1d), in-memory connect / cumulative-work / fork-choice (P1e) and LevelDB
947+
/// persistence (P1f). The only deferred leg is the live-node constant
948+
/// cross-check (PE item4 soak); see the STATUS banner above.
947949
class HeaderChain {
948950
public:
949951
explicit HeaderChain(const NMCChainParams& params, const std::string& db_path = "")
@@ -958,9 +960,9 @@ class HeaderChain {
958960
HeaderChain(const HeaderChain&) = delete;
959961
HeaderChain& operator=(const HeaderChain&) = delete;
960962

961-
/// Initialize the chain.
962-
/// P0-DEFER: no LevelDB open, no persisted-state load, no checkpoint seed.
963-
/// Returns true (structural success) so wiring smoke-tests pass.
963+
/// Initialize the chain. Opens LevelDB at m_db_path (when set) and reloads
964+
/// persisted state via load_from_db(); degrades to in-memory on open
965+
/// failure (mirror of btc). Returns true.
964966
bool init() {
965967
LOG_INFO << "[EMB-NMC] HeaderChain::init() db_path="
966968
<< (m_db_path.empty() ? "(in-memory)" : m_db_path);
@@ -983,7 +985,7 @@ class HeaderChain {
983985
return true;
984986
}
985987

986-
/// Current chain tip (best header). P0: empty until add path is built.
988+
/// Current chain tip (best header); std::nullopt on an empty chain.
987989
std::optional<IndexEntry> tip() const {
988990
std::lock_guard<std::mutex> lock(m_mutex);
989991
if (m_tip.IsNull()) return std::nullopt;
@@ -1059,9 +1061,6 @@ class HeaderChain {
10591061
return locator;
10601062
}
10611063

1062-
/// Add a single plain header.
1063-
/// P0-DEFER: NO difficulty validation, NO PoW check, NO connection check,
1064-
/// NO persistence. Structural skeleton only — returns false.
10651064
/// Add a single plain (non-merge-mined) header.
10661065
/// P1e storage leg: in-memory connect path. On an empty chain the header
10671066
/// seeds the chain root (height 0, checkpoint anchor); otherwise it must
@@ -1138,11 +1137,20 @@ class HeaderChain {
11381137
return connect_locked(header, auxpow);
11391138
}
11401139

1141-
/// Add a batch of plain headers. P0-DEFER: returns 0 (none accepted).
1140+
/// Add a batch of plain (non-merge-mined) headers, as delivered by a
1141+
/// getheaders response during SPV header-sync. Each header is run through
1142+
/// the same connect path as add_header() under a single lock. Headers are
1143+
/// expected in ascending (parent-before-child) order; out-of-order or
1144+
/// gapped entries simply fail to connect and are skipped without aborting
1145+
/// the batch. Returns the number of headers newly connected.
11421146
int add_headers(const std::vector<BlockHeaderType>& headers) {
1143-
(void)headers;
1144-
// P0-DEFER: batch header path not implemented.
1145-
return 0;
1147+
std::lock_guard<std::mutex> lock(m_mutex);
1148+
int accepted = 0;
1149+
for (const auto& h : headers) {
1150+
if (connect_locked(h, std::nullopt))
1151+
++accepted;
1152+
}
1153+
return accepted;
11461154
}
11471155

11481156
/// P1 PC: look up a header by absolute height by walking the tip's ancestry

0 commit comments

Comments
 (0)