From bd153bb674ef6e979630a388248717e73d9cffc7 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 11 Mar 2024 12:05:00 -0400 Subject: [PATCH 1/5] Rename to 'disorganize' and reset top_state_. --- .../bitcoin/node/chasers/chaser_header.hpp | 27 +++--- src/chasers/chaser_header.cpp | 89 ++++++++++--------- 2 files changed, 65 insertions(+), 51 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp index 20fb29f8..7f8d1152 100644 --- a/include/bitcoin/node/chasers/chaser_header.hpp +++ b/include/bitcoin/node/chasers/chaser_header.hpp @@ -60,12 +60,25 @@ class BCN_API chaser_header // This is protected by strand. std::unordered_map tree_{}; + /// Disorganize unconfirmable candidate header. + /// ----------------------------------------------------------------------- + /// Handle chaser events. virtual void handle_event(const code& ec, chase event_, link value) NOEXCEPT; - // Handle events. - virtual void handle_unchecked(header_t height) NOEXCEPT; + // Reorganize the candidate chain due to block invalidity. + virtual void do_disorganize(header_t height) NOEXCEPT; + + /// Organize next candidate header. + /// ----------------------------------------------------------------------- + + /// Validate and organize next header in sequence relative to caller peer. + virtual void do_organize(const system::chain::header::cptr& header, + const organize_handler& handler) NOEXCEPT; + + /// Utilities. + /// ----------------------------------------------------------------------- /// Sum of work from header to branch point (excluded). virtual bool get_branch_work(uint256_t& work, size_t& point, @@ -79,7 +92,7 @@ class BCN_API chaser_header size_t point) const NOEXCEPT; /// Obtain chain state for the given header hash, nullptr if not found. - virtual system::chain::chain_state::ptr get_state( + virtual system::chain::chain_state::ptr get_chain_state( const system::hash_digest& hash) const NOEXCEPT; /// Header timestamp is within configured span from current time. @@ -97,14 +110,6 @@ class BCN_API chaser_header /// Move tree header to database and push to top of candidate chain. virtual bool push_header(const system::hash_digest& key) NOEXCEPT; - /// Validate and organize next header in sequence relative to caller peer. - virtual void do_organize(const system::chain::header::cptr& header, - const organize_handler& handler) NOEXCEPT; - - /// A strong header branch is committed to store when current. - virtual const network::wall_clock::duration& currency_window() const NOEXCEPT; - virtual bool use_currency_window() const NOEXCEPT; - private: // These are thread safe. const uint256_t minimum_work_; diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index 114665ee..6304793e 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -57,18 +57,15 @@ chaser_header::~chaser_header() NOEXCEPT // start // ---------------------------------------------------------------------------- -// protected code chaser_header::start() NOEXCEPT { BC_ASSERT(node_stranded()); - // Initialize cache of top candidate chain state. - // ######################################################################## + // Initialize cache of top candidate chain state (expensive). // Spans full chain to obtain cumulative work. This can be optimized by // storing it with each header, though the scan is fast. The same occurs // when a block first branches below the current chain top. Chain work is // a questionable DoS protection scheme only, so could also toss it. - // ######################################################################## top_state_ = archive().get_candidate_chain_state( config().bitcoin, archive().get_top_candidate()); @@ -78,10 +75,9 @@ code chaser_header::start() NOEXCEPT return SUBSCRIBE_EVENTS(handle_event, _1, _2, _3); } -// event handlers +// disorganize // ---------------------------------------------------------------------------- -// protected void chaser_header::handle_event(const code&, chase event_, link value) NOEXCEPT { @@ -90,16 +86,23 @@ void chaser_header::handle_event(const code&, chase event_, event_ == chase::unconnected || event_ == chase::unconfirmed) { - POST(handle_unchecked, std::get(value)); + POST(do_disorganize, std::get(value)); } } -// TODO: notify reorg? -void chaser_header::handle_unchecked(header_t header) NOEXCEPT +void chaser_header::do_disorganize(header_t header) NOEXCEPT { BC_ASSERT(stranded()); + // Skip already reorganized out, get height. + // ------------------------------------------------------------------------ + + // Upon restart candidate chain validation will hit unconfirmable block. + if (closed()) + return; + // If header is not a current candidate it has been reorganized out. + // If header becomes candidate again its unconfirmable state is handled. auto& query = archive(); if (!query.is_candidate_block(header)) return; @@ -111,8 +114,12 @@ void chaser_header::handle_unchecked(header_t header) NOEXCEPT return; } + // Mark candidates above and pop at/above height. + // ------------------------------------------------------------------------ + // Pop from top down to and including header marking each as unconfirmable. - for (auto index = query.get_top_candidate(); index >= height; --index) + // Unconfirmability isn't necessary for validation but adds query context. + for (auto index = query.get_top_candidate(); index > height; --index) { if (!query.set_block_unconfirmable(query.to_candidate(index)) || !query.pop_candidate()) @@ -122,14 +129,21 @@ void chaser_header::handle_unchecked(header_t header) NOEXCEPT } } - // There may not be (valid) blocks between fork point and invalid block. - const auto fork_point = query.get_fork(); - const auto top = query.get_top_candidate(); - if (top == fork_point) + // Candidate at height is already marked as unconfirmable by notifier. + if (!query.pop_candidate()) + { + close(error::store_integrity); return; + } - // Header tree requires chain state, initialize at fork point. + // Copy candidates from above fork point to top into header tree. + // ------------------------------------------------------------------------ + + // There may not be (valid) blocks between fork point and invalid block, + // but top_state_ must be recomputed and if there are blocks then header + // tree also requires chain state, so initialize at fork point (expensive). const auto& coin = config().bitcoin; + const auto fork_point = query.get_fork(); auto state = query.get_candidate_chain_state(coin, fork_point); if (!state) { @@ -137,7 +151,7 @@ void chaser_header::handle_unchecked(header_t header) NOEXCEPT return; } - // Copy candidates from above fork point into header tree. + const auto top = top_state_->height(); for (auto index = add1(fork_point); index <= top; ++index) { const auto save = query.get_header(query.to_candidate(index)); @@ -151,8 +165,9 @@ void chaser_header::handle_unchecked(header_t header) NOEXCEPT cache(save, state); } - // Pop cached candidates from top down to and excluding fork point. - for (auto index = query.get_top_candidate(); index > fork_point; --index) + // Pop candidates from top to above fork point. + // ------------------------------------------------------------------------ + for (auto index = top; index > fork_point; --index) { if (!query.pop_candidate()) { @@ -161,7 +176,8 @@ void chaser_header::handle_unchecked(header_t header) NOEXCEPT } } - // Push all confirmed headers above fork point onto candidate chain. + // Push confirmed headers from above fork point onto candidate chain. + // ------------------------------------------------------------------------ const auto strong = query.get_top_confirmed(); for (auto index = add1(fork_point); index <= strong; ++index) { @@ -171,9 +187,15 @@ void chaser_header::handle_unchecked(header_t header) NOEXCEPT return; } } + + // Reset top chain state cache. + // ------------------------------------------------------------------------ + + // TODO: No new headers but might need to notify of disorganization. + top_state_ = state; } -// methods +// organize // ---------------------------------------------------------------------------- void chaser_header::organize(const header::cptr& header, @@ -222,7 +244,8 @@ void chaser_header::do_organize(const header::cptr& header_ptr, return; } - auto state = get_state(header.previous_block_hash()); + // Obtains from top_state_, tree, or store as applicable. + auto state = get_chain_state(header.previous_block_hash()); if (!state) { handler(error::orphan_header, {}); @@ -344,6 +367,7 @@ void chaser_header::do_organize(const header::cptr& header_ptr, return; } + // Reset top chain state cache. // ------------------------------------------------------------------------ top_state_ = state; @@ -355,7 +379,7 @@ void chaser_header::do_organize(const header::cptr& header_ptr, // utilities // ---------------------------------------------------------------------------- -chain_state::ptr chaser_header::get_state( +chain_state::ptr chaser_header::get_chain_state( const hash_digest& hash) const NOEXCEPT { if (!top_state_) @@ -369,6 +393,7 @@ chain_state::ptr chaser_header::get_state( if (it != tree_.end()) return it->second.state; + // Branch forms from a candidate block below top candidate (expensive). size_t height{}; const auto& query = archive(); if (query.get_height(height, query.to_header(hash))) @@ -379,12 +404,12 @@ chain_state::ptr chaser_header::get_state( bool chaser_header::is_current(const header& header) const NOEXCEPT { - if (!use_currency_window()) + if (!use_currency_window_) return true; // en.wikipedia.org/wiki/Time_formatting_and_storage_bugs#Year_2106 const auto time = wall_clock::from_time_t(header.timestamp()); - const auto current = wall_clock::now() - currency_window(); + const auto current = wall_clock::now() - currency_window_; return time >= current; } @@ -481,22 +506,6 @@ bool chaser_header::push_header(const hash_digest& key) NOEXCEPT return query.push_candidate(link); } -// properties -// ---------------------------------------------------------------------------- - -// protected -const network::wall_clock::duration& -chaser_header::currency_window() const NOEXCEPT -{ - return currency_window_; -} - -// protected -bool chaser_header::use_currency_window() const NOEXCEPT -{ - return use_currency_window_; -} - BC_POP_WARNING() BC_POP_WARNING() From 1f191f7110e1b69cf5f74cc7bdb04cd94e48d16d Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 11 Mar 2024 12:16:39 -0400 Subject: [PATCH 2/5] Use default virtual chaser destructors. --- include/bitcoin/node/chasers/chaser.hpp | 3 +-- include/bitcoin/node/chasers/chaser_block.hpp | 3 +-- include/bitcoin/node/chasers/chaser_candidate.hpp | 3 +-- include/bitcoin/node/chasers/chaser_check.hpp | 3 +-- include/bitcoin/node/chasers/chaser_confirm.hpp | 3 +-- include/bitcoin/node/chasers/chaser_connect.hpp | 3 +-- include/bitcoin/node/chasers/chaser_header.hpp | 3 +-- include/bitcoin/node/chasers/chaser_transaction.hpp | 3 +-- src/chasers/chaser.cpp | 4 ---- src/chasers/chaser_block.cpp | 4 ---- src/chasers/chaser_candidate.cpp | 4 ---- src/chasers/chaser_check.cpp | 4 ---- src/chasers/chaser_confirm.cpp | 4 ---- src/chasers/chaser_connect.cpp | 4 ---- src/chasers/chaser_header.cpp | 4 ---- src/chasers/chaser_transaction.cpp | 4 ---- 16 files changed, 8 insertions(+), 48 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser.hpp b/include/bitcoin/node/chasers/chaser.hpp index f8c43b63..553904c3 100644 --- a/include/bitcoin/node/chasers/chaser.hpp +++ b/include/bitcoin/node/chasers/chaser.hpp @@ -108,7 +108,7 @@ class BCN_API chaser typedef database::store store; typedef database::query query; - DELETE_COPY_MOVE(chaser); + DELETE_COPY_MOVE_DESTRUCT(chaser); /// Synchronously subscribe to notify and asynchronously initialize state. virtual code start() NOEXCEPT = 0; @@ -129,7 +129,6 @@ class BCN_API chaser } chaser(full_node& node) NOEXCEPT; - ~chaser() NOEXCEPT; /// Close the node after logging the code. void close(const code& ec) const NOEXCEPT; diff --git a/include/bitcoin/node/chasers/chaser_block.hpp b/include/bitcoin/node/chasers/chaser_block.hpp index e20d2791..ba489319 100644 --- a/include/bitcoin/node/chasers/chaser_block.hpp +++ b/include/bitcoin/node/chasers/chaser_block.hpp @@ -37,10 +37,9 @@ class BCN_API chaser_block : public chaser { public: - DELETE_COPY_MOVE(chaser_block); + DELETE_COPY_MOVE_DESTRUCT(chaser_block); chaser_block(full_node& node) NOEXCEPT; - virtual ~chaser_block() NOEXCEPT; virtual code start() NOEXCEPT; diff --git a/include/bitcoin/node/chasers/chaser_candidate.hpp b/include/bitcoin/node/chasers/chaser_candidate.hpp index 711b8fbd..381d9836 100644 --- a/include/bitcoin/node/chasers/chaser_candidate.hpp +++ b/include/bitcoin/node/chasers/chaser_candidate.hpp @@ -34,10 +34,9 @@ class BCN_API chaser_candidate : public chaser { public: - DELETE_COPY_MOVE(chaser_candidate); + DELETE_COPY_MOVE_DESTRUCT(chaser_candidate); chaser_candidate(full_node& node) NOEXCEPT; - virtual ~chaser_candidate() NOEXCEPT; virtual code start() NOEXCEPT; diff --git a/include/bitcoin/node/chasers/chaser_check.hpp b/include/bitcoin/node/chasers/chaser_check.hpp index 24762926..2e42d8b2 100644 --- a/include/bitcoin/node/chasers/chaser_check.hpp +++ b/include/bitcoin/node/chasers/chaser_check.hpp @@ -40,10 +40,9 @@ class BCN_API chaser_check typedef std::function handler; typedef std::list maps; - DELETE_COPY_MOVE(chaser_check); + DELETE_COPY_MOVE_DESTRUCT(chaser_check); chaser_check(full_node& node) NOEXCEPT; - virtual ~chaser_check() NOEXCEPT; virtual code start() NOEXCEPT; diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp index 33fb3bcd..cab19916 100644 --- a/include/bitcoin/node/chasers/chaser_confirm.hpp +++ b/include/bitcoin/node/chasers/chaser_confirm.hpp @@ -34,10 +34,9 @@ class BCN_API chaser_confirm : public chaser { public: - DELETE_COPY_MOVE(chaser_confirm); + DELETE_COPY_MOVE_DESTRUCT(chaser_confirm); chaser_confirm(full_node& node) NOEXCEPT; - virtual ~chaser_confirm() NOEXCEPT; virtual code start() NOEXCEPT; diff --git a/include/bitcoin/node/chasers/chaser_connect.hpp b/include/bitcoin/node/chasers/chaser_connect.hpp index 46cb2244..fba0384d 100644 --- a/include/bitcoin/node/chasers/chaser_connect.hpp +++ b/include/bitcoin/node/chasers/chaser_connect.hpp @@ -34,10 +34,9 @@ class BCN_API chaser_connect : public chaser { public: - DELETE_COPY_MOVE(chaser_connect); + DELETE_COPY_MOVE_DESTRUCT(chaser_connect); chaser_connect(full_node& node) NOEXCEPT; - virtual ~chaser_connect() NOEXCEPT; virtual code start() NOEXCEPT; diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp index 7f8d1152..0509e60f 100644 --- a/include/bitcoin/node/chasers/chaser_header.hpp +++ b/include/bitcoin/node/chasers/chaser_header.hpp @@ -38,10 +38,9 @@ class BCN_API chaser_header : public chaser { public: - DELETE_COPY_MOVE(chaser_header); + DELETE_COPY_MOVE_DESTRUCT(chaser_header); chaser_header(full_node& node) NOEXCEPT; - virtual ~chaser_header() NOEXCEPT; virtual code start() NOEXCEPT; diff --git a/include/bitcoin/node/chasers/chaser_transaction.hpp b/include/bitcoin/node/chasers/chaser_transaction.hpp index 81f3b96a..dae4c84d 100644 --- a/include/bitcoin/node/chasers/chaser_transaction.hpp +++ b/include/bitcoin/node/chasers/chaser_transaction.hpp @@ -34,10 +34,9 @@ class BCN_API chaser_transaction : public chaser { public: - DELETE_COPY_MOVE(chaser_transaction); + DELETE_COPY_MOVE_DESTRUCT(chaser_transaction); chaser_transaction(full_node& node) NOEXCEPT; - virtual ~chaser_transaction() NOEXCEPT; code start() NOEXCEPT override; virtual void store(const system::chain::transaction::cptr& block) NOEXCEPT; diff --git a/src/chasers/chaser.cpp b/src/chasers/chaser.cpp index 7d7c325f..e1a8e103 100644 --- a/src/chasers/chaser.cpp +++ b/src/chasers/chaser.cpp @@ -43,10 +43,6 @@ chaser::chaser(full_node& node) NOEXCEPT { } -chaser::~chaser() NOEXCEPT -{ -} - void chaser::close(const code& ec) const NOEXCEPT { LOGF("Chaser failed, " << ec.message()); diff --git a/src/chasers/chaser_block.cpp b/src/chasers/chaser_block.cpp index 30ea3407..b64decc0 100644 --- a/src/chasers/chaser_block.cpp +++ b/src/chasers/chaser_block.cpp @@ -46,10 +46,6 @@ chaser_block::chaser_block(full_node& node) NOEXCEPT { } -chaser_block::~chaser_block() NOEXCEPT -{ -} - // start // ---------------------------------------------------------------------------- diff --git a/src/chasers/chaser_candidate.cpp b/src/chasers/chaser_candidate.cpp index 01b42fbf..0a750156 100644 --- a/src/chasers/chaser_candidate.cpp +++ b/src/chasers/chaser_candidate.cpp @@ -39,10 +39,6 @@ chaser_candidate::chaser_candidate(full_node& node) NOEXCEPT { } -chaser_candidate::~chaser_candidate() NOEXCEPT -{ -} - // start // ---------------------------------------------------------------------------- diff --git a/src/chasers/chaser_check.cpp b/src/chasers/chaser_check.cpp index 6d7fcaeb..db31d5c8 100644 --- a/src/chasers/chaser_check.cpp +++ b/src/chasers/chaser_check.cpp @@ -51,10 +51,6 @@ chaser_check::chaser_check(full_node& node) NOEXCEPT { } -chaser_check::~chaser_check() NOEXCEPT -{ -} - // utility // ---------------------------------------------------------------------------- // private diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index 84387d04..f8cbc7a5 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -38,10 +38,6 @@ chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT { } -chaser_confirm::~chaser_confirm() NOEXCEPT -{ -} - // start // ---------------------------------------------------------------------------- diff --git a/src/chasers/chaser_connect.cpp b/src/chasers/chaser_connect.cpp index 8f2913f8..2fd3a1c5 100644 --- a/src/chasers/chaser_connect.cpp +++ b/src/chasers/chaser_connect.cpp @@ -38,10 +38,6 @@ chaser_connect::chaser_connect(full_node& node) NOEXCEPT { } -chaser_connect::~chaser_connect() NOEXCEPT -{ -} - // start // ---------------------------------------------------------------------------- diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index 6304793e..031ae2b2 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -50,10 +50,6 @@ chaser_header::chaser_header(full_node& node) NOEXCEPT { } -chaser_header::~chaser_header() NOEXCEPT -{ -} - // start // ---------------------------------------------------------------------------- diff --git a/src/chasers/chaser_transaction.cpp b/src/chasers/chaser_transaction.cpp index 320cf120..bc3b4d36 100644 --- a/src/chasers/chaser_transaction.cpp +++ b/src/chasers/chaser_transaction.cpp @@ -39,10 +39,6 @@ chaser_transaction::chaser_transaction(full_node& node) NOEXCEPT { } -chaser_transaction::~chaser_transaction() NOEXCEPT -{ -} - // start // ---------------------------------------------------------------------------- From 03128efb2c1fb1580c6cadc189278eab9a5d4e21 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 11 Mar 2024 12:17:48 -0400 Subject: [PATCH 3/5] Fix integer compare sign mismatch. --- src/sessions/session_outbound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp index 9d4a8ca4..666e8e7e 100644 --- a/src/sessions/session_outbound.cpp +++ b/src/sessions/session_outbound.cpp @@ -66,7 +66,7 @@ void session_outbound::do_performance(uint64_t channel, uint64_t speed, const network::result_handler& handler) NOEXCEPT { // Three elements are required to measure deviation, don't drop to two. - constexpr auto mimimum_for_deviation = 3; + constexpr auto mimimum_for_deviation = 3_size; BC_ASSERT(stranded()); From ba49facdf83919982e9af1efb05b6a2c07b3d99c Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 11 Mar 2024 12:43:11 -0400 Subject: [PATCH 4/5] Change error::unknown to internal_error. --- include/bitcoin/node/error.hpp | 2 +- src/error.cpp | 2 +- test/error.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/bitcoin/node/error.hpp b/include/bitcoin/node/error.hpp index 0e683e4d..27f9c070 100644 --- a/include/bitcoin/node/error.hpp +++ b/include/bitcoin/node/error.hpp @@ -37,7 +37,7 @@ namespace error { enum error_t : uint8_t { success, - unknown, + internal_error, unexpected_event, // database diff --git a/src/error.cpp b/src/error.cpp index baf9ec9b..086e8fd0 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -28,7 +28,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { // general { success, "success" }, - { unknown, "unknown error" }, + { internal_error, "internal error" }, { unexpected_event, "unexpected event" }, // database diff --git a/test/error.cpp b/test/error.cpp index 05bc559a..9942aeb2 100644 --- a/test/error.cpp +++ b/test/error.cpp @@ -32,13 +32,13 @@ BOOST_AUTO_TEST_CASE(error_t__code__success__false_exected_message) BOOST_REQUIRE_EQUAL(ec.message(), "success"); } -BOOST_AUTO_TEST_CASE(error_t__code__unknown__true_exected_message) +BOOST_AUTO_TEST_CASE(error_t__code__internal_error__true_exected_message) { - constexpr auto value = error::unknown; + constexpr auto value = error::internal_error; const auto ec = code(value); BOOST_REQUIRE(ec); BOOST_REQUIRE(ec == value); - BOOST_REQUIRE_EQUAL(ec.message(), "unknown error"); + BOOST_REQUIRE_EQUAL(ec.message(), "internal error"); } BOOST_AUTO_TEST_CASE(error_t__code__unexpected_event__true_exected_message) From 3d38fcbf38cee7112ce87bf884d723fe2c7f8115 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 11 Mar 2024 12:43:40 -0400 Subject: [PATCH 5/5] Fix cached chain state -> set to fork point on deorg. --- src/chasers/chaser_header.cpp | 39 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index 031ae2b2..7f369c74 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -106,7 +106,14 @@ void chaser_header::do_disorganize(header_t header) NOEXCEPT size_t height{}; if (!query.get_height(height, header) || is_zero(height)) { - close(error::store_integrity); + close(error::internal_error); + return; + } + + const auto fork_point = query.get_fork(); + if (height <= fork_point) + { + close(error::internal_error); return; } @@ -132,23 +139,23 @@ void chaser_header::do_disorganize(header_t header) NOEXCEPT return; } - // Copy candidates from above fork point to top into header tree. + // Reset top chain state cache to fork point. // ------------------------------------------------------------------------ - // There may not be (valid) blocks between fork point and invalid block, - // but top_state_ must be recomputed and if there are blocks then header - // tree also requires chain state, so initialize at fork point (expensive). const auto& coin = config().bitcoin; - const auto fork_point = query.get_fork(); - auto state = query.get_candidate_chain_state(coin, fork_point); - if (!state) + const auto top_candidate = top_state_->height(); + top_state_ = query.get_candidate_chain_state(coin, fork_point); + if (!top_state_) { close(error::store_integrity); return; } - const auto top = top_state_->height(); - for (auto index = add1(fork_point); index <= top; ++index) + // Copy candidates from above fork point to top into header tree. + // ------------------------------------------------------------------------ + + auto state = top_state_; + for (auto index = add1(fork_point); index <= top_candidate; ++index) { const auto save = query.get_header(query.to_candidate(index)); if (!save) @@ -163,7 +170,7 @@ void chaser_header::do_disorganize(header_t header) NOEXCEPT // Pop candidates from top to above fork point. // ------------------------------------------------------------------------ - for (auto index = top; index > fork_point; --index) + for (auto index = top_candidate; index > fork_point; --index) { if (!query.pop_candidate()) { @@ -174,8 +181,8 @@ void chaser_header::do_disorganize(header_t header) NOEXCEPT // Push confirmed headers from above fork point onto candidate chain. // ------------------------------------------------------------------------ - const auto strong = query.get_top_confirmed(); - for (auto index = add1(fork_point); index <= strong; ++index) + const auto top_confirmed = query.get_top_confirmed(); + for (auto index = add1(fork_point); index <= top_confirmed; ++index) { if (!query.push_candidate(query.to_confirmed(index))) { @@ -183,12 +190,6 @@ void chaser_header::do_disorganize(header_t header) NOEXCEPT return; } } - - // Reset top chain state cache. - // ------------------------------------------------------------------------ - - // TODO: No new headers but might need to notify of disorganization. - top_state_ = state; } // organize