From 1f86ffd35bd166047b0ffac746ae27fe58563929 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 22 Feb 2024 15:55:57 -0500 Subject: [PATCH 1/9] Improve organize() error reporting. --- include/bitcoin/node/protocols/protocol.hpp | 3 --- .../node/protocols/protocol_block_in.hpp | 4 +++ .../protocols/protocol_block_in_31800.hpp | 5 ++++ .../protocols/protocol_header_in_31800.hpp | 4 +++ src/protocols/protocol.cpp | 10 ------- src/protocols/protocol_block_in.cpp | 26 ++++++++++++++---- src/protocols/protocol_block_in_31800.cpp | 27 +++++++++++++++---- src/protocols/protocol_header_in_31800.cpp | 15 ++++++++++- 8 files changed, 70 insertions(+), 24 deletions(-) diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index eae5027a..9f67c0f1 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -61,9 +61,6 @@ class BCN_API protocol virtual void organize(const system::chain::block::cptr& block, network::result_handler&& handler) NOEXCEPT; - /// Handle organize result. - virtual void handle_organize(const code& ec) NOEXCEPT; - /// Configuration settings for all libraries. const configuration& config() const NOEXCEPT; diff --git a/include/bitcoin/node/protocols/protocol_block_in.hpp b/include/bitcoin/node/protocols/protocol_block_in.hpp index 03f9618b..8e66f4f5 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -71,6 +71,10 @@ class BCN_API protocol_block_in /// Invoked when initial blocks sync is complete. virtual void complete() NOEXCEPT; + /// Handle organize result. + virtual void handle_organize(const code& ec, + const system::chain::block::cptr& block_ptr) NOEXCEPT; + private: static system::hashes to_hashes( const network::messages::get_data& getter) NOEXCEPT; diff --git a/include/bitcoin/node/protocols/protocol_block_in_31800.hpp b/include/bitcoin/node/protocols/protocol_block_in_31800.hpp index 2998dd97..b49e2213 100644 --- a/include/bitcoin/node/protocols/protocol_block_in_31800.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in_31800.hpp @@ -26,6 +26,7 @@ namespace libbitcoin { namespace node { +/// This does NOT inhereit from protocol_block_in. class BCN_API protocol_block_in_31800 : public node::protocol, protected network::tracker @@ -82,6 +83,10 @@ class BCN_API protocol_block_in_31800 /// Invoked when initial blocks sync is complete. virtual void complete() NOEXCEPT; + /// Handle organize result. + virtual void handle_organize(const code& ec, + const system::chain::block::cptr& block_ptr) NOEXCEPT; + private: static system::hashes to_hashes( const network::messages::get_data& getter) NOEXCEPT; diff --git a/include/bitcoin/node/protocols/protocol_header_in_31800.hpp b/include/bitcoin/node/protocols/protocol_header_in_31800.hpp index c671bfbc..2933b887 100644 --- a/include/bitcoin/node/protocols/protocol_header_in_31800.hpp +++ b/include/bitcoin/node/protocols/protocol_header_in_31800.hpp @@ -52,6 +52,10 @@ class BCN_API protocol_header_in_31800 /// Invoked when initial headers sync is complete. virtual void complete() NOEXCEPT; + /// Handle organize result. + virtual void handle_organize(const code& ec, + const system::chain::header::cptr& header_ptr) NOEXCEPT; + private: network::messages::get_headers create_get_headers() NOEXCEPT; network::messages::get_headers create_get_headers( diff --git a/src/protocols/protocol.cpp b/src/protocols/protocol.cpp index 2307d756..cd2000bc 100644 --- a/src/protocols/protocol.cpp +++ b/src/protocols/protocol.cpp @@ -40,16 +40,6 @@ void protocol::performance(uint64_t channel, uint64_t speed, session_.performance(channel, speed, std::move(handler)); } - -void protocol::handle_organize(const code& ec) NOEXCEPT -{ - if (ec) - { - LOGP("protocol::handle_organize, " << ec.message()); - stop(ec); - } -} - void protocol::organize(const system::chain::header::cptr& header, result_handler&& handler) NOEXCEPT { diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index 39d614ce..63077797 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -133,21 +133,26 @@ bool protocol_block_in::handle_receive_block(const code& ec, return false; } + // Alias. + const auto& block_ptr = message->block_ptr; + // Unrequested block, may not have been announced via inventory. - if (tracker->hashes.back() != message->block_ptr->hash()) + if (tracker->hashes.back() != block_ptr->hash()) return true; // Out of order or invalid. - if (message->block_ptr->header().previous_block_hash() != top_.hash()) + if (block_ptr->header().previous_block_hash() != top_.hash()) { - LOGP("Orphan block [" << encode_hash(message->block_ptr->hash()) + LOGP("Orphan block [" << encode_hash(block_ptr->hash()) << "] from [" << authority() << "]."); return false; } - organize(message->block_ptr, BIND1(handle_organize, _1)); + // TODO: use BIND2. + organize(block_ptr, + [=](const code& ec) { handle_organize(ec, block_ptr); }); - top_ = { message->block_ptr->hash(), add1(top_.height()) }; + top_ = { block_ptr->hash(), add1(top_.height()) }; LOGP("Block [" << encode_hash(top_.hash()) << "] at (" << top_.height() << ") from [" << authority() << "]."); @@ -184,6 +189,17 @@ void protocol_block_in::complete() NOEXCEPT << top_.height() << ")."); } +void protocol_block_in::handle_organize(const code& ec, + const chain::block::cptr& block_ptr) NOEXCEPT +{ + if (ec) + { + LOGR("Error organizing block [" << encode_hash(block_ptr->hash()) + << "] from [" << authority() << "] " << ec.message()); + stop(ec); + } +} + // private // ---------------------------------------------------------------------------- diff --git a/src/protocols/protocol_block_in_31800.cpp b/src/protocols/protocol_block_in_31800.cpp index 3cfbd949..00364f90 100644 --- a/src/protocols/protocol_block_in_31800.cpp +++ b/src/protocols/protocol_block_in_31800.cpp @@ -201,21 +201,26 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec, return false; } + // Alias. + const auto& block_ptr = message->block_ptr; + // Unrequested block, may not have been announced via inventory. - if (tracker->hashes.back() != message->block_ptr->hash()) + if (tracker->hashes.back() != block_ptr->hash()) return true; // Out of order or invalid. - if (message->block_ptr->header().previous_block_hash() != top_.hash()) + if (block_ptr->header().previous_block_hash() != top_.hash()) { - LOGP("Orphan block [" << encode_hash(message->block_ptr->hash()) + LOGP("Orphan block [" << encode_hash(block_ptr->hash()) << "] from [" << authority() << "]."); return false; } - organize(message->block_ptr, BIND1(handle_organize, _1)); + // TODO: use BIND2. + organize(block_ptr, + [=](const code& ec) { handle_organize(ec, block_ptr); }); - top_ = { message->block_ptr->hash(), add1(top_.height()) }; + top_ = { block_ptr->hash(), add1(top_.height()) }; LOGP("Block [" << encode_hash(top_.hash()) << "] at (" << top_.height() << ") from [" << authority() << "]."); @@ -255,6 +260,18 @@ void protocol_block_in_31800::complete() NOEXCEPT << top_.height() << ")."); } +void protocol_block_in_31800::handle_organize(const code& ec, + const chain::block::cptr& block_ptr) NOEXCEPT +{ + if (ec) + { + LOGR("Error organizing block [" << encode_hash(block_ptr->hash()) + << "] from [" << authority() << "] " << ec.message()); + stop(ec); + } +} + + // private // ---------------------------------------------------------------------------- diff --git a/src/protocols/protocol_header_in_31800.cpp b/src/protocols/protocol_header_in_31800.cpp index 1dc3ccd1..2c4ef641 100644 --- a/src/protocols/protocol_header_in_31800.cpp +++ b/src/protocols/protocol_header_in_31800.cpp @@ -87,7 +87,9 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, return false; } - organize(header_ptr, BIND1(handle_organize, _1)); + // TODO: use BIND2. + organize(header_ptr, + [=](const code& ec) { handle_organize(ec, header_ptr); }); top_ = { header_ptr->hash(), add1(top_.height()) }; LOGP("Header [" << encode_hash(top_.hash()) << "] at (" @@ -117,6 +119,17 @@ void protocol_header_in_31800::complete() NOEXCEPT << top_.height() << ")."); } +void protocol_header_in_31800::handle_organize(const code& ec, + const chain::header::cptr& header_ptr) NOEXCEPT +{ + if (ec) + { + LOGR("Error organizing header [" << encode_hash(header_ptr ->hash()) + << "] from [" << authority() << "] " << ec.message()); + stop(ec); + } +} + // private // ---------------------------------------------------------------------------- From 7e43a32fc34e9ac635f505595abef70d7ab8e611 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 22 Feb 2024 16:01:42 -0500 Subject: [PATCH 2/9] Use BIND# macro. --- src/protocols/protocol_block_in.cpp | 4 +--- src/protocols/protocol_block_in_31800.cpp | 4 +--- src/protocols/protocol_header_in_31800.cpp | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index 63077797..6c558850 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -148,9 +148,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, return false; } - // TODO: use BIND2. - organize(block_ptr, - [=](const code& ec) { handle_organize(ec, block_ptr); }); + organize(block_ptr, BIND2(handle_organize, _1, block_ptr)); top_ = { block_ptr->hash(), add1(top_.height()) }; LOGP("Block [" << encode_hash(top_.hash()) << "] at (" diff --git a/src/protocols/protocol_block_in_31800.cpp b/src/protocols/protocol_block_in_31800.cpp index 00364f90..191d510f 100644 --- a/src/protocols/protocol_block_in_31800.cpp +++ b/src/protocols/protocol_block_in_31800.cpp @@ -216,9 +216,7 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec, return false; } - // TODO: use BIND2. - organize(block_ptr, - [=](const code& ec) { handle_organize(ec, block_ptr); }); + organize(block_ptr, BIND2(handle_organize, _1, block_ptr)); top_ = { block_ptr->hash(), add1(top_.height()) }; LOGP("Block [" << encode_hash(top_.hash()) << "] at (" diff --git a/src/protocols/protocol_header_in_31800.cpp b/src/protocols/protocol_header_in_31800.cpp index 2c4ef641..17f709da 100644 --- a/src/protocols/protocol_header_in_31800.cpp +++ b/src/protocols/protocol_header_in_31800.cpp @@ -87,9 +87,7 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, return false; } - // TODO: use BIND2. - organize(header_ptr, - [=](const code& ec) { handle_organize(ec, header_ptr); }); + organize(header_ptr, BIND2(handle_organize, _1, header_ptr)); top_ = { header_ptr->hash(), add1(top_.height()) }; LOGP("Header [" << encode_hash(top_.hash()) << "] at (" From fc96b2ff93752c7bab713160427af750674d12a8 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 22 Feb 2024 17:22:49 -0500 Subject: [PATCH 3/9] Enable applicable warning suppressions. --- src/protocols/protocol_header_in_31800.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/protocol_header_in_31800.cpp b/src/protocols/protocol_header_in_31800.cpp index 17f709da..2046b4f0 100644 --- a/src/protocols/protocol_header_in_31800.cpp +++ b/src/protocols/protocol_header_in_31800.cpp @@ -35,8 +35,8 @@ using namespace network::messages; using namespace std::placeholders; // Shared pointers required for lifetime in handler parameters. -////BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED) -////BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR) +BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED) +BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR) // Start. // ---------------------------------------------------------------------------- @@ -158,8 +158,8 @@ get_headers protocol_header_in_31800::create_get_headers( return { std::move(hashes) }; } -////BC_POP_WARNING() -////BC_POP_WARNING() +BC_POP_WARNING() +BC_POP_WARNING() } // namespace node } // namespace libbitcoin From 7e8241a41a77dc921974fb430906576f1fccce32 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 22 Feb 2024 17:39:13 -0500 Subject: [PATCH 4/9] Data-driven attachment by version. --- include/bitcoin/node/sessions/attach.hpp | 36 +++++++++++------------- src/sessions/session_outbound.cpp | 34 +++++++++------------- 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/include/bitcoin/node/sessions/attach.hpp b/include/bitcoin/node/sessions/attach.hpp index 51a593e5..332a8a9e 100644 --- a/include/bitcoin/node/sessions/attach.hpp +++ b/include/bitcoin/node/sessions/attach.hpp @@ -57,40 +57,36 @@ class attach void attach_protocols( const network::channel::ptr& channel) NOEXCEPT override { - // Attach appropriate alert, reject, ping, and/or address protocols. - Session::attach_protocols(channel); - auto& self = *this; const auto version = channel->negotiated_version(); + ////constexpr auto performance = false; + + // Attach appropriate alert, reject, ping, and/or address protocols. + Session::attach_protocols(channel); if (version >= network::messages::level::bip130) { + // Headers-first synchronization (parallel block download). channel->attach(self)->start(); channel->attach(self)->start(); + ////channel->attach(self, performance)->start(); } else if (version >= network::messages::level::headers_protocol) { + // Headers-first synchronization (parallel block download). channel->attach(self)->start(); channel->attach(self)->start(); + ////channel->attach(self, performance)->start(); + } + else + { + // Blocks-first synchronization (no header protocol). + channel->attach(self)->start(); } - ////if (version >= network::messages::level::headers_protocol) - ////{ - //// // Channels only compete for download rate in outbound session. - //// constexpr auto performance = false; - //// - //// // Parallel block download (works with header protocol). - //// channel->attach(self, performance)->start(); - ////} - ////else - ////{ - //// // Blocks-first synchronization (no header protocol). - //// channel->attach(self)->start(); - ////} - - ////channel->attach(self)->start(); - ////channel->attach(self)->start(); - ////channel->attach(self)->start(); + channel->attach(self)->start(); + channel->attach(self)->start(); + channel->attach(self)->start(); } }; diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp index 1fd90614..8c9df64f 100644 --- a/src/sessions/session_outbound.cpp +++ b/src/sessions/session_outbound.cpp @@ -95,40 +95,34 @@ void session_outbound::do_performance(uint64_t channel, uint64_t speed, void session_outbound::attach_protocols( const network::channel::ptr& channel) NOEXCEPT { - // Attach appropriate alert, reject, ping, and/or address protocols. - network::session_outbound::attach_protocols(channel); - auto& self = *this; const auto version = channel->negotiated_version(); + ////constexpr auto performance = true; + + // Attach appropriate alert, reject, ping, and/or address protocols. + network::session_outbound::attach_protocols(channel); if (version >= network::messages::level::bip130) { channel->attach(self)->start(); channel->attach(self)->start(); + ////channel->attach(self, performance)->start(); } else if (version >= network::messages::level::headers_protocol) { channel->attach(self)->start(); channel->attach(self)->start(); + ////channel->attach(self, performance)->start(); + } + else + { + // Blocks-first synchronization (no header protocol). + channel->attach(self)->start(); } - ////if (version >= network::messages::level::headers_protocol) - ////{ - //// // Channels compete for download rate in outbound session. - //// constexpr auto performance = true; - //// - //// // Parallel block download (works with header protocol). - //// channel->attach(self, performance)->start(); - ////} - ////else - ////{ - //// // Blocks-first synchronization (no header protocol). - //// channel->attach(self)->start(); - ////} - - ////channel->attach(self)->start(); - ////channel->attach(self)->start(); - ////channel->attach(self)->start(); + channel->attach(self)->start(); + channel->attach(self)->start(); + channel->attach(self)->start(); } BC_POP_WARNING() From 3d30fe0c68068bc88e99d3b89b27143c907c262e Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 22 Feb 2024 17:39:32 -0500 Subject: [PATCH 5/9] Hardwire for pre-headers block protocol (no peers). --- include/bitcoin/node/sessions/attach.hpp | 33 ++++++++++++------------ src/sessions/session_outbound.cpp | 29 +++++++++++---------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/include/bitcoin/node/sessions/attach.hpp b/include/bitcoin/node/sessions/attach.hpp index 332a8a9e..caa25833 100644 --- a/include/bitcoin/node/sessions/attach.hpp +++ b/include/bitcoin/node/sessions/attach.hpp @@ -58,27 +58,28 @@ class attach const network::channel::ptr& channel) NOEXCEPT override { auto& self = *this; - const auto version = channel->negotiated_version(); + ////const auto version = channel->negotiated_version(); ////constexpr auto performance = false; // Attach appropriate alert, reject, ping, and/or address protocols. Session::attach_protocols(channel); - if (version >= network::messages::level::bip130) - { - // Headers-first synchronization (parallel block download). - channel->attach(self)->start(); - channel->attach(self)->start(); - ////channel->attach(self, performance)->start(); - } - else if (version >= network::messages::level::headers_protocol) - { - // Headers-first synchronization (parallel block download). - channel->attach(self)->start(); - channel->attach(self)->start(); - ////channel->attach(self, performance)->start(); - } - else + // Very hard to find < 31800 peer to connect with. + ////if (version >= network::messages::level::bip130) + ////{ + //// // Headers-first synchronization (parallel block download). + //// channel->attach(self)->start(); + //// channel->attach(self)->start(); + //// ////channel->attach(self, performance)->start(); + ////} + ////else if (version >= network::messages::level::headers_protocol) + ////{ + //// // Headers-first synchronization (parallel block download). + //// channel->attach(self)->start(); + //// channel->attach(self)->start(); + //// ////channel->attach(self, performance)->start(); + ////} + ////else { // Blocks-first synchronization (no header protocol). channel->attach(self)->start(); diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp index 8c9df64f..6cab25b2 100644 --- a/src/sessions/session_outbound.cpp +++ b/src/sessions/session_outbound.cpp @@ -96,25 +96,26 @@ void session_outbound::attach_protocols( const network::channel::ptr& channel) NOEXCEPT { auto& self = *this; - const auto version = channel->negotiated_version(); + ////const auto version = channel->negotiated_version(); ////constexpr auto performance = true; // Attach appropriate alert, reject, ping, and/or address protocols. network::session_outbound::attach_protocols(channel); - if (version >= network::messages::level::bip130) - { - channel->attach(self)->start(); - channel->attach(self)->start(); - ////channel->attach(self, performance)->start(); - } - else if (version >= network::messages::level::headers_protocol) - { - channel->attach(self)->start(); - channel->attach(self)->start(); - ////channel->attach(self, performance)->start(); - } - else + // Very hard to find < 31800 peer to connect with. + ////if (version >= network::messages::level::bip130) + ////{ + //// channel->attach(self)->start(); + //// channel->attach(self)->start(); + //// ////channel->attach(self, performance)->start(); + ////} + ////else if (version >= network::messages::level::headers_protocol) + ////{ + //// channel->attach(self)->start(); + //// channel->attach(self)->start(); + //// ////channel->attach(self, performance)->start(); + ////} + ////else { // Blocks-first synchronization (no header protocol). channel->attach(self)->start(); From 5405681cd3a2eaff8dc5246196e4eb2568a79f9c Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 23 Feb 2024 13:37:47 -0500 Subject: [PATCH 6/9] chaser_header style/comments. --- .../bitcoin/node/chasers/chaser_header.hpp | 8 ++-- src/chasers/chaser_header.cpp | 46 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp index b225386d..ea5fd4f9 100644 --- a/include/bitcoin/node/chasers/chaser_header.hpp +++ b/include/bitcoin/node/chasers/chaser_header.hpp @@ -53,7 +53,7 @@ class BCN_API chaser_header struct proposed_header { database::context context; - system::chain::header::cptr item; + system::chain::header::cptr header; }; typedef std::vector header_links; @@ -92,14 +92,16 @@ class BCN_API chaser_header /// Move tree header to database and push to top of candidate chain. virtual bool push(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 network::result_handler& handler) NOEXCEPT; + /// Properties. virtual const network::wall_clock::duration& currency_window() const NOEXCEPT; virtual bool use_currency_window() const NOEXCEPT; private: void do_handle_event(const code& ec, chase event_, link value) NOEXCEPT; - void do_organize(const system::chain::header::cptr& header, - const network::result_handler& handler) NOEXCEPT; // These are thread safe. const system::chain::checkpoints& checkpoints_; diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index bb0f0cf0..46c2b52e 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -30,6 +30,7 @@ namespace node { using namespace network; using namespace system; +using namespace system::chain; using namespace std::placeholders; BC_PUSH_WARNING(NO_NEW_OR_DELETE) @@ -87,7 +88,7 @@ void chaser_header::do_handle_event(const code&, chase, link) NOEXCEPT BC_ASSERT_MSG(stranded(), "chaser_header"); } -void chaser_header::organize(const chain::header::cptr& header, +void chaser_header::organize(const header::cptr& header, result_handler&& handler) NOEXCEPT { boost::asio::post(strand(), @@ -95,9 +96,11 @@ void chaser_header::organize(const chain::header::cptr& header, this, header, std::move(handler))); } -// private +// protected +// ---------------------------------------------------------------------------- + // Caller may capture header_ptr in handler closure for detailed logging. -void chaser_header::do_organize(const chain::header::cptr& header_ptr, +void chaser_header::do_organize(const header::cptr& header_ptr, const result_handler& handler) NOEXCEPT { BC_ASSERT_MSG(stranded(), "chaser_header"); @@ -135,11 +138,11 @@ void chaser_header::do_organize(const chain::header::cptr& header_ptr, // ------------------------------------------------------------------------ // Rolling forward chain_state eliminates requery cost. - state_.reset(new chain::chain_state(*state_, header, coin)); + state_.reset(new chain_state(*state_, header, coin)); const auto context = state_->context(); // Checkpoints are considered chain not block/header validation. - if (chain::checkpoint::is_conflict(coin.checkpoints, hash, + if (checkpoint::is_conflict(coin.checkpoints, hash, state_->height())) { handler(network::error::protocol_violation); @@ -256,15 +259,14 @@ void chaser_header::do_organize(const chain::header::cptr& header_ptr, handler(error::success); } -// protected -bool chaser_header::is_current(const chain::header& header, +bool chaser_header::is_current(const header& header, size_t height) const NOEXCEPT { if (!use_currency_window()) return true; // Checkpoints are already validated. Current if at a checkpoint height. - if (chain::checkpoint::is_at(checkpoints_, height)) + if (checkpoint::is_at(checkpoints_, height)) return true; // en.wikipedia.org/wiki/Time_formatting_and_storage_bugs#Year_2106 @@ -275,8 +277,8 @@ bool chaser_header::is_current(const chain::header& header, // protected bool chaser_header::get_branch_work(uint256_t& work, size_t& point, - system::hashes& tree_branch, header_links& store_branch, - const chain::header& header) const NOEXCEPT + hashes& tree_branch, header_links& store_branch, + const header& header) const NOEXCEPT { // Use pointer to avoid const/copy. auto previous = &header.previous_block_hash(); @@ -289,9 +291,9 @@ bool chaser_header::get_branch_work(uint256_t& work, size_t& point, for (auto it = tree_.find(*previous); it != tree_.end(); it = tree_.find(*previous)) { - previous = &it->second.item->previous_block_hash(); - tree_branch.push_back(it->second.item->hash()); - work += it->second.item->proof(); + previous = &it->second.header->previous_block_hash(); + tree_branch.push_back(it->second.header->hash()); + work += it->second.header->proof(); } // Sum branch work from store. @@ -304,14 +306,13 @@ bool chaser_header::get_branch_work(uint256_t& work, size_t& point, return false; store_branch.push_back(link); - work += system::chain::header::proof(bits); + work += chain::header::proof(bits); } // Height of the highest candidate header is the branch point. return query.get_height(point, link); } -// protected // **************************************************************************** // CONSENSUS: branch with greater work causes candidate reorganization. // Chasers eventually reorganize candidate branch into confirmed if valid. @@ -328,7 +329,7 @@ bool chaser_header::get_is_strong(bool& strong, const uint256_t& work, if (!query.get_bits(bits, query.to_candidate(height))) return false; - candidate_work += chain::header::proof(bits); + candidate_work += header::proof(bits); if (!((strong = work > candidate_work))) return true; } @@ -337,9 +338,8 @@ bool chaser_header::get_is_strong(bool& strong, const uint256_t& work, return true; } -// protected -void chaser_header::save(const chain::header::cptr& header, - const chain::context& context) NOEXCEPT +void chaser_header::save(const header::cptr& header, + const context& context) NOEXCEPT { tree_.insert( { @@ -355,9 +355,8 @@ void chaser_header::save(const chain::header::cptr& header, }); } -// protected -database::header_link chaser_header::push(const chain::header::cptr& header, - const chain::context& context) const NOEXCEPT +database::header_link chaser_header::push(const header::cptr& header, + const context& context) const NOEXCEPT { auto& query = archive(); const auto link = query.set_link(*header, database::context @@ -373,7 +372,6 @@ database::header_link chaser_header::push(const chain::header::cptr& header, return link; } -// protected bool chaser_header::push(const system::hash_digest& key) NOEXCEPT { const auto value = tree_.extract(key); @@ -381,7 +379,7 @@ bool chaser_header::push(const system::hash_digest& key) NOEXCEPT auto& query = archive(); const auto& node = value.mapped(); - return query.push_candidate(query.set_link(*node.item, node.context)); + return query.push_candidate(query.set_link(*node.header, node.context)); } BC_POP_WARNING() From 4548524d90fdeec7dc8ec950d972259ce3613aef Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 23 Feb 2024 13:39:48 -0500 Subject: [PATCH 7/9] Implement chaser_block.populate, style. --- include/bitcoin/node/chasers/chaser_block.hpp | 13 +- src/chasers/chaser_block.cpp | 118 +++++++++++------- 2 files changed, 83 insertions(+), 48 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser_block.hpp b/include/bitcoin/node/chasers/chaser_block.hpp index fdad7bf3..284d86b5 100644 --- a/include/bitcoin/node/chasers/chaser_block.hpp +++ b/include/bitcoin/node/chasers/chaser_block.hpp @@ -52,7 +52,7 @@ class BCN_API chaser_block struct validated_block { database::context context; - system::chain::block::cptr item; + system::chain::block::cptr block; }; typedef std::vector header_links; @@ -91,15 +91,22 @@ class BCN_API chaser_block /// Move tree header to database and push to top of candidate chain. virtual bool push(const system::hash_digest& key) NOEXCEPT; + /// Populate block prevouts and metadata from block tree. + virtual void populate(const system::chain::block& block) const NOEXCEPT; + + /// Validate and organize next block in sequence relative to caller peer. + virtual void do_organize(const system::chain::block::cptr& block, + const network::result_handler& handler) NOEXCEPT; + /// Properties. /// Given non-current blocks cached in memory, should always be zero/false. virtual const network::wall_clock::duration& currency_window() const NOEXCEPT; virtual bool use_currency_window() const NOEXCEPT; private: + void set_prevout(const system::chain::input& input) const NOEXCEPT; + void do_handle_event(const code& ec, chase event_, link value) NOEXCEPT; - void do_organize(const system::chain::block::cptr& block, - const network::result_handler& handler) NOEXCEPT; // These are thread safe. const system::chain::checkpoints& checkpoints_; diff --git a/src/chasers/chaser_block.cpp b/src/chasers/chaser_block.cpp index e5ace80e..4554f91d 100644 --- a/src/chasers/chaser_block.cpp +++ b/src/chasers/chaser_block.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -30,6 +31,7 @@ namespace node { using namespace network; using namespace system; +using namespace system::chain; using namespace std::placeholders; BC_PUSH_WARNING(NO_NEW_OR_DELETE) @@ -87,7 +89,7 @@ void chaser_block::do_handle_event(const code&, chase, link) NOEXCEPT BC_ASSERT_MSG(stranded(), "chaser_block"); } -void chaser_block::organize(const chain::block::cptr& block, +void chaser_block::organize(const block::cptr& block, result_handler&& handler) NOEXCEPT { boost::asio::post(strand(), @@ -95,9 +97,11 @@ void chaser_block::organize(const chain::block::cptr& block, this, block, std::move(handler))); } -// private +// protected +// ---------------------------------------------------------------------------- + // Caller may capture block_ptr in handler closure for detailed logging. -void chaser_block::do_organize(const chain::block::cptr& block_ptr, +void chaser_block::do_organize(const block::cptr& block_ptr, const result_handler& handler) NOEXCEPT { BC_ASSERT_MSG(stranded(), "chaser_block"); @@ -139,19 +143,19 @@ void chaser_block::do_organize(const chain::block::cptr& block_ptr, // Rolling forward chain_state eliminates requery cost. // Do not use block ref here as the block override is for tx pool. - state_.reset(new chain::chain_state(*state_, header, coin)); + state_.reset(new chain_state(*state_, header, coin)); const auto context = state_->context(); + const auto height = state_->height(); // Checkpoints are considered chain not block/header validation. - if (chain::checkpoint::is_conflict(coin.checkpoints, hash, - state_->height())) + if (checkpoint::is_conflict(coin.checkpoints, hash, height)) { handler(network::error::protocol_violation); return; }; // Block validations are bypassed when under checkpoint/milestone. - if (!chain::checkpoint::is_under(coin.checkpoints, state_->height())) + if (!checkpoint::is_under(coin.checkpoints, height)) { auto error = block.check(); if (error) @@ -167,27 +171,20 @@ void chaser_block::do_organize(const chain::block::cptr& block_ptr, return; } - // Populate prevouts only, internal to block. - // ******************************************************************** - // TODO: populate input metadata for block internal. - // ******************************************************************** - block.populate(); + // Populate prevouts/metadata internal to block. + block.populate(height, state_->median_time_past()); - // ******************************************************************** - // TODO: populate prevouts and input metadata for block tree. - // ******************************************************************** + // Populate prevouts/metadata from block tree. + populate(block); - // Populate stored missing prevouts only, not input metadata. - // ******************************************************************** - // TODO: populate input metadata for stored blocks. - // ******************************************************************** + // Populate prevouts/metadata from store. if (!query.populate(block)) { handler(network::error::protocol_violation); return; } - // TODO: also requires input metadata population. + // Requires input metadata population. error = block.accept(context, coin.subsidy_interval_blocks, coin.initial_subsidy()); if (error) @@ -203,10 +200,6 @@ void chaser_block::do_organize(const chain::block::cptr& block_ptr, handler(network::error::protocol_violation); return; } - - // ******************************************************************** - // TODO: with all metadata populated, block.confirm may be possible. - // ******************************************************************** } // Compute relative work. @@ -310,15 +303,14 @@ void chaser_block::do_organize(const chain::block::cptr& block_ptr, handler(error::success); } -// protected -bool chaser_block::is_current(const chain::header& header, +bool chaser_block::is_current(const header& header, size_t height) const NOEXCEPT { if (!use_currency_window()) return true; // Checkpoints are already validated. Current if at a checkpoint height. - if (chain::checkpoint::is_at(checkpoints_, height)) + if (checkpoint::is_at(checkpoints_, height)) return true; // en.wikipedia.org/wiki/Time_formatting_and_storage_bugs#Year_2106 @@ -327,10 +319,9 @@ bool chaser_block::is_current(const chain::header& header, return time >= current; } -// protected bool chaser_block::get_branch_work(uint256_t& work, size_t& point, - system::hashes& tree_branch, header_links& store_branch, - const chain::header& header) const NOEXCEPT + hashes& tree_branch, header_links& store_branch, + const header& header) const NOEXCEPT { // Use pointer to avoid const/copy. auto previous = &header.previous_block_hash(); @@ -343,9 +334,9 @@ bool chaser_block::get_branch_work(uint256_t& work, size_t& point, for (auto it = tree_.find(*previous); it != tree_.end(); it = tree_.find(*previous)) { - previous = &it->second.item->header().previous_block_hash(); - tree_branch.push_back(it->second.item->header().hash()); - work += it->second.item->header().proof(); + previous = &it->second.block->header().previous_block_hash(); + tree_branch.push_back(it->second.block->header().hash()); + work += it->second.block->header().proof(); } // Sum branch work from store. @@ -358,14 +349,13 @@ bool chaser_block::get_branch_work(uint256_t& work, size_t& point, return false; store_branch.push_back(link); - work += system::chain::header::proof(bits); + work += chain::header::proof(bits); } // Height of the highest candidate header is the branch point. return query.get_height(point, link); } -// protected // **************************************************************************** // CONSENSUS: branch with greater work causes candidate reorganization. // Chasers eventually reorganize candidate branch into confirmed if valid. @@ -382,7 +372,7 @@ bool chaser_block::get_is_strong(bool& strong, const uint256_t& work, if (!query.get_bits(bits, query.to_candidate(height))) return false; - candidate_work += chain::header::proof(bits); + candidate_work += header::proof(bits); if (!((strong = work > candidate_work))) return true; } @@ -391,9 +381,8 @@ bool chaser_block::get_is_strong(bool& strong, const uint256_t& work, return true; } -// protected -void chaser_block::save(const chain::block::cptr& block, - const chain::context& context) NOEXCEPT +void chaser_block::save(const block::cptr& block, + const context& context) NOEXCEPT { tree_.insert( { @@ -409,9 +398,8 @@ void chaser_block::save(const chain::block::cptr& block, }); } -// protected -database::header_link chaser_block::push(const chain::block::cptr& block, - const chain::context& context) const NOEXCEPT +database::header_link chaser_block::push(const block::cptr& block, + const context& context) const NOEXCEPT { auto& query = archive(); const auto link = query.set_link(*block, database::context @@ -427,15 +415,55 @@ database::header_link chaser_block::push(const chain::block::cptr& block, return link; } -// protected -bool chaser_block::push(const system::hash_digest& key) NOEXCEPT +bool chaser_block::push(const hash_digest& key) NOEXCEPT { const auto value = tree_.extract(key); BC_ASSERT_MSG(!value.empty(), "missing tree value"); auto& query = archive(); const auto& node = value.mapped(); - return query.push_candidate(query.set_link(*node.item, node.context)); + return query.push_candidate(query.set_link(*node.block, node.context)); +} + +void chaser_block::set_prevout(const input& input) const NOEXCEPT +{ + const auto& point = input.point(); + + // Scan all blocks for matching tx (linear :/) + std::for_each(tree_.begin(), tree_.end(), [&](const auto& element) NOEXCEPT + { + const auto& txs = *element.second.block->transactions_ptr(); + const auto it = std::find_if(txs.begin(), txs.end(), + [&](const auto& tx) NOEXCEPT + { + return tx->hash(false) == point.hash(); + }); + + if (it != txs.end()) + { + const auto& tx = **it; + const auto& outs = *tx.outputs_ptr(); + if (point.index() < outs.size()) + { + input.prevout = outs.at(point.index()); + input.metadata.height = element.second.context.height; + input.metadata.median_time_past = element.second.context.mtp; + input.metadata.coinbase = tx.is_coinbase(); + input.metadata.spent = false; + return; + } + } + }); +} + +void chaser_block::populate(const block& block) const NOEXCEPT +{ + const auto ins = block.inputs_ptr(); + std::for_each(ins->begin(), ins->end(), [&](const auto& in) NOEXCEPT + { + if (!in->prevout && !in->point().is_null()) + set_prevout(*in); + }); } BC_POP_WARNING() From 3d9b925dcba635886267f4ecfc376cab9054aeb4 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 23 Feb 2024 14:48:43 -0500 Subject: [PATCH 8/9] Comment. --- src/chasers/chaser_block.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/chasers/chaser_block.cpp b/src/chasers/chaser_block.cpp index 4554f91d..dfc0d4b3 100644 --- a/src/chasers/chaser_block.cpp +++ b/src/chasers/chaser_block.cpp @@ -449,6 +449,8 @@ void chaser_block::set_prevout(const input& input) const NOEXCEPT input.metadata.height = element.second.context.height; input.metadata.median_time_past = element.second.context.mtp; input.metadata.coinbase = tx.is_coinbase(); + + // Spentness is not populated, handled in confirmation chaser. input.metadata.spent = false; return; } From 1ad5cceec68eb3a4279266999f92cbff88ba0a59 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 23 Feb 2024 21:33:17 -0500 Subject: [PATCH 9/9] Revert block.populate() metadata. --- include/bitcoin/node/chasers/chaser_block.hpp | 1 - src/chasers/chaser_block.cpp | 16 +++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser_block.hpp b/include/bitcoin/node/chasers/chaser_block.hpp index 284d86b5..6e298de6 100644 --- a/include/bitcoin/node/chasers/chaser_block.hpp +++ b/include/bitcoin/node/chasers/chaser_block.hpp @@ -105,7 +105,6 @@ class BCN_API chaser_block private: void set_prevout(const system::chain::input& input) const NOEXCEPT; - void do_handle_event(const code& ec, chase event_, link value) NOEXCEPT; // These are thread safe. diff --git a/src/chasers/chaser_block.cpp b/src/chasers/chaser_block.cpp index dfc0d4b3..e3a9c0a7 100644 --- a/src/chasers/chaser_block.cpp +++ b/src/chasers/chaser_block.cpp @@ -171,20 +171,20 @@ void chaser_block::do_organize(const block::cptr& block_ptr, return; } - // Populate prevouts/metadata internal to block. - block.populate(height, state_->median_time_past()); + // Populate prevouts internal to block. + block.populate(); - // Populate prevouts/metadata from block tree. + // Populate prevouts from block tree. populate(block); - // Populate prevouts/metadata from store. + // Populate prevouts from store. if (!query.populate(block)) { handler(network::error::protocol_violation); return; } - // Requires input metadata population. + // Requires only prevout population. error = block.accept(context, coin.subsidy_interval_blocks, coin.initial_subsidy()); if (error) @@ -446,12 +446,6 @@ void chaser_block::set_prevout(const input& input) const NOEXCEPT if (point.index() < outs.size()) { input.prevout = outs.at(point.index()); - input.metadata.height = element.second.context.height; - input.metadata.median_time_past = element.second.context.mtp; - input.metadata.coinbase = tx.is_coinbase(); - - // Spentness is not populated, handled in confirmation chaser. - input.metadata.spent = false; return; } }