From 243ec11c8f63ac3101b6fc83501d24251490154f Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 18 Nov 2024 18:49:32 -0500 Subject: [PATCH 1/8] Put validator message processing on own strand. --- .../bitcoin/node/chasers/chaser_validate.hpp | 2 + src/chasers/chaser_validate.cpp | 73 ++++++++++--------- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser_validate.hpp b/include/bitcoin/node/chasers/chaser_validate.hpp index 90f6fe9f..6119e10f 100644 --- a/include/bitcoin/node/chasers/chaser_validate.hpp +++ b/include/bitcoin/node/chasers/chaser_validate.hpp @@ -73,8 +73,10 @@ class BCN_API chaser_validate // These are protected by strand. network::threadpool threadpool_; + network::asio::strand strand_; system::hash_digest neutrino_{}; size_t validation_backlog_{}; + bool mature_{}; }; } // namespace node diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index f119aa12..c3cedad5 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -42,13 +42,8 @@ BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR) BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED) BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) -// maximum_backlog is the limit of ASIO backlog in blocks. -// There is almost no cost the the backlog, as it's on an independent -// threadpool and contains only the header link value. It's better to avoid -// a costly query to get the tx count (for example) and allow the amount of -// actual work that is queued to vary significantly. The maximum_concurrency -// setting is overloaded for the purpose of limiting the backlog. - +// Multiple higher priority thread strand (base class strand uses network pool). +// Higher priority than downloader (net) ensures locality to downloader writes. chaser_validate::chaser_validate(full_node& node) NOEXCEPT : chaser(node), prepopulate_(node.config().node.prepopulate), @@ -58,7 +53,8 @@ chaser_validate::chaser_validate(full_node& node) NOEXCEPT subsidy_interval_(node.config().bitcoin.subsidy_interval_blocks), threadpool_(std::max(node.config().node.threads, 1_u32), node.config().node.priority_validation ? - network::thread_priority::high : network::thread_priority::normal) + network::thread_priority::high : network::thread_priority::normal), + strand_(threadpool_.service().get_executor()) { } @@ -96,18 +92,17 @@ bool chaser_validate::handle_event(const code&, chase event_, return true; // These come out of order, advance in order asynchronously. - // Asynchronous completion results in out of order notification. + // Asynchronous completion again results in out of order notification. switch (event_) { - // Track downloaded. - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ case chase::start: case chase::bump: { - // TODO: currency? - if (concurrent_ /*|| is_current(archive().to_candidate(height))*/) + if (concurrent_ || mature_) { - POST(do_bump, height_t{}); + ////POST(do_bump, height_t{}); + boost::asio::post(strand_, + BIND(do_bump, height_t{})); } break; @@ -117,11 +112,11 @@ bool chaser_validate::handle_event(const code&, chase event_, // value is checked block height. BC_ASSERT(std::holds_alternative(value)); - // TODO: height may be premature due to concurrent download. - const auto height = std::get(value); - if (concurrent_ /*|| is_current(archive().to_candidate(height))*/) + if (concurrent_ || mature_) { - POST(do_checked, height); + ////POST(do_checked, std::get(value)); + boost::asio::post(strand_, + BIND(do_checked, std::get(value))); } break; @@ -129,16 +124,19 @@ bool chaser_validate::handle_event(const code&, chase event_, case chase::regressed: { BC_ASSERT(std::holds_alternative(value)); - POST(do_regressed, std::get(value)); + ////POST(do_regressed, std::get(value)); + boost::asio::post(strand_, + BIND(do_regressed, std::get(value))); break; } case chase::disorganized: { BC_ASSERT(std::holds_alternative(value)); - POST(do_regressed, std::get(value)); + ////POST(do_regressed, std::get(value)); + boost::asio::post(strand_, + BIND(do_regressed, std::get(value))); break; } - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ case chase::stop: { return false; @@ -180,7 +178,6 @@ void chaser_validate::do_bump(height_t) NOEXCEPT BC_ASSERT(stranded()); const auto& query = archive(); - // Validate checked blocks starting immediately after last validated. // Bypass until next event if validation backlog is full. for (auto height = add1(position()); (validation_backlog_ < maximum_backlog_) && !closed(); ++height) @@ -188,16 +185,13 @@ void chaser_validate::do_bump(height_t) NOEXCEPT const auto link = query.to_candidate(height); const auto ec = query.get_block_state(link); - // TODO: Block until ungapped to current and then start at top validated. - - // Wait until the gap is filled at a current height. + // Wait until the gap is filled at a current height (or next top). if (ec == database::error::unassociated) return; // The size of the job is not relevant to the backlog cost. ++validation_backlog_; - // Causes a reorganization (should have been encountered by headers). if (ec == database::error::block_unconfirmable) { complete_block(ec, link, height); @@ -214,9 +208,9 @@ void chaser_validate::do_bump(height_t) NOEXCEPT continue; } - // Report backlog, should generally not exceed dowload window. - ////fire(events::block_buffered, validation_backlog_); - boost::asio::post(threadpool_.service(), BIND(validate_block, link)); + // concurrent by block + boost::asio::post(threadpool_.service(), + BIND(validate_block, link)); } } @@ -229,14 +223,18 @@ void chaser_validate::validate_block(const header_link& link) NOEXCEPT const auto block = query.get_block(link); if (!block) { - POST(complete_block, database::error::integrity, link, zero); + ////POST(complete_block, database::error::integrity, link, zero); + boost::asio::post(strand_, + BIND(complete_block, database::error::integrity, link, zero)); return; } chain::context ctx{}; if (!query.get_context(ctx, link)) { - POST(complete_block, database::error::integrity, link, zero); + ////POST(complete_block, database::error::integrity, link, zero); + boost::asio::post(strand_, + BIND(complete_block, database::error::integrity, link, zero)); return; } @@ -247,7 +245,9 @@ void chaser_validate::validate_block(const header_link& link) NOEXCEPT if (!query.populate(*block)) { // This could instead be a case of invalid milestone. - POST(complete_block, database::error::integrity, link, ctx.height); + ////POST(complete_block, database::error::integrity, link, ctx.height); + boost::asio::post(strand_, + BIND(complete_block, database::error::integrity, link, ctx.height)); return; } @@ -269,7 +269,9 @@ void chaser_validate::validate_block(const header_link& link) NOEXCEPT fire(events::block_validated, ctx.height); } - POST(complete_block, ec, link, ctx.height); + ////POST(complete_block, ec, link, ctx.height); + boost::asio::post(strand_, + BIND(complete_block, ec, link, ctx.height)); } void chaser_validate::complete_block(const code& ec, const header_link& link, @@ -303,6 +305,11 @@ void chaser_validate::complete_block(const code& ec, const header_link& link, // neutrino // ---------------------------------------------------------------------------- +// Since neutrino filters must be computed in block order, and require full +// block and previous output deserialization, configuration of this option +// implies either ordered validation or re-deserialization of 115% of the store +// in another chaser or populated block caching in that chaser (which implies a +// controlled/narrow window of concurrent validation). // Returns null_hash if not found, intended for genesis block. hash_digest chaser_validate::get_neutrino(size_t height) const NOEXCEPT From 9b703852fcf01c06edcc6c6612e93b4aa06b4a8f Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 18 Nov 2024 18:49:46 -0500 Subject: [PATCH 2/8] Simplify confirm chaser (WIP). --- .../bitcoin/node/chasers/chaser_confirm.hpp | 26 +- src/chasers/chaser_confirm.cpp | 437 +++++++----------- 2 files changed, 166 insertions(+), 297 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp index 3dbd47fc..e03a6928 100644 --- a/include/bitcoin/node/chasers/chaser_confirm.hpp +++ b/include/bitcoin/node/chasers/chaser_confirm.hpp @@ -51,24 +51,11 @@ class BCN_API chaser_confirm event_value value) NOEXCEPT; virtual void do_validated(height_t height) NOEXCEPT; - virtual void do_reorganize(size_t height) NOEXCEPT; - virtual void do_organize(size_t height) NOEXCEPT; - - virtual void enqueue_block(const database::header_link& link) NOEXCEPT; - virtual void confirm_tx(const database::context& ctx, - const database::tx_link& link, const race::ptr& racer) NOEXCEPT; - virtual void handle_tx(const code& ec, const database::tx_link& tx, - const race::ptr& racer) NOEXCEPT; - virtual void handle_txs(const code& ec, const database::tx_link& tx, - const database::header_link& link, size_t height)NOEXCEPT; - virtual void confirm_block(const code& ec, - const database::header_link& link, size_t height) NOEXCEPT; - virtual void next_block(size_t height) NOEXCEPT; + virtual void do_reorganize(header_links& fork, size_t fork_point) NOEXCEPT; + virtual void do_organize(header_links& fork, const header_links& popped, + size_t fork_point) NOEXCEPT; private: - void reset() NOEXCEPT; - bool busy() const NOEXCEPT; - bool set_organized(const database::header_link& link, height_t height) NOEXCEPT; bool reset_organized(const database::header_link& link, @@ -77,8 +64,6 @@ class BCN_API chaser_confirm height_t height) NOEXCEPT; bool roll_back(const header_links& popped, size_t fork_point, size_t top) NOEXCEPT; - bool roll_back(const header_links& popped, size_t fork_point, - size_t top, const database::header_link& link) NOEXCEPT; bool get_fork_work(uint256_t& fork_work, header_links& fork, height_t fork_top) const NOEXCEPT; @@ -90,9 +75,8 @@ class BCN_API chaser_confirm // These are protected by strand. network::threadpool threadpool_; - header_links popped_{}; - header_links fork_{}; - size_t fork_point_{}; + network::asio::strand strand_; + bool mature_{}; }; } // namespace node diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index 2794f390..42c47448 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -36,13 +37,14 @@ using namespace std::placeholders; BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) -// threads and priority_validation currently overloading validation settings. +// Single higher priority thread strand (base class strand uses network pool). +// Higher priority than validator ensures locality to validator reads. chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT : chaser(node), concurrent_(node.config().node.concurrent_confirmation), - threadpool_(std::max(node.config().node.threads, 1_u32), - node.config().node.priority_validation ? - network::thread_priority::high : network::thread_priority::normal) + threadpool_(one, node.config().node.priority_validation ? + network::thread_priority::highest : network::thread_priority::high), + strand_(threadpool_.service().get_executor()) { } @@ -77,6 +79,7 @@ bool chaser_confirm::handle_event(const code&, chase event_, if (closed()) return false; + // TODO: resume needs to ensure a bump. // Stop generating query during suspension. if (suspended()) return true; @@ -87,9 +90,16 @@ bool chaser_confirm::handle_event(const code&, chase event_, { case chase::blocks: { - // TODO: value is branch point. BC_ASSERT(std::holds_alternative(value)); - POST(do_validated, std::get(value)); + + if (concurrent_ || mature_) + { + ////// TODO: value is branch point. + ////POST(do_validated, std::get(value)); + ////boost::asio::post(strand_, + //// BIND(do_validated, std::get(value))); + } + break; } case chase::valid: @@ -97,11 +107,11 @@ bool chaser_confirm::handle_event(const code&, chase event_, // value is validated block height. BC_ASSERT(std::holds_alternative(value)); - // TODO: height may be premature due to concurrent download. - const auto height = std::get(value); - if (concurrent_ /*|| is_current(archive().to_candidate(height))*/) + if (concurrent_ || mature_) { - POST(do_validated, height); + ////POST(do_validated, std::get(value)); + boost::asio::post(strand_, + BIND(do_validated, std::get(value))); } break; @@ -121,75 +131,71 @@ bool chaser_confirm::handle_event(const code&, chase event_, // confirm // ---------------------------------------------------------------------------- -// Blocks are either confirmed (blocks first) or validated/confirmed -// (headers first) here. Candidate chain reorganizations will result in -// reported heights moving in any direction. Each is treated as independent and -// only one representing a stronger chain is considered. +// Blocks are either confirmed (blocks first) or validated/confirmed (headers +// first) here. Candidate chain reorganizations will result in reported heights +// moving in any direction. Each is treated as independent and only one +// representing a stronger chain is considered. -// Compute relative work, set fork_ and fork_point_. +// Compute relative work, set fork and fork_point, and invoke reorganize. void chaser_confirm::do_validated(height_t height) NOEXCEPT { BC_ASSERT(stranded()); - if (closed() || busy()) + if (closed()) return; bool strong{}; uint256_t work{}; + header_links fork{}; - // Scan down from height to first confirmed, accumulate links and sum work. - if (!get_fork_work(work, fork_, height)) + // Scan from validated height to first confirmed, save links, and sum work. + if (!get_fork_work(work, fork, height)) { fault(error::get_fork_work); return; } - // No longer a candidate fork (heights are not candidates). - if (fork_.empty()) + // No longer a candidate fork (may have been reorganized). + if (fork.empty()) return; - // fork_point is the highest candidate-confirmed common block. - fork_point_ = height - fork_.size(); - if (!get_is_strong(strong, work, fork_point_)) + // fork_point is the highest candidate <-> confirmed common block. + const auto fork_point = height - fork.size(); + if (!get_is_strong(strong, work, fork_point)) { fault(error::get_is_strong); return; } - // Not yet a strong fork (confirmed branch has at least as much work). - if (!strong) - { - reset(); - return; - } - - do_reorganize(archive().get_top_confirmed()); + // Fork is strong (has more work than confirmed branch). + if (strong) + do_reorganize(fork, fork_point); } -// Pop confirmed chain from height down to above fork point, save popped_. -void chaser_confirm::do_reorganize(size_t height) NOEXCEPT +// Pop confirmed chain from top down to above fork point, save popped. +void chaser_confirm::do_reorganize(header_links& fork, size_t fork_point) NOEXCEPT { - BC_ASSERT(stranded()); + auto& query = archive(); - if (height < fork_point_) + auto top = query.get_top_confirmed(); + if (top < fork_point) { fault(error::invalid_fork_point); return; } - popped_.clear(); - auto& query = archive(); - while (height > fork_point_) + header_links popped{}; + while (top > fork_point) { - const auto link = query.to_confirmed(height); - if (link.is_terminal()) + const auto top_link = query.to_confirmed(top); + if (top_link.is_terminal()) { fault(error::to_confirmed); return; } - popped_.push_back(link); - if (!query.set_unstrong(link)) + popped.push_back(top_link); + if (!query.set_unstrong(top_link)) { fault(error::set_unstrong); return; @@ -201,265 +207,149 @@ void chaser_confirm::do_reorganize(size_t height) NOEXCEPT return; } - notify(error::success, chase::reorganized, popped_.back()); - fire(events::block_reorganized, height--); + notify(error::success, chase::reorganized, top_link); + fire(events::block_reorganized, top--); } - do_organize(add1(height)); + // Top is now fork_point. + do_organize(fork, popped, fork_point); } // Push candidate headers from above fork point to confirmed chain. -void chaser_confirm::do_organize(size_t height) NOEXCEPT +void chaser_confirm::do_organize(header_links& fork, + const header_links& popped, size_t fork_point) NOEXCEPT { - BC_ASSERT(stranded()); - if (fork_.empty()) - return; - auto& query = archive(); - const auto& link = fork_.back(); - const auto bypass = is_under_checkpoint(height) || - query.is_milestone(link); - if (!bypass) + // height tracks each fork link, starting at fork_point+1. + size_t height = fork_point; + + while (!fork.empty()) { - const auto ec = query.get_block_state(link); + ++height; + const auto& link = fork.back(); - if (ec == database::error::block_valid) + if (is_under_checkpoint(height) || query.is_milestone(link)) { - if (!query.set_strong(link)) + notify(error::success, chase::confirmable, height); + fire(events::confirm_bypassed, height); + LOGV("Block confirmation bypassed and organized: " << height); + + // Checkpoint and milestone are already set_strong. + if (!set_organized(link, height)) { - fault(error::set_strong); + fault(database::error::integrity); return; } - - enqueue_block(link); - return; } - else if (ec == database::error::block_confirmable) + else { - // Required of all confirmed, and before checking confirmable. - // Checked blocks are set at download, cannot be unset (reorged). - // Milestone blocks are set/unset strong by header organization. - if (!query.set_strong(link)) + auto ec = query.get_block_state(link); + if (ec == database::error::block_valid) { - fault(error::set_strong); + if (!query.set_strong(link)) + { + fault(database::error::integrity); + return; + } + + // This spawns threads internally, blocking until complete. + if ((ec = query.block_confirmable(link))) + { + if (ec == database::error::integrity) + { + fault(database::error::integrity); + return; + } + + notify(ec, chase::unconfirmable, link); + fire(events::block_unconfirmable, height); + LOGR("Unconfirmable block [" << height << "] " + << ec.message()); + + if (!query.set_unstrong(link)) + { + fault(database::error::integrity); + return; + } + + if (!query.set_block_unconfirmable(link)) + { + fault(database::error::integrity); + return; + } + + if (!roll_back(popped, fork_point, sub1(height))) + fault(database::error::integrity); + + return; + } + + // TODO: fees. + if (!query.set_block_confirmable(link, {})) + { + fault(database::error::integrity); + return; + } + + notify(ec, chase::confirmable, height); + fire(events::block_confirmed, height); + LOGV("Block confirmed and organized: " << height); + + if (!set_organized(link, height)) + fault(database::error::integrity); + return; } + else if (ec == database::error::block_confirmable) + { + if (!query.set_strong(link)) + { + fault(database::error::integrity); + return; + } - // falls through (previously confirmable, reported as bypass) - } - else if (ec == database::error::block_unconfirmable) - { - notify(ec, chase::unconfirmable, link); - fire(events::block_unconfirmable, height); - - // Roll back previously confirmed blocks. - if (!roll_back(popped_, fork_point_, sub1(height))) - fault(error::node_roll_back); - - reset(); - return; - } - else - { - // With or without an error code, shouldn't be here. - // database::error::block_valid [canonical state ] - // database::error::block_confirmable [resurrected state] - // database::error::block_unconfirmable [shouldn't be here] ? - // database::error::unknown_state [shouldn't be here] - // database::error::unassociated [shouldn't be here] - // database::error::unvalidated [shouldn't be here] - fault(error::node_confirm); - return; - } - } - - notify(error::success, chase::confirmable, height); - fire(events::confirm_bypassed, height); - - if (!set_organized(link, height)) - { - fault(error::set_organized); - return; - } - - POST(next_block, add1(height)); - return; -} - -// DISTRUBUTE WORK UNITS -void chaser_confirm::enqueue_block(const header_link& link) NOEXCEPT -{ - BC_ASSERT(stranded()); - const auto& query = archive(); - - context ctx{}; - const auto txs = query.to_transactions(link); - if (txs.empty() || !query.get_context(ctx, link)) - { - POST(confirm_block, database::error::integrity, link, size_t{}); - return; - } - - code ec{}; - const auto height = ctx.height; - if ((ec = query.unspent_duplicates(txs.front(), ctx))) - { - POST(confirm_block, ec, link, height); - return; - } - - if (is_one(txs.size())) - { - POST(confirm_block, ec, link, height); - return; - } - - const auto racer = std::make_shared(sub1(txs.size())); - racer->start(BIND(handle_txs, _1, _2, link, height)); - fire(events::block_buffered, height); - - for (auto tx = std::next(txs.begin()); tx != txs.end(); ++tx) - boost::asio::post(threadpool_.service(), - BIND(confirm_tx, ctx, *tx, racer)); -} - -// START WORK UNIT -void chaser_confirm::confirm_tx(const context& ctx, const tx_link& link, - const race::ptr& racer) NOEXCEPT -{ - const auto ec = archive().tx_confirmable(link, ctx); - POST(handle_tx, ec, link, racer); -} - -// FINISH WORK UNIT -void chaser_confirm::handle_tx(const code& ec, const tx_link& tx, - const race::ptr& racer) NOEXCEPT -{ - BC_ASSERT(stranded()); - - // handle_txs will only get invoked once, with a first error code, so - // invoke fault here ensure that non-validation codes are not lost. - if (ec == database::error::integrity) - fault(error::node_confirm); - - // TODO: need to sort out bypass, validity, and fault codes. - // Always allow the racer to finish, invokes handle_txs exactly once. - racer->finish(ec, tx); -} - -// SYNCHRONIZE WORK UNITS -void chaser_confirm::handle_txs(const code& ec, const tx_link& tx, - const header_link& link, size_t height) NOEXCEPT -{ - BC_ASSERT(stranded()); - - if (ec) - { - // Log tx here as it's the first failed one. - LOGR("Error confirming tx [" << encode_hash(archive().get_tx_key(tx)) - << "] " << ec.message()); - } - - confirm_block(ec, link, height); -} - -// SUMMARIZE WORK -void chaser_confirm::confirm_block(const code& ec, const header_link& link, - size_t height) NOEXCEPT -{ - BC_ASSERT(stranded()); - auto& query = archive(); + notify(error::success, chase::confirmable, height); + fire(events::confirm_bypassed, height); + LOGV("Block previously confirmable organized: " << height); - if (ec == database::error::integrity) - { - fault(error::node_confirm); - return; - } + if (!set_organized(link, height)) + fault(database::error::integrity); - if (ec) - { - if (!query.set_block_unconfirmable(link)) - { - fault(error::set_block_unconfirmable); - return; - } + return; + } + else if (ec == database::error::block_unconfirmable) + { + notify(ec, chase::unconfirmable, link); + fire(events::block_unconfirmable, height); + LOGV("Block confirmation failed: " << height); - LOGR("Unconfirmable block [" << height << "] " << ec.message()); - notify(ec, chase::unconfirmable, link); - fire(events::block_unconfirmable, height); + if (!roll_back(popped, fork_point, sub1(height))) + fault(database::error::integrity); - // Roll back current and previously confirmed blocks. - if (!roll_back(popped_, fork_point_, height, link)) - { - fault(error::node_roll_back); - return; + return; + } + else + { + // With or without an error code, shouldn't be here. + // database::error::block_valid [canonical state ] + // database::error::block_confirmable [resurrected state] + // database::error::block_unconfirmable [shouldn't be here] ? + // database::error::unknown_state [shouldn't be here] + // database::error::unassociated [shouldn't be here] + // database::error::unvalidated [shouldn't be here] + fault(database::error::integrity); + return; + } } - reset(); - return; - } - - // TODO: move fee setter to set_block_valid (transitory) and propagate to - // TODO: set_block_confirmable (final). Bypassed do not have the fee cache. - if (!query.set_block_confirmable(link, uint64_t{})) - { - fault(error::set_block_confirmable); - return; - } - - notify(error::success, chase::confirmable, height); - fire(events::block_confirmed, height); - if (!set_organized(link, height)) - { - fault(error::set_organized); - return; - } - - LOGV("Block confirmed and organized: " << height); - next_block(add1(height)); -} - -// SHARED ITERATE -void chaser_confirm::next_block(size_t height) NOEXCEPT -{ - BC_ASSERT(stranded()); - - // Continue until fork is empty. - fork_.pop_back(); - if (!fork_.empty()) - { - do_organize(height); - return; - } - - reset(); - const auto& query = archive(); - - // Prevent stall by bumping, as the event may have been missed. - const auto code = query.get_block_state(query.to_candidate(height)); - if ((code == database::error::block_valid) || - (code == database::error::block_confirmable)) - { - do_validated(height); + fork.pop_back(); } } // Private // ---------------------------------------------------------------------------- -void chaser_confirm::reset() NOEXCEPT -{ - fork_.clear(); - popped_.clear(); - fork_point_ = zero; -} - -bool chaser_confirm::busy() const NOEXCEPT -{ - return !fork_.empty(); -} - bool chaser_confirm::set_organized(const header_link& link, height_t) NOEXCEPT { auto& query = archive(); @@ -495,13 +385,8 @@ bool chaser_confirm::set_reorganized(const header_link& link, return true; } -bool chaser_confirm::roll_back(const header_links& popped, - size_t fork_point, size_t top, const header_link& link) NOEXCEPT -{ - // The current block (top/link) is set_strong but is not confirmable. - return archive().set_unstrong(link) && roll_back(popped, fork_point, top); -} - +// Roll back to the specified new top. Header organization may then return the +// node to a previously-stronger branch - no need to do that here. bool chaser_confirm::roll_back(const header_links& popped, size_t fork_point, size_t top) NOEXCEPT { From 609b6346ceca7243575c863f3658ae47afc8341e Mon Sep 17 00:00:00 2001 From: evoskuil Date: Wed, 6 Nov 2024 19:53:14 -0500 Subject: [PATCH 3/8] Update fault codes, balance confirmation threads. --- include/bitcoin/node/error.hpp | 69 +++--- .../node/impl/chasers/chaser_organize.ipp | 32 +-- src/chasers/chaser_confirm.cpp | 59 +++-- src/chasers/chaser_header.cpp | 2 +- src/chasers/chaser_validate.cpp | 18 +- src/error.cpp | 71 +++--- src/protocols/protocol_block_in_31800.cpp | 2 +- test/error.cpp | 232 ++---------------- 8 files changed, 157 insertions(+), 328 deletions(-) diff --git a/include/bitcoin/node/error.hpp b/include/bitcoin/node/error.hpp index 9e7aa6ca..232d09b9 100644 --- a/include/bitcoin/node/error.hpp +++ b/include/bitcoin/node/error.hpp @@ -53,39 +53,52 @@ enum error_t : uint8_t suspended_service, /// blockchain - branch_error, orphan_block, orphan_header, duplicate_block, duplicate_header, - ////validation_bypass, - ////confirmation_bypass, - /// chasers - set_block_unconfirmable, - get_height, - get_branch_work, - get_is_strong, - invalid_branch_point, - pop_candidate, - push_candidate, - invalid_fork_point, - get_candidate_chain_state, - get_block, - get_unassociated, - get_fork_work, - to_confirmed, - pop_confirmed, - get_block_confirmable, - get_block_state, - set_strong, - set_unstrong, - set_organized, - set_block_confirmable, - set_block_valid, - node_confirm, - node_validate, - node_roll_back + /// faults (terminal, code error and store corruption assumed) + protocol1, + header1, + organize1, + organize2, + organize3, + organize4, + organize5, + organize6, + organize7, + organize8, + organize9, + organize10, + organize11, + organize12, + organize13, + organize14, + organize15, + validate1, + validate2, + validate3, + validate4, + validate5, + validate6, + confirm1, + confirm2, + confirm3, + confirm4, + confirm5, + confirm6, + confirm7, + confirm8, + confirm9, + confirm10, + confirm11, + confirm12, + confirm13, + confirm14, + confirm15, + confirm16, + confirm17 }; // No current need for error_code equivalence mapping. diff --git a/include/bitcoin/node/impl/chasers/chaser_organize.ipp b/include/bitcoin/node/impl/chasers/chaser_organize.ipp index 790399d0..a85cf4e3 100644 --- a/include/bitcoin/node/impl/chasers/chaser_organize.ipp +++ b/include/bitcoin/node/impl/chasers/chaser_organize.ipp @@ -57,8 +57,8 @@ code CLASS::start() NOEXCEPT if (!state_) { - fault(error::get_candidate_chain_state); - return error::get_candidate_chain_state; + fault(error::organize1); + return error::organize1; } LOGN("Candidate top [" << system::encode_hash(state_->hash()) << ":" @@ -205,14 +205,14 @@ void CLASS::do_organize(typename Block::cptr block, if (!get_branch_work(work, branch_point, tree_branch, store_branch, header)) { - handler(fault(error::get_branch_work), height); + handler(fault(error::organize2), height); return; } // branch_point is the highest tree-candidate common block. if (!get_is_strong(strong, work, branch_point)) { - handler(fault(error::get_is_strong), height); + handler(fault(error::organize3), height); return; } @@ -235,7 +235,7 @@ void CLASS::do_organize(typename Block::cptr block, const auto top_candidate = state_->height(); if (branch_point > top_candidate) { - handler(fault(error::invalid_branch_point), height); + handler(fault(error::organize4), height); return; } @@ -247,7 +247,7 @@ void CLASS::do_organize(typename Block::cptr block, if ((is_under_milestone(index) && !query.set_unstrong(candidate)) || !query.pop_candidate()) { - handler(fault(error::pop_candidate), height); + handler(fault(error::organize5), height); return; } @@ -264,7 +264,7 @@ void CLASS::do_organize(typename Block::cptr block, if ((is_under_milestone(index) && !query.set_strong(link)) || !query.push_candidate(link)) { - handler(fault(error::push_candidate), height); + handler(fault(error::organize6), height); return; } @@ -347,7 +347,7 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT size_t height{}; if (!query.get_height(height, link) || is_zero(height)) { - fault(error::get_height); + fault(error::organize7); return; } @@ -355,7 +355,7 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT const auto fork_point = query.get_fork(); if (height <= fork_point) { - fault(error::invalid_fork_point); + fault(error::organize8); return; } @@ -365,7 +365,7 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT auto state = query.get_candidate_chain_state(settings_, fork_point); if (!state) { - fault(error::get_candidate_chain_state); + fault(error::organize9); return; } @@ -378,7 +378,7 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT { if (!get_block(block, index)) { - fault(error::get_block); + fault(error::organize10); return; } @@ -398,7 +398,7 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT if ((is_under_milestone(index) && !query.set_unstrong(candidate)) || !query.pop_candidate()) { - fault(error::pop_candidate); + fault(error::organize11); return; } @@ -418,7 +418,7 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT // Confirmed are already set_strong and must stay that way. if (!query.push_candidate(query.to_confirmed(index))) { - fault(error::push_candidate); + fault(error::organize12); return; } @@ -428,7 +428,7 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT state = query.get_candidate_chain_state(settings_, top_confirmed); if (!state) { - fault(error::get_candidate_chain_state); + fault(error::organize13); return; } @@ -552,7 +552,7 @@ code CLASS::push_block(const Block& block, return ec; if (!query.push_candidate(link)) - return error::push_candidate; + return error::organize14; return ec; } @@ -562,7 +562,7 @@ code CLASS::push_block(const system::hash_digest& key) NOEXCEPT { const auto handle = tree_.extract(key); if (!handle) - return error::branch_error; + return error::organize15; const auto& value = handle.mapped(); return push_block(*value.block, value.state->context()); diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index 42c47448..81911e38 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -42,7 +42,9 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT : chaser(node), concurrent_(node.config().node.concurrent_confirmation), - threadpool_(one, node.config().node.priority_validation ? + threadpool_(std::max(ceilinged_add(node.config().node.threads, + node.config().network.threads), 1_u32), + node.config().node.priority_validation ? network::thread_priority::highest : network::thread_priority::high), strand_(threadpool_.service().get_executor()) { @@ -151,7 +153,7 @@ void chaser_confirm::do_validated(height_t height) NOEXCEPT // Scan from validated height to first confirmed, save links, and sum work. if (!get_fork_work(work, fork, height)) { - fault(error::get_fork_work); + fault(error::confirm1); return; } @@ -163,7 +165,7 @@ void chaser_confirm::do_validated(height_t height) NOEXCEPT const auto fork_point = height - fork.size(); if (!get_is_strong(strong, work, fork_point)) { - fault(error::get_is_strong); + fault(error::confirm2); return; } @@ -180,7 +182,7 @@ void chaser_confirm::do_reorganize(header_links& fork, size_t fork_point) NOEXCE auto top = query.get_top_confirmed(); if (top < fork_point) { - fault(error::invalid_fork_point); + fault(error::confirm3); return; } @@ -190,20 +192,20 @@ void chaser_confirm::do_reorganize(header_links& fork, size_t fork_point) NOEXCE const auto top_link = query.to_confirmed(top); if (top_link.is_terminal()) { - fault(error::to_confirmed); + fault(error::confirm4); return; } popped.push_back(top_link); if (!query.set_unstrong(top_link)) { - fault(error::set_unstrong); + fault(error::confirm5); return; } if (!query.pop_confirmed()) { - fault(error::pop_confirmed); + fault(error::confirm6); return; } @@ -238,7 +240,7 @@ void chaser_confirm::do_organize(header_links& fork, // Checkpoint and milestone are already set_strong. if (!set_organized(link, height)) { - fault(database::error::integrity); + fault(error::confirm7); return; } } @@ -249,7 +251,7 @@ void chaser_confirm::do_organize(header_links& fork, { if (!query.set_strong(link)) { - fault(database::error::integrity); + fault(error::confirm8); return; } @@ -258,7 +260,7 @@ void chaser_confirm::do_organize(header_links& fork, { if (ec == database::error::integrity) { - fault(database::error::integrity); + fault(error::confirm9); return; } @@ -269,18 +271,18 @@ void chaser_confirm::do_organize(header_links& fork, if (!query.set_unstrong(link)) { - fault(database::error::integrity); + fault(error::confirm10); return; } if (!query.set_block_unconfirmable(link)) { - fault(database::error::integrity); + fault(error::confirm11); return; } if (!roll_back(popped, fork_point, sub1(height))) - fault(database::error::integrity); + fault(error::confirm12); return; } @@ -288,7 +290,7 @@ void chaser_confirm::do_organize(header_links& fork, // TODO: fees. if (!query.set_block_confirmable(link, {})) { - fault(database::error::integrity); + fault(error::confirm13); return; } @@ -297,7 +299,7 @@ void chaser_confirm::do_organize(header_links& fork, LOGV("Block confirmed and organized: " << height); if (!set_organized(link, height)) - fault(database::error::integrity); + fault(error::confirm14); return; } @@ -305,7 +307,7 @@ void chaser_confirm::do_organize(header_links& fork, { if (!query.set_strong(link)) { - fault(database::error::integrity); + fault(error::confirm15); return; } @@ -314,37 +316,34 @@ void chaser_confirm::do_organize(header_links& fork, LOGV("Block previously confirmable organized: " << height); if (!set_organized(link, height)) - fault(database::error::integrity); - - return; - } - else if (ec == database::error::block_unconfirmable) - { - notify(ec, chase::unconfirmable, link); - fire(events::block_unconfirmable, height); - LOGV("Block confirmation failed: " << height); - - if (!roll_back(popped, fork_point, sub1(height))) - fault(database::error::integrity); + fault(error::confirm16); return; } else { + /////////////////////////////////////////////////////////////// + // TODO: do not start branch unless block valid or confirmable. + /////////////////////////////////////////////////////////////// + // With or without an error code, shouldn't be here. // database::error::block_valid [canonical state ] // database::error::block_confirmable [resurrected state] - // database::error::block_unconfirmable [shouldn't be here] ? + // database::error::block_unconfirmable [shouldn't be here] // database::error::unknown_state [shouldn't be here] // database::error::unassociated [shouldn't be here] // database::error::unvalidated [shouldn't be here] - fault(database::error::integrity); + ////fault(error::confirm17); return; } } fork.pop_back(); } + + /////////////////////////////////////////////////////////////////////////// + // TODO: terminal stall will happen here as validation completes. + /////////////////////////////////////////////////////////////////////////// } // Private diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index d1fec76f..81a9d2df 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -37,7 +37,7 @@ chaser_header::chaser_header(full_node& node) NOEXCEPT code chaser_header::start() NOEXCEPT { if (!initialize_milestone()) - return fault(database::error::integrity); + return fault(error::header1); return chaser_organize
::start(); } diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index c3cedad5..046c8581 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -223,18 +223,18 @@ void chaser_validate::validate_block(const header_link& link) NOEXCEPT const auto block = query.get_block(link); if (!block) { - ////POST(complete_block, database::error::integrity, link, zero); + ////POST(complete_block, error::validate1, link, zero); boost::asio::post(strand_, - BIND(complete_block, database::error::integrity, link, zero)); + BIND(complete_block, error::validate1, link, zero)); return; } chain::context ctx{}; if (!query.get_context(ctx, link)) { - ////POST(complete_block, database::error::integrity, link, zero); + ////POST(complete_block, error::validate2, link, zero); boost::asio::post(strand_, - BIND(complete_block, database::error::integrity, link, zero)); + BIND(complete_block, error::validate2, link, zero)); return; } @@ -245,9 +245,9 @@ void chaser_validate::validate_block(const header_link& link) NOEXCEPT if (!query.populate(*block)) { // This could instead be a case of invalid milestone. - ////POST(complete_block, database::error::integrity, link, ctx.height); + ////POST(complete_block, error::validate3, link, ctx.height); boost::asio::post(strand_, - BIND(complete_block, database::error::integrity, link, ctx.height)); + BIND(complete_block, error::validate3, link, ctx.height)); return; } @@ -257,12 +257,12 @@ void chaser_validate::validate_block(const header_link& link) NOEXCEPT { if (!query.set_block_unconfirmable(link)) { - ec = database::error::integrity; + ec = error::validate4; } } else if (!query.set_block_valid(link)) { - ec = database::error::integrity; + ec = error::validate5; } else { @@ -284,7 +284,7 @@ void chaser_validate::complete_block(const code& ec, const header_link& link, if (ec) { - if (ec == database::error::integrity) + if (ec == error::validate6) { fault(ec); return; diff --git a/src/error.cpp b/src/error.cpp index 81af74d1..71e5fa8a 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -43,41 +43,52 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { suspended_service, "sacrificed service" }, // blockchain - { branch_error, "branch error" }, { orphan_block, "orphan block" }, { orphan_header, "orphan header" }, { duplicate_block, "duplicate block" }, { duplicate_header, "duplicate header" }, - ////{ validation_bypass, "validation bypass" }, - ////{ confirmation_bypass, "confirmation bypass" }, - /// query - { set_block_unconfirmable, "set_block_unconfirmable" }, - { get_height, "get_height" }, - { get_branch_work, "get_branch_work" }, - { get_is_strong, "get_is_strong" }, - { invalid_branch_point, "invalid_branch_point" }, - { pop_candidate, "pop_candidate" }, - { push_candidate, "push_candidate" }, - { invalid_fork_point, "invalid_fork_point" }, - { get_candidate_chain_state, "get_candidate_chain_state" }, - { get_block, "get_block" }, - { get_unassociated, "get_unassociated" }, - { get_fork_work, "get_fork_work" }, - { to_confirmed, "to_confirmed" }, - { pop_confirmed, "pop_confirmed" }, - { get_block_confirmable, "get_block_confirmable" }, - { get_block_state, "get_block_state" }, - { set_strong, "set_strong" }, - { set_unstrong, "set_unstrong" }, - { set_organized, "set_organized" }, - { set_block_confirmable, "set_block_confirmable" }, - { set_block_valid, "set_block_valid" }, - - /// query composite - { node_confirm, "node_confirm" }, - { node_validate, "node_validate" }, - { node_roll_back, "node_roll_back" } + /// faults + { protocol1, "protocol1" }, + { header1, "header1" }, + { organize1, "organize1" }, + { organize2, "organize2" }, + { organize3, "organize3" }, + { organize4, "organize4" }, + { organize5, "organize5" }, + { organize6, "organize6" }, + { organize7, "organize7" }, + { organize8, "organize8" }, + { organize9, "organize9" }, + { organize10, "organize10" }, + { organize11, "organize11" }, + { organize12, "organize12" }, + { organize13, "organize13" }, + { organize14, "organize14" }, + { organize15, "organize15" }, + { validate1, "validate1" }, + { validate2, "validate2" }, + { validate3, "validate3" }, + { validate4, "validate4" }, + { validate5, "validate5" }, + { validate6, "validate6" }, + { confirm1, "confirm1" }, + { confirm2, "confirm2" }, + { confirm3, "confirm3" }, + { confirm4, "confirm4" }, + { confirm5, "confirm5" }, + { confirm6, "confirm6" }, + { confirm7, "confirm7" }, + { confirm8, "confirm8" }, + { confirm9, "confirm9" }, + { confirm10, "confirm10" }, + { confirm11, "confirm11" }, + { confirm12, "confirm12" }, + { confirm13, "confirm13" }, + { confirm14, "confirm14" }, + { confirm15, "confirm15" }, + { confirm16, "confirm16" }, + { confirm17, "confirm17" } }; DEFINE_ERROR_T_CATEGORY(error, "node", "node code") diff --git a/src/protocols/protocol_block_in_31800.cpp b/src/protocols/protocol_block_in_31800.cpp index 1a3604b4..e48b7cc5 100644 --- a/src/protocols/protocol_block_in_31800.cpp +++ b/src/protocols/protocol_block_in_31800.cpp @@ -336,7 +336,7 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec, { LOGF("Failure setting block unconfirmable [" << encode_hash(hash) << ":" << height << "] from [" << authority() << "]."); - fault(error::set_block_unconfirmable); + fault(error::protocol1); return false; } diff --git a/test/error.cpp b/test/error.cpp index c8180586..97881dad 100644 --- a/test/error.cpp +++ b/test/error.cpp @@ -121,15 +121,6 @@ BOOST_AUTO_TEST_CASE(error_t__code__suspended_service__true_exected_message) // blockchain -BOOST_AUTO_TEST_CASE(error_t__code__branch_error__true_exected_message) -{ - constexpr auto value = error::branch_error; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "branch error"); -} - BOOST_AUTO_TEST_CASE(error_t__code__orphan_block__true_exected_message) { constexpr auto value = error::orphan_block; @@ -166,242 +157,57 @@ BOOST_AUTO_TEST_CASE(error_t__code__duplicate_header__true_exected_message) BOOST_REQUIRE_EQUAL(ec.message(), "duplicate header"); } -////BOOST_AUTO_TEST_CASE(error_t__code__validation_bypass__true_exected_message) -////{ -//// constexpr auto value = error::validation_bypass; -//// const auto ec = code(value); -//// BOOST_REQUIRE(ec); -//// BOOST_REQUIRE(ec == value); -//// BOOST_REQUIRE_EQUAL(ec.message(), "validation bypass"); -////} -//// -////BOOST_AUTO_TEST_CASE(error_t__code__confirmation_bypass__true_exected_message) -////{ -//// constexpr auto value = error::confirmation_bypass; -//// const auto ec = code(value); -//// BOOST_REQUIRE(ec); -//// BOOST_REQUIRE(ec == value); -//// BOOST_REQUIRE_EQUAL(ec.message(), "confirmation bypass"); -////} - -// query - -BOOST_AUTO_TEST_CASE(error_t__code__set_block_unconfirmable__true_exected_message) -{ - constexpr auto value = error::set_block_unconfirmable; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "set_block_unconfirmable"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__get_height__true_exected_message) -{ - constexpr auto value = error::get_height; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_height"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__get_branch_work__true_exected_message) -{ - constexpr auto value = error::get_branch_work; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_branch_work"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__get_is_strong__true_exected_message) -{ - constexpr auto value = error::get_is_strong; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_is_strong"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__invalid_branch_point__true_exected_message) -{ - constexpr auto value = error::invalid_branch_point; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "invalid_branch_point"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__pop_candidate__true_exected_message) -{ - constexpr auto value = error::pop_candidate; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "pop_candidate"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__push_candidate__true_exected_message) -{ - constexpr auto value = error::push_candidate; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "push_candidate"); -} +// faults -BOOST_AUTO_TEST_CASE(error_t__code__invalid_fork_point__true_exected_message) +BOOST_AUTO_TEST_CASE(error_t__code__protocol1__true_exected_message) { - constexpr auto value = error::invalid_fork_point; + constexpr auto value = error::protocol1; const auto ec = code(value); BOOST_REQUIRE(ec); BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "invalid_fork_point"); + BOOST_REQUIRE_EQUAL(ec.message(), "protocol1"); } -BOOST_AUTO_TEST_CASE(error_t__code__get_candidate_chain_state__true_exected_message) +BOOST_AUTO_TEST_CASE(error_t__code__header1__true_exected_message) { - constexpr auto value = error::get_candidate_chain_state; + constexpr auto value = error::header1; const auto ec = code(value); BOOST_REQUIRE(ec); BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_candidate_chain_state"); + BOOST_REQUIRE_EQUAL(ec.message(), "header1"); } -BOOST_AUTO_TEST_CASE(error_t__code__get_block__true_exected_message) +BOOST_AUTO_TEST_CASE(error_t__code__organize1__true_exected_message) { - constexpr auto value = error::get_block; + constexpr auto value = error::organize1; const auto ec = code(value); BOOST_REQUIRE(ec); BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_block"); + BOOST_REQUIRE_EQUAL(ec.message(), "organize1"); } -BOOST_AUTO_TEST_CASE(error_t__code__get_unassociated__true_exected_message) -{ - constexpr auto value = error::get_unassociated; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_unassociated"); -} +// TODO: organize2-organize15 -BOOST_AUTO_TEST_CASE(error_t__code__get_fork_work__true_exected_message) +BOOST_AUTO_TEST_CASE(error_t__code__validate1__true_exected_message) { - constexpr auto value = error::get_fork_work; + constexpr auto value = error::validate1; const auto ec = code(value); BOOST_REQUIRE(ec); BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_fork_work"); + BOOST_REQUIRE_EQUAL(ec.message(), "validate1"); } -BOOST_AUTO_TEST_CASE(error_t__code__to_confirmed__true_exected_message) -{ - constexpr auto value = error::to_confirmed; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "to_confirmed"); -} +// TODO: validate2-validate6 -BOOST_AUTO_TEST_CASE(error_t__code__pop_confirmed__true_exected_message) +BOOST_AUTO_TEST_CASE(error_t__code__confirm1__true_exected_message) { - constexpr auto value = error::pop_confirmed; + constexpr auto value = error::confirm1; const auto ec = code(value); BOOST_REQUIRE(ec); BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "pop_confirmed"); + BOOST_REQUIRE_EQUAL(ec.message(), "confirm1"); } -BOOST_AUTO_TEST_CASE(error_t__code__get_block_confirmable__true_exected_message) -{ - constexpr auto value = error::get_block_confirmable; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_block_confirmable"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__get_block_state__true_exected_message) -{ - constexpr auto value = error::get_block_state; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "get_block_state"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__set_strong__true_exected_message) -{ - constexpr auto value = error::set_strong; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "set_strong"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__set_unstrong__true_exected_message) -{ - constexpr auto value = error::set_unstrong; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "set_unstrong"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__set_organized__true_exected_message) -{ - constexpr auto value = error::set_organized; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "set_organized"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__set_block_confirmable__true_exected_message) -{ - constexpr auto value = error::set_block_confirmable; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "set_block_confirmable"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__set_block_valid__true_exected_message) -{ - constexpr auto value = error::set_block_valid; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "set_block_valid"); -} - -// query composite - -BOOST_AUTO_TEST_CASE(error_t__code__node_confirm__true_exected_message) -{ - constexpr auto value = error::node_confirm; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "node_confirm"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__node_validate__true_exected_message) -{ - constexpr auto value = error::node_validate; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "node_validate"); -} - -BOOST_AUTO_TEST_CASE(error_t__code__node_roll_back__true_exected_message) -{ - constexpr auto value = error::node_roll_back; - const auto ec = code(value); - BOOST_REQUIRE(ec); - BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "node_roll_back"); -} +// TODO: confirm2-confirm17 BOOST_AUTO_TEST_SUITE_END() From 87a619bf34185111cd42c4fffb499c2df0c9587c Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 9 Nov 2024 10:51:30 -0500 Subject: [PATCH 4/8] Use auto. --- src/chasers/chaser_confirm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index 81911e38..1aa7454a 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -224,7 +224,7 @@ void chaser_confirm::do_organize(header_links& fork, auto& query = archive(); // height tracks each fork link, starting at fork_point+1. - size_t height = fork_point; + auto height = fork_point; while (!fork.empty()) { From d7d76ad350440dc4e7949b5054f43b4c093d1e9d Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 9 Nov 2024 21:51:28 -0500 Subject: [PATCH 5/8] Comment. --- src/chasers/chaser_validate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index 046c8581..12b8231f 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -87,6 +87,7 @@ bool chaser_validate::handle_event(const code&, chase event_, if (closed()) return false; + // TODO: resume needs to ensure a bump. // Stop generating query during suspension. if (suspended()) return true; From c9740298c7e8cd7a7e2e81b99e448873ccb409b9 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 11 Nov 2024 09:59:24 -0500 Subject: [PATCH 6/8] Tight validation coupling. --- include/bitcoin/node/chase.hpp | 3 + include/bitcoin/node/chasers/chaser_check.hpp | 2 + .../bitcoin/node/chasers/chaser_confirm.hpp | 10 +- src/chasers/chaser_check.cpp | 24 +- src/chasers/chaser_confirm.cpp | 450 ++++++++++++------ 5 files changed, 339 insertions(+), 150 deletions(-) diff --git a/include/bitcoin/node/chase.hpp b/include/bitcoin/node/chase.hpp index aea98cb3..e356a0ed 100644 --- a/include/bitcoin/node/chase.hpp +++ b/include/bitcoin/node/chase.hpp @@ -91,6 +91,9 @@ enum class chase /// Check/Identify. /// ----------------------------------------------------------------------- + /////// A set of blocks is being checked, top block provided (height_t). + ////checking, + /// A block has been downloaded, checked and stored (height_t). /// Issued by 'block_in_31800' or 'populate' and handled by 'connect'. /// Populate is bypassed for checkpoint/milestone blocks. diff --git a/include/bitcoin/node/chasers/chaser_check.hpp b/include/bitcoin/node/chasers/chaser_check.hpp index ae0166e1..32edcbc0 100644 --- a/include/bitcoin/node/chasers/chaser_check.hpp +++ b/include/bitcoin/node/chasers/chaser_check.hpp @@ -68,6 +68,7 @@ class BCN_API chaser_check virtual void do_get_hashes(const map_handler& handler) NOEXCEPT; virtual void do_put_hashes(const map_ptr& map, const network::result_handler& handler) NOEXCEPT; + virtual void do_confirmable(height_t height) NOEXCEPT; private: typedef std::deque maps; @@ -89,6 +90,7 @@ class BCN_API chaser_check // These are protected by strand. size_t inventory_{}; size_t requested_{}; + size_t confirmed_{}; job::ptr job_{}; maps maps_{}; }; diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp index e03a6928..875ad800 100644 --- a/include/bitcoin/node/chasers/chaser_confirm.hpp +++ b/include/bitcoin/node/chasers/chaser_confirm.hpp @@ -50,10 +50,14 @@ class BCN_API chaser_confirm virtual bool handle_event(const code& ec, chase event_, event_value value) NOEXCEPT; + ////virtual void do_checking(height_t height) NOEXCEPT; + virtual void do_regressed(height_t branch_point) NOEXCEPT; virtual void do_validated(height_t height) NOEXCEPT; - virtual void do_reorganize(header_links& fork, size_t fork_point) NOEXCEPT; - virtual void do_organize(header_links& fork, const header_links& popped, - size_t fork_point) NOEXCEPT; + virtual void do_bump(height_t branch_point) NOEXCEPT; + + ////virtual void do_reorganize(header_links& fork, size_t fork_point) NOEXCEPT; + ////virtual void do_organize(header_links& fork, const header_links& popped, + //// size_t fork_point) NOEXCEPT; private: bool set_organized(const database::header_link& link, diff --git a/src/chasers/chaser_check.cpp b/src/chasers/chaser_check.cpp index c71b5d36..6bbda207 100644 --- a/src/chasers/chaser_check.cpp +++ b/src/chasers/chaser_check.cpp @@ -130,6 +130,12 @@ bool chaser_check::handle_event(const code&, chase event_, POST(do_headers, std::get(value)); break; } + case chase::confirmable: + { + BC_ASSERT(std::holds_alternative(value)); + POST(do_confirmable, std::get(value)); + break; + } case chase::stop: { return false; @@ -143,6 +149,15 @@ bool chaser_check::handle_event(const code&, chase event_, return true; } +void chaser_check::do_confirmable(height_t height) NOEXCEPT +{ + BC_ASSERT(stranded()); + confirmed_ = height; + + if (confirmed_ == requested_) + do_headers(height_t{}); +} + // regression // ---------------------------------------------------------------------------- @@ -223,7 +238,7 @@ void chaser_check::do_bump(height_t) NOEXCEPT query.to_candidate(add1(position())))) set_position(add1(position())); - set_unassociated(); + do_headers(height_t{}); } // add headers @@ -324,8 +339,10 @@ size_t chaser_check::set_unassociated() NOEXCEPT if (closed() || purging()) return {}; - // Defer new work issuance until all gaps are filled. - if (position() < requested_ || requested_ >= maximum_height_) + // Defer new work issuance until gaps filled and confirmation caught up. + if (position() < requested_ || + requested_ >= maximum_height_ || + confirmed_ < requested_) return {}; // Inventory size gets set only once. @@ -364,6 +381,7 @@ size_t chaser_check::set_unassociated() NOEXCEPT << count << ") last (" << requested_ << ")."); + ////notify(error::success, chase::checking, requested_); return count; } diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index 1aa7454a..bc1f159c 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -42,9 +42,7 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT : chaser(node), concurrent_(node.config().node.concurrent_confirmation), - threadpool_(std::max(ceilinged_add(node.config().node.threads, - node.config().network.threads), 1_u32), - node.config().node.priority_validation ? + threadpool_(1_u32, node.config().node.priority_validation ? network::thread_priority::highest : network::thread_priority::high), strand_(threadpool_.service().get_executor()) { @@ -52,6 +50,7 @@ chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT code chaser_confirm::start() NOEXCEPT { + set_position(archive().get_fork()); SUBSCRIBE_EVENTS(handle_event, _1, _2, _3); return error::success; } @@ -90,16 +89,26 @@ bool chaser_confirm::handle_event(const code&, chase event_, // These can come out of order, advance in order synchronously. switch (event_) { - case chase::blocks: + ////case chase::blocks: + ////{ + //// BC_ASSERT(std::holds_alternative(value)); + //// + //// if (concurrent_ || mature_) + //// { + //// // TODO: value is branch point. + //// POST(do_validated, std::get(value)); + //// } + //// + //// break; + ////} + case chase::start: + case chase::bump: { - BC_ASSERT(std::holds_alternative(value)); - if (concurrent_ || mature_) { - ////// TODO: value is branch point. - ////POST(do_validated, std::get(value)); - ////boost::asio::post(strand_, - //// BIND(do_validated, std::get(value))); + ////POST(do_bump, height_t{}); + boost::asio::post(strand_, + BIND(do_bump, height_t{})); } break; @@ -118,6 +127,30 @@ bool chaser_confirm::handle_event(const code&, chase event_, break; } + ////case chase::checking: + ////{ + //// BC_ASSERT(std::holds_alternative(value)); + //// ////POST(do_checking, std::get(value)); + //// boost::asio::post(strand_, + //// BIND(do_checking, std::get(value))); + //// break; + ////} + case chase::regressed: + { + BC_ASSERT(std::holds_alternative(value)); + ////POST(do_regressed, std::get(value)); + boost::asio::post(strand_, + BIND(do_regressed, std::get(value))); + break; + } + case chase::disorganized: + { + BC_ASSERT(std::holds_alternative(value)); + ////POST(do_regressed, std::get(value)); + boost::asio::post(strand_, + BIND(do_regressed, std::get(value))); + break; + } case chase::stop: { return false; @@ -131,118 +164,52 @@ bool chaser_confirm::handle_event(const code&, chase event_, return true; } -// confirm -// ---------------------------------------------------------------------------- -// Blocks are either confirmed (blocks first) or validated/confirmed (headers -// first) here. Candidate chain reorganizations will result in reported heights -// moving in any direction. Each is treated as independent and only one -// representing a stronger chain is considered. +////void chaser_confirm::do_checking(height_t height) NOEXCEPT +////{ +////} -// Compute relative work, set fork and fork_point, and invoke reorganize. -void chaser_confirm::do_validated(height_t height) NOEXCEPT +void chaser_confirm::do_regressed(height_t branch_point) NOEXCEPT { BC_ASSERT(stranded()); - - if (closed()) - return; - - bool strong{}; - uint256_t work{}; - header_links fork{}; - - // Scan from validated height to first confirmed, save links, and sum work. - if (!get_fork_work(work, fork, height)) - { - fault(error::confirm1); - return; - } - - // No longer a candidate fork (may have been reorganized). - if (fork.empty()) - return; - - // fork_point is the highest candidate <-> confirmed common block. - const auto fork_point = height - fork.size(); - if (!get_is_strong(strong, work, fork_point)) - { - fault(error::confirm2); - return; - } - - // Fork is strong (has more work than confirmed branch). - if (strong) - do_reorganize(fork, fork_point); -} - -// Pop confirmed chain from top down to above fork point, save popped. -void chaser_confirm::do_reorganize(header_links& fork, size_t fork_point) NOEXCEPT -{ auto& query = archive(); - auto top = query.get_top_confirmed(); - if (top < fork_point) - { - fault(error::confirm3); - return; - } - - header_links popped{}; - while (top > fork_point) + for (auto height = position(); height > branch_point; --height) { - const auto top_link = query.to_confirmed(top); - if (top_link.is_terminal()) - { - fault(error::confirm4); - return; - } - - popped.push_back(top_link); - if (!query.set_unstrong(top_link)) + if (!query.set_unstrong(query.to_candidate(height))) { - fault(error::confirm5); + fault(error::confirm1); return; } + } - if (!query.pop_confirmed()) - { - fault(error::confirm6); - return; - } + set_position(branch_point); +} - notify(error::success, chase::reorganized, top_link); - fire(events::block_reorganized, top--); - } +void chaser_confirm::do_validated(height_t height) NOEXCEPT +{ + BC_ASSERT(stranded()); - // Top is now fork_point. - do_organize(fork, popped, fork_point); + // Candidate block was validated at the given height, confirm/advance. + if (height == add1(position())) + do_bump(height); } -// Push candidate headers from above fork point to confirmed chain. -void chaser_confirm::do_organize(header_links& fork, - const header_links& popped, size_t fork_point) NOEXCEPT +void chaser_confirm::do_bump(height_t) NOEXCEPT { + BC_ASSERT(stranded()); auto& query = archive(); - // height tracks each fork link, starting at fork_point+1. - auto height = fork_point; - - while (!fork.empty()) + // Keep working past window if possible. + for (auto height = add1(position()); !closed(); ++height) { - ++height; - const auto& link = fork.back(); + const auto link = query.to_candidate(height); if (is_under_checkpoint(height) || query.is_milestone(link)) { notify(error::success, chase::confirmable, height); fire(events::confirm_bypassed, height); - LOGV("Block confirmation bypassed and organized: " << height); - - // Checkpoint and milestone are already set_strong. - if (!set_organized(link, height)) - { - fault(error::confirm7); - return; - } + LOGV("Block confirmation bypassed: " << height); + ////return; } else { @@ -251,81 +218,66 @@ void chaser_confirm::do_organize(header_links& fork, { if (!query.set_strong(link)) { - fault(error::confirm8); + fault(error::confirm2); return; } - - // This spawns threads internally, blocking until complete. + if ((ec = query.block_confirmable(link))) { if (ec == database::error::integrity) { - fault(error::confirm9); + fault(error::confirm3); return; } - notify(ec, chase::unconfirmable, link); - fire(events::block_unconfirmable, height); - LOGR("Unconfirmable block [" << height << "] " - << ec.message()); - - if (!query.set_unstrong(link)) + if (!query.set_block_unconfirmable(link)) { - fault(error::confirm10); + fault(error::confirm4); return; } - if (!query.set_block_unconfirmable(link)) + if (!query.set_unstrong(link)) { - fault(error::confirm11); + fault(error::confirm5); return; } - if (!roll_back(popped, fork_point, sub1(height))) - fault(error::confirm12); - + // Blocks between link and fork point will be set_unstrong + // by header reorganization, picked up by do_regressed. + notify(ec, chase::unconfirmable, link); + fire(events::block_unconfirmable, height); + LOGR("Unconfirmable block [" << height << "] " + << ec.message()); return; } - + // TODO: fees. if (!query.set_block_confirmable(link, {})) { - fault(error::confirm13); + fault(error::confirm6); return; } - - notify(ec, chase::confirmable, height); + + notify(error::success, chase::confirmable, height); fire(events::block_confirmed, height); - LOGV("Block confirmed and organized: " << height); - - if (!set_organized(link, height)) - fault(error::confirm14); - - return; + LOGV("Block confirmed: " << height); + ////return; } else if (ec == database::error::block_confirmable) { if (!query.set_strong(link)) { - fault(error::confirm15); + fault(error::confirm7); return; } - + notify(error::success, chase::confirmable, height); fire(events::confirm_bypassed, height); - LOGV("Block previously confirmable organized: " << height); - - if (!set_organized(link, height)) - fault(error::confirm16); - - return; + LOGV("Block previously confirmable: " << height); + ////return; } else { - /////////////////////////////////////////////////////////////// - // TODO: do not start branch unless block valid or confirmable. - /////////////////////////////////////////////////////////////// - // With or without an error code, shouldn't be here. // database::error::block_valid [canonical state ] // database::error::block_confirmable [resurrected state] @@ -333,19 +285,229 @@ void chaser_confirm::do_organize(header_links& fork, // database::error::unknown_state [shouldn't be here] // database::error::unassociated [shouldn't be here] // database::error::unvalidated [shouldn't be here] - ////fault(error::confirm17); return; } - } - fork.pop_back(); + set_position(height); + } } - - /////////////////////////////////////////////////////////////////////////// - // TODO: terminal stall will happen here as validation completes. - /////////////////////////////////////////////////////////////////////////// } +// confirm +// ---------------------------------------------------------------------------- +// Blocks are either confirmed (blocks first) or validated/confirmed (headers +// first) here. Candidate chain reorganizations will result in reported heights +// moving in any direction. Each is treated as independent and only one +// representing a stronger chain is considered. + +////// Compute relative work, set fork and fork_point, and invoke reorganize. +////void chaser_confirm::do_validated(height_t height) NOEXCEPT +////{ +//// BC_ASSERT(stranded()); +//// +//// if (closed()) +//// return; +//// +//// bool strong{}; +//// uint256_t work{}; +//// header_links fork{}; +//// +//// // Scan from validated height to first confirmed, save links, and sum work. +//// if (!get_fork_work(work, fork, height)) +//// { +//// fault(error::confirm1); +//// return; +//// } +//// +//// // No longer a candidate fork (may have been reorganized). +//// if (fork.empty()) +//// return; +//// +//// // fork_point is the highest candidate <-> confirmed common block. +//// const auto fork_point = height - fork.size(); +//// if (!get_is_strong(strong, work, fork_point)) +//// { +//// fault(error::confirm2); +//// return; +//// } +//// +//// // Fork is strong (has more work than confirmed branch). +//// if (strong) +//// do_reorganize(fork, fork_point); +////} +//// +////// Pop confirmed chain from top down to above fork point, save popped. +////void chaser_confirm::do_reorganize(header_links& fork, size_t fork_point) NOEXCEPT +////{ +//// auto& query = archive(); +//// +//// auto top = query.get_top_confirmed(); +//// if (top < fork_point) +//// { +//// fault(error::confirm3); +//// return; +//// } +//// +//// header_links popped{}; +//// while (top > fork_point) +//// { +//// const auto top_link = query.to_confirmed(top); +//// if (top_link.is_terminal()) +//// { +//// fault(error::confirm4); +//// return; +//// } +//// +//// popped.push_back(top_link); +//// if (!query.set_unstrong(top_link)) +//// { +//// fault(error::confirm5); +//// return; +//// } +//// +//// if (!query.pop_confirmed()) +//// { +//// fault(error::confirm6); +//// return; +//// } +//// +//// notify(error::success, chase::reorganized, top_link); +//// fire(events::block_reorganized, top--); +//// } +//// +//// // Top is now fork_point. +//// do_organize(fork, popped, fork_point); +////} +//// +////// Push candidate headers from above fork point to confirmed chain. +////void chaser_confirm::do_organize(header_links& fork, +//// const header_links& popped, size_t fork_point) NOEXCEPT +////{ +//// auto& query = archive(); +//// +//// // height tracks each fork link, starting at fork_point+1. +//// auto height = fork_point; +//// +//// while (!fork.empty()) +//// { +//// ++height; +//// const auto& link = fork.back(); +//// +//// if (is_under_checkpoint(height) || query.is_milestone(link)) +//// { +//// notify(error::success, chase::confirmable, height); +//// fire(events::confirm_bypassed, height); +//// LOGV("Block confirmation bypassed and organized: " << height); +//// +//// // Checkpoint and milestone are already set_strong. +//// if (!set_organized(link, height)) +//// { +//// fault(error::confirm7); +//// return; +//// } +//// } +//// else +//// { +//// auto ec = query.get_block_state(link); +//// if (ec == database::error::block_valid) +//// { +//// if (!query.set_strong(link)) +//// { +//// fault(error::confirm8); +//// return; +//// } +//// +//// // This spawns threads internally, blocking until complete. +//// if ((ec = query.block_confirmable(link))) +//// { +//// if (ec == database::error::integrity) +//// { +//// fault(error::confirm9); +//// return; +//// } +//// +//// notify(ec, chase::unconfirmable, link); +//// fire(events::block_unconfirmable, height); +//// LOGR("Unconfirmable block [" << height << "] " +//// << ec.message()); +//// +//// if (!query.set_unstrong(link)) +//// { +//// fault(error::confirm10); +//// return; +//// } +//// +//// if (!query.set_block_unconfirmable(link)) +//// { +//// fault(error::confirm11); +//// return; +//// } +//// +//// if (!roll_back(popped, fork_point, sub1(height))) +//// fault(error::confirm12); +//// +//// return; +//// } +//// +//// // TODO: fees. +//// if (!query.set_block_confirmable(link, {})) +//// { +//// fault(error::confirm13); +//// return; +//// } +//// +//// notify(ec, chase::confirmable, height); +//// fire(events::block_confirmed, height); +//// LOGV("Block confirmed and organized: " << height); +//// +//// if (!set_organized(link, height)) +//// fault(error::confirm14); +//// +//// return; +//// } +//// else if (ec == database::error::block_confirmable) +//// { +//// if (!query.set_strong(link)) +//// { +//// fault(error::confirm15); +//// return; +//// } +//// +//// notify(error::success, chase::confirmable, height); +//// fire(events::confirm_bypassed, height); +//// LOGV("Block previously confirmable organized: " << height); +//// +//// if (!set_organized(link, height)) +//// fault(error::confirm16); +//// +//// return; +//// } +//// else +//// { +//// /////////////////////////////////////////////////////////////// +//// // TODO: do not start branch unless block valid or confirmable. +//// /////////////////////////////////////////////////////////////// +//// +//// // With or without an error code, shouldn't be here. +//// // database::error::block_valid [canonical state ] +//// // database::error::block_confirmable [resurrected state] +//// // database::error::block_unconfirmable [shouldn't be here] +//// // database::error::unknown_state [shouldn't be here] +//// // database::error::unassociated [shouldn't be here] +//// // database::error::unvalidated [shouldn't be here] +//// ////fault(error::confirm17); +//// return; +//// } +//// } +//// +//// fork.pop_back(); +//// } +//// +//// /////////////////////////////////////////////////////////////////////////// +//// // TODO: terminal stall will happen here as validation completes. +//// /////////////////////////////////////////////////////////////////////////// +////} + // Private // ---------------------------------------------------------------------------- From 9048b7e41ef9bc968af9ede8daca12a491b84cd3 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 17 Nov 2024 15:12:19 -0500 Subject: [PATCH 7/8] Disable organize (temporary). --- src/chasers/chaser_confirm.cpp | 123 +++++++++++++++++---------------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index bc1f159c..526dcc63 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -203,6 +203,11 @@ void chaser_confirm::do_bump(height_t) NOEXCEPT for (auto height = add1(position()); !closed(); ++height) { const auto link = query.to_candidate(height); + auto ec = query.get_block_state(link); + + // Don't report bypassed block is confirmable until associated. + if (ec == database::error::unassociated) + return; if (is_under_checkpoint(height) || query.is_milestone(link)) { @@ -211,85 +216,81 @@ void chaser_confirm::do_bump(height_t) NOEXCEPT LOGV("Block confirmation bypassed: " << height); ////return; } - else + else if (ec == database::error::block_valid) { - auto ec = query.get_block_state(link); - if (ec == database::error::block_valid) + if (!query.set_strong(link)) { - if (!query.set_strong(link)) - { - fault(error::confirm2); - return; - } + fault(error::confirm2); + return; + } - if ((ec = query.block_confirmable(link))) + if ((ec = query.block_confirmable(link))) + { + if (ec == database::error::integrity) { - if (ec == database::error::integrity) - { - fault(error::confirm3); - return; - } - - if (!query.set_block_unconfirmable(link)) - { - fault(error::confirm4); - return; - } - - if (!query.set_unstrong(link)) - { - fault(error::confirm5); - return; - } - - // Blocks between link and fork point will be set_unstrong - // by header reorganization, picked up by do_regressed. - notify(ec, chase::unconfirmable, link); - fire(events::block_unconfirmable, height); - LOGR("Unconfirmable block [" << height << "] " - << ec.message()); + fault(error::confirm3); return; } - - // TODO: fees. - if (!query.set_block_confirmable(link, {})) + + if (!query.set_block_unconfirmable(link)) { - fault(error::confirm6); + fault(error::confirm4); return; } - - notify(error::success, chase::confirmable, height); - fire(events::block_confirmed, height); - LOGV("Block confirmed: " << height); - ////return; - } - else if (ec == database::error::block_confirmable) - { - if (!query.set_strong(link)) + + if (!query.set_unstrong(link)) { - fault(error::confirm7); + fault(error::confirm5); return; } + + // Blocks between link and fork point will be set_unstrong + // by header reorganization, picked up by do_regressed. + notify(ec, chase::unconfirmable, link); + fire(events::block_unconfirmable, height); + LOGR("Unconfirmable block [" << height << "] " + << ec.message()); + return; + } - notify(error::success, chase::confirmable, height); - fire(events::confirm_bypassed, height); - LOGV("Block previously confirmable: " << height); - ////return; + // TODO: fees. + if (!query.set_block_confirmable(link, {})) + { + fault(error::confirm6); + return; } - else + + notify(error::success, chase::confirmable, height); + fire(events::block_confirmed, height); + LOGV("Block confirmed: " << height); + ////return; + } + else if (ec == database::error::block_confirmable) + { + if (!query.set_strong(link)) { - // With or without an error code, shouldn't be here. - // database::error::block_valid [canonical state ] - // database::error::block_confirmable [resurrected state] - // database::error::block_unconfirmable [shouldn't be here] - // database::error::unknown_state [shouldn't be here] - // database::error::unassociated [shouldn't be here] - // database::error::unvalidated [shouldn't be here] + fault(error::confirm7); return; } - - set_position(height); + + notify(error::success, chase::confirmable, height); + fire(events::confirm_bypassed, height); + LOGV("Block previously confirmable: " << height); + ////return; + } + else + { + // With or without an error code, shouldn't be here. + // database::error::block_valid [canonical state ] + // database::error::block_confirmable [resurrected state] + // database::error::block_unconfirmable [shouldn't be here] + // database::error::unknown_state [shouldn't be here] + // database::error::unassociated [shouldn't be here] + // database::error::unvalidated [shouldn't be here] + return; } + + set_position(height); } } From 6385398aa862fbfbd8bfe607b1a3a0abbc1a6e89 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 18 Nov 2024 18:45:26 -0500 Subject: [PATCH 8/8] Disable confirmation coupling (temporary). --- src/chasers/chaser_check.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chasers/chaser_check.cpp b/src/chasers/chaser_check.cpp index 6bbda207..ea102d61 100644 --- a/src/chasers/chaser_check.cpp +++ b/src/chasers/chaser_check.cpp @@ -341,8 +341,8 @@ size_t chaser_check::set_unassociated() NOEXCEPT // Defer new work issuance until gaps filled and confirmation caught up. if (position() < requested_ || - requested_ >= maximum_height_ || - confirmed_ < requested_) + requested_ >= maximum_height_ + /*||confirmed_ < requested_*/) return {}; // Inventory size gets set only once.