From dc275ad033932c77f829b85ccfbcebfcf29d9f05 Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Fri, 25 Sep 2026 03:28:40 -0400 Subject: [PATCH 1/2] Pass cumulative work to header archival. --- include/bitcoin/node/chasers/chaser_header.hpp | 3 ++- src/chasers/chaser_header.cpp | 10 ++++++---- test/functional/p2p_setup_fixture.hpp | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp index ae0735f1..c12db53e 100644 --- a/include/bitcoin/node/chasers/chaser_header.hpp +++ b/include/bitcoin/node/chasers/chaser_header.hpp @@ -102,7 +102,8 @@ class BCN_API chaser_header height_t candidate_height) NOEXCEPT; code push_header(const system::hash_digest& key) NOEXCEPT; code push_header(const system::chain::header& header, - const system::chain::context& ctx, bool milestone) NOEXCEPT; + const system::chain::context& ctx, const uint256_t& work, + bool milestone) NOEXCEPT; void cache(const system::chain::header::cptr& header, const chain_state::cptr& state) NOEXCEPT; diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index c1f7bd3a..3800bf6d 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -341,7 +341,8 @@ void chaser_header::do_organize(const header::cptr& header_ptr, } // Push new header as top of candidate chain. - if (const auto ec = push_header(header, state->context(), milestone)) + if (const auto ec = push_header(header, state->context(), + state->cumulative_work(), milestone)) { handler(fault(ec), height); return; @@ -627,11 +628,11 @@ bool chaser_header::set_organized(const header_link& link, // Milestone is archived in the header and like checkpoint cannot change. // But unlike checkpointed, milestoned blocks may not be strong chain. code chaser_header::push_header(const header& header, const context& ctx, - bool milestone) NOEXCEPT + const uint256_t& work, bool milestone) NOEXCEPT { auto& query = archive(); header_link link{}; - const auto ec = query.set_code(link, header, ctx, milestone, false); + const auto ec = query.set_code(link, header, ctx, work, milestone, false); if (ec) return ec; @@ -648,7 +649,8 @@ code chaser_header::push_header(const hash_digest& key) NOEXCEPT const auto& header_ptr = handle.mapped(); const auto& state = header_ptr->get_state(); - return push_header(*header_ptr, state->context(), false); + return push_header(*header_ptr, state->context(), + state->cumulative_work(), false); } void chaser_header::cache(const header::cptr& header, diff --git a/test/functional/p2p_setup_fixture.hpp b/test/functional/p2p_setup_fixture.hpp index ae12f910..cc72374d 100644 --- a/test/functional/p2p_setup_fixture.hpp +++ b/test/functional/p2p_setup_fixture.hpp @@ -125,7 +125,7 @@ struct p2p_unassociated_setup_fixture inline p2p_unassociated_setup_fixture() : p2p_setup_fixture([](node::query& query) { - return query.set(unassociated(), database::context{}, false); + return query.set(unassociated(), database::context{}, {}, false); }, [](configuration& config) { config.network.enable_not_found = true; From ea4f5ed3439b2934fc6a355395bc29949f2a4a8d Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Fri, 25 Sep 2026 04:14:16 -0400 Subject: [PATCH 2/2] Write validated tx state for newly pooled transactions. --- include/bitcoin/node/error.hpp | 1 + src/chasers/chaser_transaction.cpp | 19 ++++++++++++++++++- src/error.cpp | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/bitcoin/node/error.hpp b/include/bitcoin/node/error.hpp index 59e4328d..b96c62d5 100644 --- a/include/bitcoin/node/error.hpp +++ b/include/bitcoin/node/error.hpp @@ -113,6 +113,7 @@ enum error_t : uint8_t confirm11, confirm12, transaction1, + transaction2, estimates_initialize, estimates_push1, estimates_push2, diff --git a/src/chasers/chaser_transaction.cpp b/src/chasers/chaser_transaction.cpp index eb08c329..a1edb26a 100644 --- a/src/chasers/chaser_transaction.cpp +++ b/src/chasers/chaser_transaction.cpp @@ -153,22 +153,39 @@ void chaser_transaction::do_submit(const transactions_cptr& txs, bool test, } auto& query = archive(); + database::tx_links fresh(txs->size(), database::tx_link::terminal); for (index = {}; index < txs->size(); ++index) { + bool pooled{}; database::tx_link link{}; const auto& tx = *txs->at(index); // Disk full may leave package partly archived, resolves by resubmit. - if (const auto ec = query.set_code(link, tx)) + if (const auto ec = query.set_code(link, pooled, tx)) { handler(fault(ec), index); return; } + if (!pooled) + fresh.at(index) = link; + fire(events::tx_archived, to_rate(tx)); notify(error::success, chases::transaction{ link }); } + // Package parents are resolved by hash, so the whole package precedes. + for (index = {}; index < txs->size(); ++index) + { + const database::tx_link link{ fresh.at(index) }; + if (!link.is_terminal() && + !query.set_tx_state(link, *txs->at(index), pool_)) + { + handler(fault(error::transaction2), index); + return; + } + } + handler(error::success, {}); } diff --git a/src/error.cpp b/src/error.cpp index 67eae43d..eefe49b7 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -103,6 +103,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { confirm11, "confirm11" }, { confirm12, "confirm12" }, { transaction1, "transaction1" }, + { transaction2, "transaction2" }, { estimates_initialize, "estimates_initialize" }, { estimates_push1, "estimates_push1" }, { estimates_push2, "estimates_push2" },