From 07599a119dba0b373c25da968ac6b69d38ae4750 Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Mon, 12 Oct 2026 00:11:21 -0400 Subject: [PATCH] Read block state flags in place of state codes. --- .../node/protocols/protocol_block_out_106.hpp | 4 -- src/chasers/chaser_confirm.cpp | 58 ++++++++----------- src/chasers/chaser_header.cpp | 11 +--- src/chasers/chaser_validate.cpp | 49 +++++----------- src/protocols/protocol_block_in_31800.cpp | 6 +- src/protocols/protocol_block_out_106.cpp | 15 +---- test/chasers/chaser_confirm.cpp | 24 +++++--- test/chasers/chaser_validate.cpp | 54 +++++++++-------- 8 files changed, 87 insertions(+), 134 deletions(-) diff --git a/include/bitcoin/node/protocols/protocol_block_out_106.hpp b/include/bitcoin/node/protocols/protocol_block_out_106.hpp index 007522c8..aa1fba69 100644 --- a/include/bitcoin/node/protocols/protocol_block_out_106.hpp +++ b/include/bitcoin/node/protocols/protocol_block_out_106.hpp @@ -35,8 +35,6 @@ class BCN_API protocol_block_out_106 protocol_block_out_106(const auto& session, const network::channel::ptr& channel) NOEXCEPT : node::protocol_peer(session, channel), - top_checkpoint_height_( - session->system_settings().top_checkpoint().height()), node_pruned_(session->node_settings().limited_blocks), node_witness_(session->node_settings().provide_witness), network::tracker(session->log) @@ -85,11 +83,9 @@ class BCN_API protocol_block_out_106 private: using inventory = network::messages::peer::inventory; - bool is_under_checkpoint(const database::header_link& link) NOEXCEPT; inventory create_inventory(const get_blocks& locator) const NOEXCEPT; // These are thread safe. - const size_t top_checkpoint_height_; const bool node_pruned_; const bool node_witness_; }; diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index 7d3bfc42..1ea8b49e 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -161,8 +161,7 @@ void chaser_confirm::do_bumped(height_t) NOEXCEPT // Guarded by candidate interlock. size_t fork_point{}; const auto& query = archive(); - auto fork = query.get_validated_fork(fork_point, checkpoint(), - silent_limit()); + auto fork = query.get_validated_fork(fork_point, silent_limit()); // Fork may be empty if candidates were reorganized. if (fork.empty()) @@ -246,51 +245,40 @@ void chaser_confirm::organize(header_states& fork, const header_links& popped, auto height = add1(fork_point); // Continue when suspended as write error terminates synchronous loop. - for (const auto& state: fork) + for (const auto& item: fork) { if (closed()) return; - switch (state.ec.value()) + if (database::is_bypass(item.state)) { - case database::error::bypassed: + if (!query.set_filter_head(item.link)) { - if (!query.set_filter_head(state.link)) - { - fault(error::confirm6); - return; - } - - complete_block(error::success, state.link, height, true); - break; + fault(error::confirm6); + return; } - case database::error::block_valid: - { - // False always sets a store fault (including for disk full). - if (!confirm_block(state.link, height, popped, fork_point)) - return; - break; - } - case database::error::block_confirmable: - { - // Previously confirmable is not considered bypass. - complete_block(error::success, state.link, height, false); - break; - } - // error::unassociated - // error::unknown_state - // error::block_prevalid - // error::block_unconfirmable - default: - { - fault(error::confirm7); + complete_block(error::success, item.link, height, true); + } + else if (database::is_confirmable(item.state)) + { + // Previously confirmable is not considered bypass. + complete_block(error::success, item.link, height, false); + } + else if (database::is_validated(item.state)) + { + // False always sets a store fault (including for disk full). + if (!confirm_block(item.link, height, popped, fork_point)) return; - } + } + else + { + fault(error::confirm7); + return; } // After set_block_confirmable. - if (!set_organized(state.link, height++)) + if (!set_organized(item.link, height++)) { fault(error::confirm8); return; diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index 4b4a3361..25b09fb7 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -566,18 +566,11 @@ code chaser_header::duplicate(size_t& height, const auto id = query.to_header(hash); if (!id.is_terminal()) { - // database::error::block_unconfirmable - // database::error::block_confirmable - // database::error::block_valid - // database::error::unknown_state (debugging) - // database::error::unvalidated - const auto ec = query.get_header_state(id); - // All header states are duplicates, one implies fail. - if (ec == database::error::block_unconfirmable) + if (query.is_unconfirmable(id)) { height = query.get_height(id); - return ec; + return database::error::block_unconfirmable; } // height set to max_size_t unless unconfirmable. diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index b98de698..6f2a559f 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -208,53 +208,30 @@ void chaser_validate::do_bumped(height_t height) NOEXCEPT while ((validate_backlog_ < maximum_backlog_) && !closed() && !suspended()) { const auto link = query.to_candidate(height); - const auto ec = query.get_block_state(link); + const auto state = query.get_block_state(link); // Must exit on unassociated so they are not set valid in bypass. // Given height-based iteration, any block state may be enountered. - if (ec == database::error::unassociated) + if (!database::is_associated(state)) return; // The last job requiring validation has been posted. if (height == maximum_height_) maximum_posted_ = true; - const auto bypass = is_under_checkpoint(height) || - query.is_milestone(link); - const auto silent = query.is_silent(link, height); + if (database::is_unconfirmable(state)) + return; - switch (ec.value()) + const auto bypass = database::is_bypass(state); + if (database::is_validated(state) || + (bypass && !filter_ && !query.is_silent(link, height))) + { + complete_block(error::success, link, height, true); + } + else { - case database::error::unvalidated: - case database::error::unknown_state: - { - if (bypass && !filter_ && !silent) - { - complete_block(error::success, link, height, true); - } - else - { - ++validate_backlog_; - post_block(link, bypass); - } - break; - } - case database::error::block_valid: - case database::error::block_confirmable: - { - complete_block(error::success, link, height, true); - break; - } - case database::error::block_unconfirmable: - { - return; - } - ////case database::error::unassociated - default: - { - fault(error::validate1); - return; - } + ++validate_backlog_; + post_block(link, bypass); } // All posted validations must complete or this is invalid. diff --git a/src/protocols/protocol_block_in_31800.cpp b/src/protocols/protocol_block_in_31800.cpp index a0930435..2e06fd48 100644 --- a/src/protocols/protocol_block_in_31800.cpp +++ b/src/protocols/protocol_block_in_31800.cpp @@ -286,7 +286,7 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec, const auto link = it->link; const auto height = it->context.height; const auto checked = is_under_checkpoint(height); - const auto bypass = checked || query.is_milestone(link); + const auto bypass = query.is_bypass(link); if (node_pruned_ && bypass && block.is_segregated()) { LOGR("Unexpected witness from [" << opposite() << "]."); @@ -441,8 +441,8 @@ bool protocol_block_in_31800::is_under_checkpoint(size_t height) const NOEXCEPT type_id protocol_block_in_31800::to_block_type( const association& item) const NOEXCEPT { - return node_pruned_ && (is_under_checkpoint(item.context.height) || - archive().is_milestone(item.link)) ? type_id::block : block_type_; + return node_pruned_ && archive().is_bypass(item.link) ? type_id::block : + block_type_; } BC_POP_WARNING() diff --git a/src/protocols/protocol_block_out_106.cpp b/src/protocols/protocol_block_out_106.cpp index 31babdd8..cdc0d9f6 100644 --- a/src/protocols/protocol_block_out_106.cpp +++ b/src/protocols/protocol_block_out_106.cpp @@ -248,7 +248,7 @@ bool protocol_block_out_106::is_servable(const hash_digest& LOG_ONLY(hash), } const auto& query = archive(); - if (node_pruned_ && (is_under_checkpoint(link) || query.is_milestone(link))) + if (node_pruned_ && query.is_bypass(link)) { LOGV("Requested pruned block " << encode_hash(hash) << " from [" << opposite() << "]."); @@ -305,19 +305,6 @@ protocol_block_out_106::inventory protocol_block_out_106::create_inventory( ); } -bool protocol_block_out_106::is_under_checkpoint( - const database::header_link& link) NOEXCEPT -{ - const auto height = archive().get_height(link); - if (height.is_terminal()) - { - fault(database::error::integrity); - return false; - } - - return height <= top_checkpoint_height_; -} - BC_POP_WARNING() BC_POP_WARNING() BC_POP_WARNING() diff --git a/test/chasers/chaser_confirm.cpp b/test/chasers/chaser_confirm.cpp index 8443af99..7784d7d9 100644 --- a/test/chasers/chaser_confirm.cpp +++ b/test/chasers/chaser_confirm.cpp @@ -236,6 +236,11 @@ static void confirm_uncheckpointed(configuration& config) config.bitcoin.checkpoints.clear(); } +static bool is_valid_only(database::block_state state) +{ + return database::is_validated(state) && !database::is_confirmable(state); +} + struct confirm_setup_fixture { DELETE_COPY_MOVE(confirm_setup_fixture); @@ -325,11 +330,12 @@ struct confirm_setup_fixture }); } - bool stated(const chain::block& block, const code& expected) + bool stated(const chain::block& block, + bool(*expected)(database::block_state)) { return await([&]() { - return query_.get_block_state(link(block)) == expected; + return expected(query_.get_block_state(link(block))); }); } }; @@ -484,27 +490,27 @@ BOOST_AUTO_TEST_SUITE(chaser_confirm_tests) ////{ //// BOOST_REQUIRE(confirmed(confirm_d2(), 2)); //// BOOST_REQUIRE(confirmed(confirm_d1(), 1)); -//// BOOST_REQUIRE(stated(confirm_d2(), database::error::block_confirmable)); +//// BOOST_REQUIRE(stated(confirm_d2(), database::is_confirmable)); //// BOOST_REQUIRE(!query_.is_confirmed_block(link(confirm_c1()))); ////} ////BOOST_FIXTURE_TEST_CASE(chaser_confirm__start__weaker_candidate_fork__not_reorganized, confirm_weaker_fixture) ////{ -//// BOOST_REQUIRE(stated(confirm_d1(), database::error::block_valid)); +//// BOOST_REQUIRE(stated(confirm_d1(), is_valid_only)); //// BOOST_REQUIRE(confirmed(confirm_c2(), 2)); //// BOOST_REQUIRE(confirmed(confirm_c1(), 1)); ////} ////BOOST_FIXTURE_TEST_CASE(chaser_confirm__start__immature_spend__unconfirmable, confirm_immature_fixture) ////{ -//// BOOST_REQUIRE(stated(confirm_e2(), database::error::block_unconfirmable)); +//// BOOST_REQUIRE(stated(confirm_e2(), database::is_unconfirmable)); //// BOOST_REQUIRE(confirmed(confirm_d1(), 1)); //// BOOST_REQUIRE_EQUAL(query_.get_top_confirmed(), 1u); ////} ////BOOST_FIXTURE_TEST_CASE(chaser_confirm__start__immature_spend_fork__unconfirmable, confirm_immature_fork_fixture) ////{ -//// BOOST_REQUIRE(stated(confirm_e2(), database::error::block_unconfirmable)); +//// BOOST_REQUIRE(stated(confirm_e2(), database::is_unconfirmable)); //// BOOST_REQUIRE(await([&]() { return query_.get_top_confirmed() == 1u; })); //// BOOST_REQUIRE(!query_.is_confirmed_block(link(confirm_e2()))); ////} @@ -512,13 +518,13 @@ BOOST_AUTO_TEST_SUITE(chaser_confirm_tests) BOOST_FIXTURE_TEST_CASE(chaser_confirm__start__current_candidates__organized, confirm_current_fixture) { BOOST_REQUIRE(confirmed(confirm_d2(), 2)); - BOOST_REQUIRE(stated(confirm_d2(), database::error::block_confirmable)); + BOOST_REQUIRE(stated(confirm_d2(), database::is_confirmable)); } BOOST_FIXTURE_TEST_CASE(chaser_confirm__start__valid_candidate_without_filter_body__suspended, confirm_unfiltered_fixture) { BOOST_REQUIRE(await([&]() { return node_.suspended(); })); - BOOST_REQUIRE(stated(confirm_d1(), database::error::block_valid)); + BOOST_REQUIRE(stated(confirm_d1(), is_valid_only)); BOOST_REQUIRE_EQUAL(query_.get_top_confirmed(), zero); } @@ -574,7 +580,7 @@ BOOST_FIXTURE_TEST_CASE(chaser_confirm__start__bypassed_candidate_unheaded_paren ////BOOST_FIXTURE_TEST_CASE(chaser_confirm__start__valid_candidate_without_prevouts__suspended_unconfirmable, confirm_unprevouted_fixture) ////{ //// BOOST_REQUIRE(await([&]() { return node_.suspended(); })); -//// BOOST_REQUIRE(stated(confirm_e2(), database::error::block_unconfirmable)); +//// BOOST_REQUIRE(stated(confirm_e2(), database::is_unconfirmable)); //// BOOST_REQUIRE(await([&]() { return query_.get_top_confirmed() == zero; })); ////} diff --git a/test/chasers/chaser_validate.cpp b/test/chasers/chaser_validate.cpp index d8766551..277b1ed1 100644 --- a/test/chasers/chaser_validate.cpp +++ b/test/chasers/chaser_validate.cpp @@ -224,6 +224,11 @@ static void validate_current(configuration& config) config.node.currency_window_minutes = 0; } +static bool is_valid_only(database::block_state state) +{ + return database::is_validated(state) && !database::is_confirmable(state); +} + struct validate_setup_fixture { DELETE_COPY_MOVE(validate_setup_fixture); @@ -300,7 +305,7 @@ struct validate_setup_fixture return false; } - code state(const chain::block& block) const + database::block_state state(const chain::block& block) const { return query_.get_block_state(query_.to_header(block.hash())); } @@ -310,9 +315,10 @@ struct validate_setup_fixture return await([&]() { return query_.get_top_confirmed() == top; }); } - bool stated(const chain::block& block, const code& expected) + bool stated(const chain::block& block, + bool(*expected)(database::block_state)) { - return await([&]() { return state(block) == expected; }); + return await([&]() { return expected(state(block)); }); } }; @@ -518,26 +524,26 @@ struct validate_drain_accessor BOOST_FIXTURE_TEST_CASE(chaser_validate__start__unvalidated_candidates__confirmable, validate_unvalidated_fixture) { BOOST_REQUIRE(confirmed(2)); - BOOST_REQUIRE(stated(validate_a1(), database::error::block_confirmable)); - BOOST_REQUIRE(stated(validate_a2(), database::error::block_confirmable)); + BOOST_REQUIRE(stated(validate_a1(), database::is_confirmable)); + BOOST_REQUIRE(stated(validate_a2(), database::is_confirmable)); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__current_candidates__confirmable, validate_current_fixture) { BOOST_REQUIRE(confirmed(2)); - BOOST_REQUIRE(stated(validate_a1(), database::error::block_confirmable)); - BOOST_REQUIRE(stated(validate_a2(), database::error::block_confirmable)); + BOOST_REQUIRE(stated(validate_a1(), database::is_confirmable)); + BOOST_REQUIRE(stated(validate_a2(), database::is_confirmable)); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__overspent_coinbase__unconfirmable, validate_overspent_fixture) { - BOOST_REQUIRE(stated(validate_overspent1(), database::error::block_unconfirmable)); + BOOST_REQUIRE(stated(validate_overspent1(), database::is_unconfirmable)); BOOST_REQUIRE_EQUAL(query_.get_top_confirmed(), zero); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__missing_prevout__unconfirmable, validate_missing_fixture) { - BOOST_REQUIRE(stated(validate_missing2(), database::error::block_unconfirmable)); + BOOST_REQUIRE(stated(validate_missing2(), database::is_unconfirmable)); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__checkpointed_candidates__organized, validate_checkpointed_fixture) @@ -553,25 +559,25 @@ BOOST_FIXTURE_TEST_CASE(chaser_validate__start__checkpointed_unfiltered_candidat BOOST_FIXTURE_TEST_CASE(chaser_validate__start__prevalidated_candidates__valid_organized, validate_prevalidated_fixture) { BOOST_REQUIRE(confirmed(1)); - BOOST_REQUIRE(stated(validate_a1(), database::error::block_confirmable)); - BOOST_REQUIRE(stated(validate_a2(), database::error::block_unconfirmable)); + BOOST_REQUIRE(stated(validate_a1(), database::is_confirmable)); + BOOST_REQUIRE(stated(validate_a2(), database::is_unconfirmable)); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__maximum_height__confirmable, validate_maximum_fixture) { - BOOST_REQUIRE(stated(validate_a1(), database::error::block_confirmable)); + BOOST_REQUIRE(stated(validate_a1(), database::is_confirmable)); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__staged_prevalid__validated_iff_accelerated, validate_staged_fixture) { BOOST_REQUIRE_EQUAL(query_.prevalid0_records(), zero); - BOOST_REQUIRE_EQUAL(state(validate_x1()) == database::error::block_valid, system::batched::accelerated()); + BOOST_REQUIRE_EQUAL(is_valid_only(state(validate_x1())), system::batched::accelerated()); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__staged_second_bank__validated_iff_accelerated, validate_staged_second_fixture) { BOOST_REQUIRE_EQUAL(query_.prevalid_records(true), zero); - BOOST_REQUIRE_EQUAL(state(validate_x1()) == database::error::block_valid, system::batched::accelerated()); + BOOST_REQUIRE_EQUAL(is_valid_only(state(validate_x1())), system::batched::accelerated()); } BOOST_FIXTURE_TEST_CASE(chaser_validate__process_batch__residual_commit_during_drain__drained, validate_noncandidates_fixture) @@ -585,15 +591,15 @@ BOOST_FIXTURE_TEST_CASE(chaser_validate__process_batch__residual_commit_during_d BOOST_REQUIRE(instance.lost_); BOOST_REQUIRE(is_zero(query_.prevalid_records(false))); BOOST_REQUIRE(is_zero(query_.prevalid_records(true))); - BOOST_REQUIRE_EQUAL(state(validate_x1()), database::error::block_valid); - BOOST_REQUIRE_EQUAL(state(validate_a1()), database::error::block_valid); + BOOST_REQUIRE(is_valid_only(state(validate_x1()))); + BOOST_REQUIRE(is_valid_only(state(validate_a1()))); } BOOST_FIXTURE_TEST_CASE(chaser_validate__windowed__prevalid__valid, validate_windowed_fixture) { BOOST_REQUIRE(query_.set_prevalid(query_.to_header(validate_x1().hash()), false)); node_.notify(node::error::success, chases::windowed{ 1 }); - BOOST_REQUIRE(stated(validate_x1(), database::error::block_valid)); + BOOST_REQUIRE(stated(validate_x1(), is_valid_only)); BOOST_REQUIRE(await([&]() { return is_zero(query_.prevalid0_records()); })); } @@ -605,7 +611,7 @@ BOOST_FIXTURE_TEST_CASE(chaser_validate__windowed__invalid_ecdsa_signature__unco BOOST_REQUIRE(query_.set_signatures(signatures, link, false)); BOOST_REQUIRE(query_.set_prevalid(link, false)); node_.notify(node::error::success, chases::windowed{ 1 }); - BOOST_REQUIRE(stated(validate_x1(), database::error::block_unconfirmable)); + BOOST_REQUIRE(stated(validate_x1(), database::is_unconfirmable)); BOOST_REQUIRE(await([&]() { return is_zero(query_.ecdsa0_records()) && is_zero(query_.prevalid0_records()); })); } @@ -617,7 +623,7 @@ BOOST_FIXTURE_TEST_CASE(chaser_validate__windowed__invalid_schnorr_signature__un BOOST_REQUIRE(query_.set_signatures(signatures, link, false)); BOOST_REQUIRE(query_.set_prevalid(link, false)); node_.notify(node::error::success, chases::windowed{ 1 }); - BOOST_REQUIRE(stated(validate_x1(), database::error::block_unconfirmable)); + BOOST_REQUIRE(stated(validate_x1(), database::is_unconfirmable)); BOOST_REQUIRE(await([&]() { return is_zero(query_.schnorr0_records()) && is_zero(query_.prevalid0_records()); })); } @@ -629,7 +635,7 @@ BOOST_FIXTURE_TEST_CASE(chaser_validate__windowed__invalid_schnorr_signature__un //// node_.notify(node::error::success, chases::disorganized{ 0 }); //// node_.notify(node::error::success, chases::bump{ 0 }); //// node_.notify(node::error::success, chases::checked{ 1 }); -//// BOOST_REQUIRE(stated(validate_a2(), database::error::block_confirmable)); +//// BOOST_REQUIRE(stated(validate_a2(), database::is_confirmable)); //// BOOST_REQUIRE_EQUAL(query_.get_top_confirmed(), 2u); ////} @@ -639,26 +645,26 @@ BOOST_FIXTURE_TEST_CASE(chaser_validate__bump__unfull_new_candidate__confirmable BOOST_REQUIRE(validate_candidate(query_, validate_a3(), 3)); node_.notify(node::error::success, chases::unfull{}); node_.notify(node::error::success, chases::bump{ 0 }); - BOOST_REQUIRE(stated(validate_a3(), database::error::block_confirmable)); + BOOST_REQUIRE(stated(validate_a3(), database::is_confirmable)); BOOST_REQUIRE(confirmed(3)); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__immature_internal_spend__unconfirmable, validate_immature_fixture) { - BOOST_REQUIRE(stated(validate_immature1(), database::error::block_unconfirmable)); + BOOST_REQUIRE(stated(validate_immature1(), database::is_unconfirmable)); BOOST_REQUIRE_EQUAL(query_.get_top_confirmed(), zero); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__extra_coinbases__unconfirmable, validate_coinbases_fixture) { - BOOST_REQUIRE(stated(validate_coinbases1(), database::error::block_unconfirmable)); + BOOST_REQUIRE(stated(validate_coinbases1(), database::is_unconfirmable)); BOOST_REQUIRE_EQUAL(query_.get_top_confirmed(), zero); } BOOST_FIXTURE_TEST_CASE(chaser_validate__start__current_overspent_coinbase__unconfirmable, validate_current_overspent_fixture) { - BOOST_REQUIRE(stated(validate_overspent1(), database::error::block_unconfirmable)); + BOOST_REQUIRE(stated(validate_overspent1(), database::is_unconfirmable)); BOOST_REQUIRE_EQUAL(query_.get_top_confirmed(), zero); }