diff --git a/Makefile.am b/Makefile.am
index d39b89b33..813860848 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -45,6 +45,7 @@ src_libbitcoin_node_la_SOURCES = \
src/chasers/chaser_check.cpp \
src/chasers/chaser_confirm.cpp \
src/chasers/chaser_header.cpp \
+ src/chasers/chaser_populate.cpp \
src/chasers/chaser_snapshot.cpp \
src/chasers/chaser_storage.cpp \
src/chasers/chaser_template.cpp \
@@ -89,6 +90,7 @@ test_libbitcoin_node_test_SOURCES = \
test/chasers/chaser_check.cpp \
test/chasers/chaser_confirm.cpp \
test/chasers/chaser_header.cpp \
+ test/chasers/chaser_populate.cpp \
test/chasers/chaser_template.cpp \
test/chasers/chaser_transaction.cpp \
test/chasers/chaser_validate.cpp \
@@ -140,6 +142,7 @@ include_bitcoin_node_chasers_HEADERS = \
include/bitcoin/node/chasers/chaser_confirm.hpp \
include/bitcoin/node/chasers/chaser_header.hpp \
include/bitcoin/node/chasers/chaser_organize.hpp \
+ include/bitcoin/node/chasers/chaser_populate.hpp \
include/bitcoin/node/chasers/chaser_snapshot.hpp \
include/bitcoin/node/chasers/chaser_storage.hpp \
include/bitcoin/node/chasers/chaser_template.hpp \
diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt
index 6bb6e5f42..bcbcb815f 100644
--- a/builds/cmake/CMakeLists.txt
+++ b/builds/cmake/CMakeLists.txt
@@ -255,6 +255,7 @@ add_library( ${CANONICAL_LIB_NAME}
"../../src/chasers/chaser_check.cpp"
"../../src/chasers/chaser_confirm.cpp"
"../../src/chasers/chaser_header.cpp"
+ "../../src/chasers/chaser_populate.cpp"
"../../src/chasers/chaser_snapshot.cpp"
"../../src/chasers/chaser_storage.cpp"
"../../src/chasers/chaser_template.cpp"
@@ -329,6 +330,7 @@ if (with-tests)
"../../test/chasers/chaser_check.cpp"
"../../test/chasers/chaser_confirm.cpp"
"../../test/chasers/chaser_header.cpp"
+ "../../test/chasers/chaser_populate.cpp"
"../../test/chasers/chaser_template.cpp"
"../../test/chasers/chaser_transaction.cpp"
"../../test/chasers/chaser_validate.cpp"
diff --git a/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj b/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj
index f6c0ac61d..a3ac41477 100644
--- a/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj
@@ -75,6 +75,7 @@
+
diff --git a/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
index b8dd021e6..0fc4ebb1d 100644
--- a/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
@@ -36,6 +36,9 @@
src\chasers
+
+ src\chasers
+
src\chasers
diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
index 01ab576a1..d1974246c 100644
--- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
@@ -78,6 +78,7 @@
+
@@ -114,6 +115,7 @@
+
diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
index 8d44ffe59..549c30b1a 100644
--- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
@@ -63,6 +63,9 @@
src\chasers
+
+ src\chasers
+
src\chasers
@@ -167,6 +170,9 @@
include\bitcoin\node\chasers
+
+ include\bitcoin\node\chasers
+
include\bitcoin\node\chasers
diff --git a/include/bitcoin/node.hpp b/include/bitcoin/node.hpp
index ed2a916e7..09b6025ff 100644
--- a/include/bitcoin/node.hpp
+++ b/include/bitcoin/node.hpp
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/bitcoin/node/chasers/chaser_block.hpp b/include/bitcoin/node/chasers/chaser_block.hpp
index 421116f09..a445df14e 100644
--- a/include/bitcoin/node/chasers/chaser_block.hpp
+++ b/include/bitcoin/node/chasers/chaser_block.hpp
@@ -41,33 +41,33 @@ class BCN_API chaser_block
protected:
/// Get header from Block instance.
- virtual const system::chain::header& get_header(
- const system::chain::block& block) const NOEXCEPT;
+ const system::chain::header& get_header(
+ const system::chain::block& block) const NOEXCEPT override;
/// Query store for const pointer to Block instance by candidate height.
- virtual bool get_block(system::chain::block::cptr& out,
- size_t height) const NOEXCEPT;
+ bool get_block(system::chain::block::cptr& out,
+ size_t height) const NOEXCEPT override;
/// Determine if Block is a duplicate (success for not duplicate).
- virtual code duplicate(size_t& height,
- const system::hash_digest& hash) const NOEXCEPT;
+ code duplicate(size_t& height,
+ const system::hash_digest& hash) const NOEXCEPT override;
/// Determine if Block is valid.
- virtual code validate(const system::chain::block& block,
- const chain_state& state) const NOEXCEPT;
+ code validate(const system::chain::block& block,
+ const chain_state& state) const NOEXCEPT override;
/// Notify check chaser to redownload the block (nop).
- virtual void do_malleated(header_t link) NOEXCEPT;
+ void do_malleated(header_t link) NOEXCEPT override;
/// Determine if state is top of a storable branch (always true).
- virtual bool is_storable(const chain_state& state) const NOEXCEPT;
+ bool is_storable(const chain_state& state) const NOEXCEPT override;
/// True if Block is on a milestone-covered branch.
- virtual bool is_under_milestone(size_t height) const NOEXCEPT;
+ bool is_under_milestone(size_t height) const NOEXCEPT override;
/// Milestone tracking.
- virtual void update_milestone(const system::chain::header& header,
- size_t height, size_t branch_point) NOEXCEPT;
+ void update_milestone(const system::chain::header& header,
+ size_t height, size_t branch_point) NOEXCEPT override;
private:
void set_prevout(const system::chain::input& input) const NOEXCEPT;
diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp
index 1876cf0c3..1e3dc3617 100644
--- a/include/bitcoin/node/chasers/chaser_confirm.hpp
+++ b/include/bitcoin/node/chasers/chaser_confirm.hpp
@@ -49,9 +49,7 @@ class BCN_API chaser_confirm
event_value value) NOEXCEPT;
virtual void do_validated(height_t height) NOEXCEPT;
-#if defined(SEQUENTIAL)
- virtual void do_organize(size_t height) NOEXCEPT;
-#else
+ virtual void do_reorganize(size_t height) NOEXCEPT;
virtual void do_organize(size_t height) NOEXCEPT;
virtual bool enqueue_block(const database::header_link& link) NOEXCEPT;
virtual void confirm_tx(const database::context& ctx,
@@ -63,17 +61,21 @@ class BCN_API chaser_confirm
virtual void confirm_block(const code& ec,
const database::header_link& link, size_t height) NOEXCEPT;
virtual void next_block(size_t height) NOEXCEPT;
-#endif // SEQUENTIAL
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,
height_t height) NOEXCEPT;
bool set_reorganized(const database::header_link& link,
height_t height) NOEXCEPT;
- bool roll_back(header_links& popped, const database::header_link& link,
- size_t fork_point, size_t top) 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;
diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp
index fa3d1efed..c36fe4b5c 100644
--- a/include/bitcoin/node/chasers/chaser_header.hpp
+++ b/include/bitcoin/node/chasers/chaser_header.hpp
@@ -44,33 +44,33 @@ class BCN_API chaser_header
protected:
/// Get header from Block instance.
- virtual const system::chain::header& get_header(
- const system::chain::header& header) const NOEXCEPT;
+ const system::chain::header& get_header(
+ const system::chain::header& header) const NOEXCEPT override;
/// Query store for const pointer to Block instance by candidate height.
- virtual bool get_block(system::chain::header::cptr& out,
- size_t height) const NOEXCEPT;
+ bool get_block(system::chain::header::cptr& out,
+ size_t height) const NOEXCEPT override;
/// Determine if Block is a duplicate (success for not duplicate).
- virtual code duplicate(size_t& height,
- const system::hash_digest& hash) const NOEXCEPT;
+ code duplicate(size_t& height,
+ const system::hash_digest& hash) const NOEXCEPT override;
/// Determine if Block is valid.
- virtual code validate(const system::chain::header& header,
- const chain_state& state) const NOEXCEPT;
+ code validate(const system::chain::header& header,
+ const chain_state& state) const NOEXCEPT override;
/// Notify check chaser to redownload the block.
- virtual void do_malleated(header_t link) NOEXCEPT;
+ void do_malleated(header_t link) NOEXCEPT override;
/// Determine if state is top of a storable branch.
- virtual bool is_storable(const chain_state& state) const NOEXCEPT;
+ bool is_storable(const chain_state& state) const NOEXCEPT override;
/// True if Block is on a milestone-covered branch.
- virtual bool is_under_milestone(size_t height) const NOEXCEPT;
+ bool is_under_milestone(size_t height) const NOEXCEPT override;
/// Milestone tracking.
- virtual void update_milestone(const system::chain::header& header,
- size_t height, size_t branch_point) NOEXCEPT;
+ void update_milestone(const system::chain::header& header,
+ size_t height, size_t branch_point) NOEXCEPT override;
private:
bool is_checkpoint(const chain_state& state) const NOEXCEPT;
diff --git a/include/bitcoin/node/chasers/chaser_populate.hpp b/include/bitcoin/node/chasers/chaser_populate.hpp
new file mode 100644
index 000000000..35212925c
--- /dev/null
+++ b/include/bitcoin/node/chasers/chaser_populate.hpp
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS)
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#ifndef LIBBITCOIN_NODE_CHASERS_CHASER_POPULATE_HPP
+#define LIBBITCOIN_NODE_CHASERS_CHASER_POPULATE_HPP
+
+#include
+#include
+
+namespace libbitcoin {
+namespace node {
+
+class full_node;
+
+/// Order and populate downloaded non-bypass blocks for validation.
+class BCN_API chaser_populate
+ : public chaser
+{
+public:
+ DELETE_COPY_MOVE_DESTRUCT(chaser_populate);
+
+ chaser_populate(full_node& node) NOEXCEPT;
+
+ /// Initialize chaser state.
+ code start() NOEXCEPT override;
+
+protected:
+ virtual bool handle_event(const code& ec, chase event_,
+ event_value value) NOEXCEPT;
+
+ virtual void do_checked(height_t height) NOEXCEPT;
+
+private:
+ // TODO:
+};
+
+} // namespace node
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/node/chasers/chasers.hpp b/include/bitcoin/node/chasers/chasers.hpp
index 248e0412d..0948c632c 100644
--- a/include/bitcoin/node/chasers/chasers.hpp
+++ b/include/bitcoin/node/chasers/chasers.hpp
@@ -25,10 +25,11 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
+#include
#endif
diff --git a/include/bitcoin/node/define.hpp b/include/bitcoin/node/define.hpp
index 4d91f90a0..d4f432499 100644
--- a/include/bitcoin/node/define.hpp
+++ b/include/bitcoin/node/define.hpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
/// Pulls in common /node headers (excluding settings/config/parser/full_node).
#include
@@ -63,25 +64,51 @@ typedef std::shared_ptr map_ptr;
typedef std::function map_handler;
-/// Node events.
-typedef uint64_t object_key;
-typedef uint64_t event_value;
-typedef network::desubscriber event_subscriber;
-typedef event_subscriber::handler event_notifier;
-typedef event_subscriber::completer event_completer;
+/// Event desubscriber key type.
+using object_key = uint64_t;
-/// Use for event_value variants (all unsigned integral integers).
-/// std::variant is inconsistent with interpretation of size_t as redundant or
-/// unique with respect to uint32_t and/or uint64_t (specifically macOS). So
-/// instead these are implicitly casted to event_value (uint64_t) and explicitly
-/// casted from event_value using system::possible_narrow_cast. This is no less
-/// type-safe as using std::variant in cases where the types are overloaded.
+/// Event value types.
using count_t = size_t;
using height_t = size_t;
using channel_t = uint64_t;
using object_t = object_key;
using header_t = database::header_link::integer;
using transaction_t = database::tx_link::integer;
+typedef system::chain::block::cptr block_t;
+////typedef struct
+////{
+//// size_t height;
+//// database::header_link link;
+//// system::chain::block::cptr block;
+////} xblock_t;
+
+/// std::variant types must be distinct, and xcode size_t is neither uint32_t
+/// nor uint64_t, so this ensures we have the distinct set of necessary types.
+using event_value =
+ iif,
+ std::variant,
+ iif,
+ std::variant,
+ std::variant>>;
+////using xevent_value =
+//// iif,
+//// std::variant,
+//// iif,
+//// std::variant,
+//// std::variant>>;
+
+/// Event desubscriber.
+typedef network::desubscriber event_subscriber;
+////typedef network::desubscriber xevent_subscriber;
+typedef event_subscriber::handler event_notifier;
+typedef event_subscriber::completer event_completer;
+
+// NDEBUG MSVC
+////static_assert(sizeof(uint64_t) == 8u);
+////static_assert(sizeof(block_t) == 16u);
+////static_assert(sizeof(xblock_t) == 32u);
+////static_assert(sizeof(event_value) == 24u);
+////static_assert(sizeof(xevent_value) == 40u);
} // namespace node
} // namespace libbitcoin
diff --git a/include/bitcoin/node/impl/chasers/chaser_organize.ipp b/include/bitcoin/node/impl/chasers/chaser_organize.ipp
index 9e26e846f..00a7d7dc5 100644
--- a/include/bitcoin/node/impl/chasers/chaser_organize.ipp
+++ b/include/bitcoin/node/impl/chasers/chaser_organize.ipp
@@ -96,13 +96,15 @@ bool CLASS::handle_event(const code&, chase event_, event_value value) NOEXCEPT
case chase::unconfirmable:
{
// Roll back the candidate chain to confirmed top (via fork point).
- POST(do_disorganize, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_disorganize, std::get(value));
break;
}
case chase::malleated:
{
// Re-obtain the malleated block if it is still a candidate (virtual).
- POST(do_malleated, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_malleated, std::get(value));
break;
}
case chase::stop:
diff --git a/include/bitcoin/node/protocols/protocol_block_in_31800.hpp b/include/bitcoin/node/protocols/protocol_block_in_31800.hpp
index 08aa4621d..a11c274e7 100644
--- a/include/bitcoin/node/protocols/protocol_block_in_31800.hpp
+++ b/include/bitcoin/node/protocols/protocol_block_in_31800.hpp
@@ -39,7 +39,6 @@ class BCN_API protocol_block_in_31800
protocol_block_in_31800(const SessionPtr& session,
const channel_ptr& channel) NOEXCEPT
: protocol_performer(session, channel),
- maximum_concurrency_(session->config().node.maximum_concurrency_()),
top_checkpoint_height_(
session->config().bitcoin.top_checkpoint().height()),
block_type_(session->config().network.witness_node() ?
@@ -92,7 +91,6 @@ class BCN_API protocol_block_in_31800
const job::ptr& job) NOEXCEPT;
// These are thread safe.
- const size_t maximum_concurrency_;
const size_t top_checkpoint_height_;
const network::messages::inventory::type_id block_type_;
diff --git a/src/chasers/chaser_check.cpp b/src/chasers/chaser_check.cpp
index b281032fa..25401fa41 100644
--- a/src/chasers/chaser_check.cpp
+++ b/src/chasers/chaser_check.cpp
@@ -19,6 +19,7 @@
#include
#include
+#include
#include
#include
#include
@@ -106,28 +107,33 @@ bool chaser_check::handle_event(const code&, chase event_,
}
case chase::checked:
{
- POST(do_checked, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_checked, std::get(value));
break;
}
case chase::regressed:
{
- POST(do_regressed, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_regressed, std::get(value));
break;
}
case chase::disorganized:
{
- POST(do_regressed, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_regressed, std::get(value));
break;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
case chase::header:
{
- POST(do_header, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_header, std::get(value));
break;
}
case chase::headers:
{
- POST(do_headers, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_headers, std::get(value));
break;
}
case chase::stop:
diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp
index 58de908a6..7b333899e 100644
--- a/src/chasers/chaser_confirm.cpp
+++ b/src/chasers/chaser_confirm.cpp
@@ -18,6 +18,7 @@
*/
#include
+#include
#include
#include
#include
@@ -66,13 +67,15 @@ bool chaser_confirm::handle_event(const code&, chase event_,
case chase::blocks:
{
// TODO: value is branch point.
- POST(do_validated, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_validated, std::get(value));
break;
}
case chase::valid:
{
// value is individual height.
- POST(do_validated, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_validated, std::get(value));
break;
}
case chase::stop:
@@ -90,22 +93,20 @@ bool chaser_confirm::handle_event(const code&, chase event_,
// confirm
// ----------------------------------------------------------------------------
-
// Blocks are either confirmed (blocks first) or validated/confirmed
// (headers first) at this point. An unconfirmable block may not land 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_.
void chaser_confirm::do_validated(height_t height) NOEXCEPT
{
BC_ASSERT(stranded());
- if (closed() || !fork_.empty())
+ if (closed() || busy())
return;
- // Compute relative work.
- // ........................................................................
-
bool strong{};
uint256_t work{};
@@ -131,28 +132,29 @@ void chaser_confirm::do_validated(height_t height) NOEXCEPT
// Not yet a strong fork (confirmed branch has at least as much work).
if (!strong)
{
- fork_.clear();
+ reset();
return;
}
- // Reorganize confirmed chain.
- // ........................................................................
+ do_reorganize(archive().get_top_confirmed());
+}
- auto& query = archive();
- const auto top = query.get_top_confirmed();
- if (top < fork_point_)
+// Pop confirmed chain from height down to above fork point, save popped_.
+void chaser_confirm::do_reorganize(size_t height) NOEXCEPT
+{
+ BC_ASSERT(stranded());
+
+ if (height < fork_point_)
{
fault(error::invalid_fork_point);
return;
}
- // Pop down to the fork point.
- auto index = top;
popped_.clear();
-
- while (index > fork_point_)
+ auto& query = archive();
+ while (height > fork_point_)
{
- const auto link = query.to_confirmed(index);
+ const auto link = query.to_confirmed(height);
if (link.is_terminal())
{
fault(error::to_confirmed);
@@ -160,7 +162,7 @@ void chaser_confirm::do_validated(height_t height) NOEXCEPT
}
popped_.push_back(link);
- if (!query.set_unstrong_parallel(link))
+ if (!query.set_unstrong(link))
{
fault(error::set_unstrong);
return;
@@ -173,173 +175,68 @@ void chaser_confirm::do_validated(height_t height) NOEXCEPT
}
notify(error::success, chase::reorganized, popped_.back());
- fire(events::block_reorganized, index--);
+ fire(events::block_reorganized, height--);
}
- // Push candidate headers to confirmed chain.
- // ........................................................................
-
- do_organize(add1(fork_point_));
+ do_organize(add1(height));
}
-#if defined(SEQUENTIAL)
-
+// Push candidate headers from above fork point to confirmed chain.
void chaser_confirm::do_organize(size_t height) NOEXCEPT
{
+ BC_ASSERT(stranded());
+ if (fork_.empty())
+ return;
+
auto& query = archive();
+ bool confirmable = false;
+ const auto& link = fork_.back();
+ const auto bypass = is_under_checkpoint(height) ||
+ query.is_milestone(link);
- // Push candidate headers to confirmed chain.
- for (const auto& link: views_reverse(fork_))
+ if (!bypass)
{
- if (closed())
- return;
-
// database::error::unassociated
// database::error::block_unconfirmable
// database::error::block_confirmable
// database::error::block_valid
// database::error::unknown_state
// database::error::unvalidated
- auto ec = query.get_block_state(link);
+ const auto ec = query.get_block_state(link);
+
+ // Previously unconfirmable block.
if (ec == database::error::block_unconfirmable)
{
notify(ec, chase::unconfirmable, link);
fire(events::block_unconfirmable, height);
- if (!roll_back(popped_, link, fork_point_, height))
+ // Roll back previously confirmed blocks.
+ if (!roll_back(popped_, fork_point_, sub1(height)))
fault(error::node_roll_back);
+ reset();
return;
}
- const auto checked = is_under_checkpoint(height) ||
- query.is_milestone(link);
-
- // Required for block_confirmable and all confirmed blocks.
- if (!checked && !query.set_strong_parallel(link))
+ // Previously evaluated and set confirmable block.
+ if (ec == database::error::block_confirmable)
{
- fault(error::set_strong);
- return;
- }
-
- if (ec == database::error::block_confirmable || checked)
- {
- // TODO: compute fees from validation records.
- if ((ec != database::error::block_confirmable) &&
- !query.set_block_confirmable(link, uint64_t{}))
- {
- fault(error::set_block_confirmable);
- return;
- }
-
- notify(ec, chase::confirmable, height);
- ////fire(events::confirm_bypassed, height);
-
- if (!set_organized(link, height))
- {
- fault(error::set_organized);
- return;
- }
- }
- else
- {
- ec = query.block_confirmable(link);
- if (ec == database::error::integrity)
- {
- fault(error::get_block_confirmable);
- return;
- }
-
- if (ec)
- {
- if (!query.set_block_unconfirmable(link))
- {
- fault(error::set_block_unconfirmable);
- return;
- }
-
- LOGR("Unconfirmable block [" << height << "] " << ec.message());
- notify(ec, chase::unconfirmable, link);
- fire(events::block_unconfirmable, height);
-
- if (!roll_back(popped_, link, fork_point_, height))
- fault(error::node_roll_back);
-
- return;
- }
-
- // TODO: compute fees from validation records.
- if (!query.set_block_confirmable(link, uint64_t{}))
+ // 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))
{
- fault(error::set_block_confirmable);
+ fault(error::set_strong);
return;
}
- notify(error::success, chase::confirmable, height);
- fire(events::block_confirmed, height);
-
- if (!set_organized(link, height))
- {
- fault(error::set_organized);
- return;
- }
+ confirmable = true;
}
-
- LOGV("Block confirmed and organized: " << height);
- ++height;
}
-}
-
-#else
-
-// CONCURRENT
-void chaser_confirm::do_organize(size_t height) NOEXCEPT
-{
- if (fork_.empty())
- return;
-
- auto& query = archive();
- const auto& link = fork_.back();
- // database::error::unassociated
- // database::error::block_unconfirmable
- // database::error::block_confirmable
- // database::error::block_valid
- // database::error::unknown_state
- // database::error::unvalidated
- auto ec = query.get_block_state(link);
- if (ec == database::error::block_unconfirmable)
+ if (bypass || confirmable)
{
- notify(ec, chase::unconfirmable, link);
- fire(events::block_unconfirmable, height);
-
- if (!roll_back(popped_, link, fork_point_, height))
- fault(error::node_roll_back);
-
- return;
- }
-
- const auto checked = is_under_checkpoint(height) ||
- query.is_milestone(link);
-
- // Required for block_confirmable and all confirmed blocks.
- if (!checked && !query.set_strong_parallel(link))
- {
- fault(error::set_strong);
- return;
- }
-
- if (ec == database::error::block_confirmable || checked)
- {
- // TODO: compute fees from validation records.
- if ((ec != database::error::block_confirmable) &&
- !query.set_block_confirmable(link, uint64_t{}))
- {
- fault(error::set_block_confirmable);
- return;
- }
-
- notify(ec, chase::confirmable, height);
+ notify(error::success, chase::confirmable, height);
////fire(events::confirm_bypassed, height);
if (!set_organized(link, height))
@@ -460,17 +357,20 @@ void chaser_confirm::confirm_block(const code& ec, const header_link& link,
LOGR("Unconfirmable block [" << height << "] " << ec.message());
notify(ec, chase::unconfirmable, link);
fire(events::block_unconfirmable, height);
- if (!roll_back(popped_, link, fork_point_, height))
+
+ // Roll back current and previously confirmed blocks.
+ if (!roll_back(popped_, fork_point_, height, link))
{
fault(error::node_roll_back);
return;
}
- fork_.clear();
+ reset();
return;
}
- // TODO: compute fees from validation records.
+ // 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);
@@ -493,8 +393,8 @@ void chaser_confirm::confirm_block(const code& ec, const header_link& link,
void chaser_confirm::next_block(size_t height) NOEXCEPT
{
BC_ASSERT(stranded());
- auto& query = archive();
+ // Continue until fork is empty.
fork_.pop_back();
if (!fork_.empty())
{
@@ -502,6 +402,9 @@ void chaser_confirm::next_block(size_t height) NOEXCEPT
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) ||
@@ -511,11 +414,21 @@ void chaser_confirm::next_block(size_t height) NOEXCEPT
}
}
-#endif // SEQUENTIAL
-
// 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();
@@ -531,7 +444,7 @@ bool chaser_confirm::reset_organized(const header_link& link,
height_t height) NOEXCEPT
{
auto& query = archive();
- if (!query.set_strong_parallel(link) || !query.push_confirmed(link))
+ if (!query.set_strong(link) || !query.push_confirmed(link))
return false;
notify(error::success, chase::organized, link);
@@ -543,7 +456,7 @@ bool chaser_confirm::set_reorganized(const header_link& link,
height_t height) NOEXCEPT
{
auto& query = archive();
- if (!query.pop_confirmed() || !query.set_unstrong_parallel(link))
+ if (!query.pop_confirmed() || !query.set_unstrong(link))
return false;
notify(error::success, chase::reorganized, link);
@@ -551,14 +464,17 @@ bool chaser_confirm::set_reorganized(const header_link& link,
return true;
}
-bool chaser_confirm::roll_back(header_links& popped,
- const header_link& link, size_t fork_point, size_t top) NOEXCEPT
+bool chaser_confirm::roll_back(const header_links& popped,
+ size_t fork_point, size_t top, const header_link& link) NOEXCEPT
{
- auto& query = archive();
+ // The current block (top/link) is set_strong but is not confirmable.
+ return archive().set_unstrong(link) && roll_back(popped, fork_point, top);
+}
- // The current block is set_strong but not confirmed.
- if (!query.set_unstrong_parallel(link))
- return false;
+bool chaser_confirm::roll_back(const header_links& popped, size_t fork_point,
+ size_t top) NOEXCEPT
+{
+ const auto& query = archive();
for (auto height = top; height > fork_point; --height)
if (!set_reorganized(query.to_confirmed(height), height))
@@ -568,7 +484,6 @@ bool chaser_confirm::roll_back(header_links& popped,
if (!reset_organized(fk, ++fork_point))
return false;
- popped.clear();
return true;
}
diff --git a/src/chasers/chaser_populate.cpp b/src/chasers/chaser_populate.cpp
new file mode 100644
index 000000000..b790ec9f5
--- /dev/null
+++ b/src/chasers/chaser_populate.cpp
@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2011-2024 libbitcoin developers (see AUTHORS)
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+#include
+#include
+#include
+#include
+
+namespace libbitcoin {
+namespace node {
+
+#define CLASS chaser_populate
+
+////using namespace system;
+////using namespace system::chain;
+////using namespace database;
+////using namespace network;
+using namespace std::placeholders;
+
+////// Shared pointers required for lifetime in handler parameters.
+////BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
+////BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
+////BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
+
+chaser_populate::chaser_populate(full_node& node) NOEXCEPT
+ : chaser(node)
+{
+}
+
+// start/stop
+// ----------------------------------------------------------------------------
+
+code chaser_populate::start() NOEXCEPT
+{
+ SUBSCRIBE_EVENTS(handle_event, _1, _2, _3);
+ return error::success;
+}
+
+bool chaser_populate::handle_event(const code&, chase event_,
+ event_value) NOEXCEPT
+{
+ if (closed())
+ return false;
+
+ switch (event_)
+ {
+ case chase::checked:
+ {
+ POST(do_checked, height_t{});
+ break;
+ }
+ case chase::stop:
+ {
+ return false;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return true;
+}
+
+void chaser_populate::do_checked(height_t) NOEXCEPT
+{
+ BC_ASSERT(stranded());
+}
+
+////BC_POP_WARNING()
+////BC_POP_WARNING()
+////BC_POP_WARNING()
+
+} // namespace node
+} // namespace libbitcoin
diff --git a/src/chasers/chaser_snapshot.cpp b/src/chasers/chaser_snapshot.cpp
index f171ca7d3..938b37004 100644
--- a/src/chasers/chaser_snapshot.cpp
+++ b/src/chasers/chaser_snapshot.cpp
@@ -82,7 +82,8 @@ bool chaser_snapshot::handle_event(const code& ec, chase event_,
if (!enabled_bytes_ || ec) break;
// Checked blocks are out of order, so this is probalistic.
- POST(do_archive, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_archive, std::get(value));
break;
}
case chase::confirmable:
@@ -91,7 +92,8 @@ bool chaser_snapshot::handle_event(const code& ec, chase event_,
if (!enabled_valid_ || ec) break;
// Confirmable covers all validation except set_confirmed (link).
- POST(do_confirm, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_confirm, std::get(value));
break;
}
default:
diff --git a/src/chasers/chaser_template.cpp b/src/chasers/chaser_template.cpp
index c30b98efa..411c44605 100644
--- a/src/chasers/chaser_template.cpp
+++ b/src/chasers/chaser_template.cpp
@@ -62,7 +62,8 @@ bool chaser_template::handle_event(const code&, chase event_,
{
case chase::transaction:
{
- POST(do_transaction, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_transaction, std::get(value));
break;
}
case chase::stop:
diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp
index 8659f097b..fc240e2b3 100644
--- a/src/chasers/chaser_validate.cpp
+++ b/src/chasers/chaser_validate.cpp
@@ -79,17 +79,20 @@ bool chaser_validate::handle_event(const code&, chase event_,
}
case chase::checked:
{
- POST(do_checked, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_checked, std::get(value));
break;
}
case chase::regressed:
{
- POST(do_regressed, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_regressed, std::get(value));
break;
}
case chase::disorganized:
{
- POST(do_regressed, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_regressed, std::get(value));
break;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -180,6 +183,7 @@ void chaser_validate::do_bump(height_t) NOEXCEPT
}
else
{
+ // Validation is currently bypassed in all cases.
////// TODO: the quantity of work must be throttled.
////// Will very rapidly pump outstanding work in asio queue.
////if (!enqueue_block(link))
@@ -361,6 +365,8 @@ void chaser_validate::validate_block(const code& ec,
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_valid(link))
{
fault(error::set_block_valid);
diff --git a/src/full_node.cpp b/src/full_node.cpp
index 15c8fae5a..175538100 100644
--- a/src/full_node.cpp
+++ b/src/full_node.cpp
@@ -18,6 +18,7 @@
*/
#include
+#include
#include
#include
#include
diff --git a/src/protocols/protocol_block_in_31800.cpp b/src/protocols/protocol_block_in_31800.cpp
index e378edd89..4edd81fc6 100644
--- a/src/protocols/protocol_block_in_31800.cpp
+++ b/src/protocols/protocol_block_in_31800.cpp
@@ -147,12 +147,14 @@ bool protocol_block_in_31800::handle_event(const code&, chase event_,
// There are count blocks to download at/above given header.
// chase::headers is only sent for current candidate chain, and this
// chase::download is only sent as a consequence of chase::headers.
- POST(do_get_downloads, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_get_downloads, std::get(value));
break;
}
case chase::report:
{
- POST(do_report, possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ POST(do_report, std::get(value));
break;
}
case chase::stop:
diff --git a/src/sessions/session.cpp b/src/sessions/session.cpp
index 467a3b22d..b1c3d3700 100644
--- a/src/sessions/session.cpp
+++ b/src/sessions/session.cpp
@@ -18,6 +18,7 @@
*/
#include
+#include
#include
#include
#include
diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp
index d781e9969..6fafd2a02 100644
--- a/src/sessions/session_outbound.cpp
+++ b/src/sessions/session_outbound.cpp
@@ -82,7 +82,8 @@ bool session_outbound::handle_event(const code&, chase event_,
case chase::starved:
{
// When a channel becomes starved notify other(s) to split work.
- do_starved(possible_narrow_cast(value));
+ BC_ASSERT(std::holds_alternative(value));
+ do_starved(std::get(value));
break;
}
case chase::stop:
diff --git a/test/chasers/chaser_populate.cpp b/test/chasers/chaser_populate.cpp
new file mode 100644
index 000000000..b1cbc3337
--- /dev/null
+++ b/test/chasers/chaser_populate.cpp
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS)
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#include "../test.hpp"
+
+BOOST_AUTO_TEST_SUITE(chaser_populate_tests)
+
+BOOST_AUTO_TEST_CASE(chaser_populate_test)
+{
+ BOOST_REQUIRE(true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()