From 947e79e0affeebb54d6939e886980a2524cb268a Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 30 Apr 2023 23:07:43 -0700 Subject: [PATCH 01/27] std::ios_base::sync_with_stdio(false) --- console/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/console/main.cpp b/console/main.cpp index 5af87307..fa764e9f 100644 --- a/console/main.cpp +++ b/console/main.cpp @@ -81,6 +81,9 @@ int bc::system::main(int argc, char* argv[]) using namespace bc::node; using namespace bc::system; + // en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio + std::ios_base::sync_with_stdio(false); + set_utf8_stdio(); parser metadata(chain::selection::mainnet); const auto& args = const_cast(argv); From a3c75e50ea6e81fdf0fa3e90c898e08e8d7e03e9 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 27 Jan 2024 13:45:05 -0500 Subject: [PATCH 02/27] Delint, rename state_.context() ref from state to context. --- src/protocols/protocol_block_in.cpp | 18 +++++++++--------- src/protocols/protocol_header_in_31800.cpp | 14 ++++++++------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index fd086795..9de97dc2 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -205,11 +205,11 @@ bool protocol_block_in::handle_receive_block(const code& ec, state_.reset(new chain::chain_state(*state_, block.header(), coin)); auto& query = archive(); - const auto state = state_->context(); + const auto context = state_->context(); // hack in bit0 late and bit1(segwit) on schedule. - //// state.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); - const auto link = query.set_link(block, state); + //// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); + const auto link = query.set_link(block, context); if (link.is_terminal()) { // This should only be from missing parent, but guarded above. @@ -228,7 +228,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //// return false; ////} - ////error = block.check(state); + ////error = block.check(context); ////if (error) ////{ //// LOGR("Invalid block (check2) [" << encode_hash(hash) @@ -237,7 +237,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //// return false; ////} - ////error = block.accept(state, coin.subsidy_interval_blocks, + ////error = block.accept(context, coin.subsidy_interval_blocks, //// coin.initial_subsidy()); ////if (error) ////{ @@ -247,7 +247,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //// return false; ////} - ////error = block.connect(state); + ////error = block.connect(context); ////if (error) ////{ //// LOGR("Invalid block (connect) [" << encode_hash(hash) @@ -270,11 +270,11 @@ bool protocol_block_in::handle_receive_block(const code& ec, } // Size will be incorrect with multiple peers or headers protocol. - if (is_zero(state.height % 10'000)) + if (is_zero(context.height % 10'000)) { - ////reporter::fire(event_block, state.height); + ////reporter::fire(event_block, context.height); ////reporter::fire(event_archive, query.archive_size()); - LOGN("BLOCK: " << state.height + LOGN("BLOCK: " << context.height << " secs: " << (unix_time() - start_) << " txs: " << query.tx_records() << " archive: " << query.archive_size()); diff --git a/src/protocols/protocol_header_in_31800.cpp b/src/protocols/protocol_header_in_31800.cpp index 1198b634..810d701e 100644 --- a/src/protocols/protocol_header_in_31800.cpp +++ b/src/protocols/protocol_header_in_31800.cpp @@ -118,10 +118,12 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, } // Rolling forward chain_state eliminates database cost. + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) state_.reset(new chain::chain_state(*state_, header, coin)); + BC_POP_WARNING() - const auto state = state_->context(); - error = header.accept(state); + const auto context = state_->context(); + error = header.accept(context); if (error) { LOGR("Invalid header (accept) [" << encode_hash(hash) @@ -131,8 +133,8 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, } // hack in bit0 late and bit1(segwit) on schedule. - //// state.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); - const auto link = query.set_link(header, state); + //// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); + const auto link = query.set_link(header, context); if (link.is_terminal()) { // This should only be from missing parent, but guarded above. @@ -151,8 +153,8 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, return false; } - if (is_zero(state.height % 10'000)) - reporter::fire(event_header, state.height); + if (is_zero(context.height % 10'000)) + reporter::fire(event_header, context.height); } // Protocol presumes max_get_headers unless complete. From 8a50a488685117c1bc2dad2be19a3cb133d9d384 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 28 Jan 2024 17:20:15 -0500 Subject: [PATCH 03/27] Style: avoid abbreviations (cap vs. capture). --- console/executor.cpp | 6 +++--- console/executor.hpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/console/executor.cpp b/console/executor.cpp index 28a08290..49f79a14 100644 --- a/console/executor.cpp +++ b/console/executor.cpp @@ -187,7 +187,7 @@ void executor::console(const auto& message) const void executor::stopper(const auto& message) { - cap_.stop(); + capture_.stop(); log_.stop(message, levels::application); stopped_.get_future().wait(); } @@ -1598,7 +1598,7 @@ void executor::subscribe_events(std::ostream& sink) void executor::subscribe_capture() { - cap_.subscribe([&](const code& ec, const std::string& line) + capture_.subscribe([&](const code& ec, const std::string& line) { const auto token = system::trim_copy(line); if (!keys_.contains(token)) @@ -1738,7 +1738,7 @@ bool executor::do_run() } logger(BN_NODE_INTERRUPT); - cap_.start(); + capture_.start(); // Open store. logger(BN_STORE_STARTING); diff --git a/console/executor.hpp b/console/executor.hpp index 69bfda9a..816b3ee3 100644 --- a/console/executor.hpp +++ b/console/executor.hpp @@ -95,15 +95,15 @@ class executor static std::atomic_bool cancel_; parser& metadata_; + full_node::ptr node_{}; full_node::store store_; full_node::query query_; std::promise stopped_{}; - full_node::ptr node_{}; std::istream& input_; std::ostream& output_; network::logger log_{}; - network::capture cap_{ input_, quit_ }; + network::capture capture_{ input_, quit_ }; std_array toggle_ { true, // application From dcfd64b77a33efd90ec3d1b1ff1e728da0d160cb Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 28 Jan 2024 17:20:54 -0500 Subject: [PATCH 04/27] Sort usings. --- console/executor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/executor.cpp b/console/executor.cpp index 49f79a14..26b23b91 100644 --- a/console/executor.cpp +++ b/console/executor.cpp @@ -38,10 +38,10 @@ namespace node { using boost::format; using system::config::printer; -using namespace system; using namespace network; -using namespace std::placeholders; +using namespace system; using namespace std::chrono; +using namespace std::placeholders; // const executor statics const std::string executor::quit_{ "q" }; From 2a210d758617e0da8197056a353156669de0e6b5 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 28 Jan 2024 19:47:05 -0500 Subject: [PATCH 05/27] Delint. --- src/protocols/protocol_block_in.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index 9de97dc2..f94885b3 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -202,7 +202,9 @@ bool protocol_block_in::handle_receive_block(const code& ec, ////} // Rolling forward chain_state eliminates database cost. + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) state_.reset(new chain::chain_state(*state_, block.header(), coin)); + BC_POP_WARNING() auto& query = archive(); const auto context = state_->context(); From 35a5321d3345dc5b2c98fa24c7ac832292a1f124 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 28 Jan 2024 19:50:22 -0500 Subject: [PATCH 06/27] Remove (disabled) checkpoint validation from block validation. --- src/protocols/protocol_block_in.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index f94885b3..af3a31a4 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -191,16 +191,6 @@ bool protocol_block_in::handle_receive_block(const code& ec, //// return false; ////} - ////// TODO: only in header. - ////if (chain::checkpoint::is_conflict(coin.checkpoints, hash, - //// add1(state_->height()))) - ////{ - //// LOGR("Invalid block (checkpoint) [" << encode_hash(hash) - //// << "] from [" << authority() << "]."); - //// stop(network::error::protocol_violation); - //// return false; - ////} - // Rolling forward chain_state eliminates database cost. BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) state_.reset(new chain::chain_state(*state_, block.header(), coin)); From 10f1e130b538258919bfe5c8f60b9648deb0b552 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 28 Jan 2024 19:53:23 -0500 Subject: [PATCH 07/27] Comments. --- src/protocols/protocol_block_in.cpp | 4 ++-- src/protocols/protocol_header_in_31800.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index af3a31a4..a5fc3bf4 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -199,12 +199,12 @@ bool protocol_block_in::handle_receive_block(const code& ec, auto& query = archive(); const auto context = state_->context(); - // hack in bit0 late and bit1(segwit) on schedule. + // TODO: ensure soft forks activated in chain_state. //// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); const auto link = query.set_link(block, context); if (link.is_terminal()) { - // This should only be from missing parent, but guarded above. + // Should only be from missing parent, and that's guarded above. LOGF("Store block error [" << encode_hash(hash) << "] from [" << authority() << "]."); stop(network::error::unknown); diff --git a/src/protocols/protocol_header_in_31800.cpp b/src/protocols/protocol_header_in_31800.cpp index 810d701e..1e491d3b 100644 --- a/src/protocols/protocol_header_in_31800.cpp +++ b/src/protocols/protocol_header_in_31800.cpp @@ -132,12 +132,12 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, return false; } - // hack in bit0 late and bit1(segwit) on schedule. + // TODO: ensure soft forks activated in chain_state. //// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); const auto link = query.set_link(header, context); if (link.is_terminal()) { - // This should only be from missing parent, but guarded above. + // Should only be from missing parent, and that's guarded above. LOGF("Store header error [" << encode_hash(hash) << "] from [" << authority() << "]."); stop(network::error::unknown); From 26dec95c07cc6d32f372d49ca0bd10609f0a2688 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 28 Jan 2024 20:47:30 -0500 Subject: [PATCH 08/27] Comments, enable full block validation. --- src/protocols/protocol_block_in.cpp | 97 ++++++++++++++--------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index a5fc3bf4..87336957 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -155,16 +155,17 @@ bool protocol_block_in::handle_receive_block(const code& ec, const auto& coin = config().bitcoin; const auto hash = block.hash(); - // May not have been announced (ie miner broadcast) or different inv. + // May not have been announced (miner broadcast) or different inv. if (tracker->hashes.back() != hash) return true; + // Out of order (orphan). if (block.header().previous_block_hash() != state_->hash()) { - // Out of order or invalid. + // Announcements are assumed to be small in number. if (tracker->announced > maximum_advertisement) { - // Treat orphan from larger-than-announce as invalid inventory. + // Treat as invalid inventory. LOGR("Orphan block inventory [" << encode_hash(message->block_ptr->hash()) << "] from [" << authority() << "]."); @@ -173,7 +174,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, } else { - // Unlike headers, block announcements may come before caught-up. + // Block announcements may come before caught-up. LOGP("Orphan block announcement [" << encode_hash(message->block_ptr->hash()) << "] from [" << authority() << "]."); @@ -181,15 +182,14 @@ bool protocol_block_in::handle_receive_block(const code& ec, } } - ////auto error = block.check(); - ////if (error) - ////{ - //// // assume announced. - //// LOGR("Invalid block (check1) [" << encode_hash(hash) - //// << "] from [" << authority() << "] " << error.message()); - //// stop(network::error::protocol_violation); - //// return false; - ////} + auto error = block.check(); + if (error) + { + LOGR("Invalid block (check) [" << encode_hash(hash) + << "] from [" << authority() << "] " << error.message()); + stop(network::error::protocol_violation); + return false; + } // Rolling forward chain_state eliminates database cost. BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) @@ -211,50 +211,45 @@ bool protocol_block_in::handle_receive_block(const code& ec, return false; } - ////// Block must be archived for full populate (no DoS protect). - ////if (!query.populate(block)) - ////{ - //// LOGR("Invalid block (populate) [" << encode_hash(hash) - //// << "] from [" << authority() << "]."); - //// stop(network::error::protocol_violation); - //// return false; - ////} - - ////error = block.check(context); - ////if (error) - ////{ - //// LOGR("Invalid block (check2) [" << encode_hash(hash) - //// << "] from [" << authority() << "] " << error.message()); - //// stop(network::error::protocol_violation); - //// return false; - ////} - - ////error = block.accept(context, coin.subsidy_interval_blocks, - //// coin.initial_subsidy()); - ////if (error) - ////{ - //// LOGR("Invalid block (accept) [" << encode_hash(hash) - //// << "] from [" << authority() << "] " << error.message()); - //// stop(network::error::protocol_violation); - //// return false; - ////} - - ////error = block.connect(context); - ////if (error) - ////{ - //// LOGR("Invalid block (connect) [" << encode_hash(hash) - //// << "] from [" << authority() << "] " << error.message()); - //// stop(network::error::protocol_violation); - //// return false; - ////} + // Block must be archived for populate. + if (!query.populate(block)) + { + // Invalid block is archived. + LOGR("Invalid block (populate) [" << encode_hash(hash) + << "] from [" << authority() << "]."); + stop(network::error::protocol_violation); + return false; + } + + error = block.accept(context, coin.subsidy_interval_blocks, + coin.initial_subsidy()); + if (error) + { + // Invalid block is archived. + LOGR("Invalid block (accept) [" << encode_hash(hash) + << "] from [" << authority() << "] " << error.message()); + stop(network::error::protocol_violation); + return false; + } + + error = block.connect(context); + if (error) + { + // Invalid block is archived. + LOGR("Invalid block (connect) [" << encode_hash(hash) + << "] from [" << authority() << "] " << error.message()); + stop(network::error::protocol_violation); + return false; + } // If populate, accept, or connect fail this is bypassed and a restart will // initialize state_ at the prior block as top. But this block exists, so // it will be skipped for download. This results in the next being orphaned // following the channel stop/start or any subsequent runs on the store. - // This is the job of the confirmation chaser. + // This is the job of the confirmation chaser (todo). if (!query.push_confirmed(link)) { + // Invalid block is archived. LOGF("Push confirmed error [" << encode_hash(hash) << "] from [" << authority() << "]."); stop(network::error::unknown); @@ -305,7 +300,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, // The distinction is ultimately arbitrary, but this signals initial currency. void protocol_block_in::current() NOEXCEPT { - reporter::fire(event_current_blocks, state_->height()); + ////reporter::fire(event_current_blocks, state_->height()); LOGN("Blocks from [" << authority() << "] complete at (" << state_->height() << ")."); } From f18d6c721c6ee4fe9f8546c752a23669722358e0 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 29 Jan 2024 10:40:05 -0500 Subject: [PATCH 09/27] Disable reporting and accept/connect validation, comments, style. --- src/protocols/protocol_block_in.cpp | 91 +++++++++++----------- src/protocols/protocol_header_in_31800.cpp | 7 +- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index 87336957..9b2c8936 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -201,6 +201,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, // TODO: ensure soft forks activated in chain_state. //// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); + const auto link = query.set_link(block, context); if (link.is_terminal()) { @@ -211,53 +212,53 @@ bool protocol_block_in::handle_receive_block(const code& ec, return false; } - // Block must be archived for populate. - if (!query.populate(block)) - { - // Invalid block is archived. - LOGR("Invalid block (populate) [" << encode_hash(hash) - << "] from [" << authority() << "]."); - stop(network::error::protocol_violation); - return false; - } - - error = block.accept(context, coin.subsidy_interval_blocks, - coin.initial_subsidy()); - if (error) - { - // Invalid block is archived. - LOGR("Invalid block (accept) [" << encode_hash(hash) - << "] from [" << authority() << "] " << error.message()); - stop(network::error::protocol_violation); - return false; - } - - error = block.connect(context); - if (error) - { - // Invalid block is archived. - LOGR("Invalid block (connect) [" << encode_hash(hash) - << "] from [" << authority() << "] " << error.message()); - stop(network::error::protocol_violation); - return false; - } - - // If populate, accept, or connect fail this is bypassed and a restart will - // initialize state_ at the prior block as top. But this block exists, so - // it will be skipped for download. This results in the next being orphaned - // following the channel stop/start or any subsequent runs on the store. - // This is the job of the confirmation chaser (todo). - if (!query.push_confirmed(link)) - { - // Invalid block is archived. - LOGF("Push confirmed error [" << encode_hash(hash) - << "] from [" << authority() << "]."); - stop(network::error::unknown); - return false; - } + ////// Block must be archived for populate. + ////if (!query.populate(block)) + ////{ + //// // Invalid block is archived. + //// LOGR("Invalid block (populate) [" << encode_hash(hash) + //// << "] from [" << authority() << "]."); + //// stop(network::error::protocol_violation); + //// return false; + ////} + + ////error = block.accept(context, coin.subsidy_interval_blocks, + //// coin.initial_subsidy()); + ////if (error) + ////{ + //// // Invalid block is archived. + //// LOGR("Invalid block (accept) [" << encode_hash(hash) + //// << "] from [" << authority() << "] " << error.message()); + //// stop(network::error::protocol_violation); + //// return false; + ////} + + ////error = block.connect(context); + ////if (error) + ////{ + //// // Invalid block is archived. + //// LOGR("Invalid block (connect) [" << encode_hash(hash) + //// << "] from [" << authority() << "] " << error.message()); + //// stop(network::error::protocol_violation); + //// return false; + ////} + + ////// If populate, accept, or connect fail this is bypassed and a restart will + ////// initialize state_ at the prior block as top. But this block exists, so + ////// it will be skipped for download. This results in the next being orphaned + ////// following the channel stop/start or any subsequent runs on the store. + ////// This is the job of the confirmation chaser (todo). + ////if (!query.push_confirmed(link)) + ////{ + //// // Invalid block is archived. + //// LOGF("Push confirmed error [" << encode_hash(hash) + //// << "] from [" << authority() << "]."); + //// stop(network::error::unknown); + //// return false; + ////} // Size will be incorrect with multiple peers or headers protocol. - if (is_zero(context.height % 10'000)) + if (is_zero(context.height % 1'000)) { ////reporter::fire(event_block, context.height); ////reporter::fire(event_archive, query.archive_size()); diff --git a/src/protocols/protocol_header_in_31800.cpp b/src/protocols/protocol_header_in_31800.cpp index 1e491d3b..95e8319c 100644 --- a/src/protocols/protocol_header_in_31800.cpp +++ b/src/protocols/protocol_header_in_31800.cpp @@ -134,6 +134,7 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, // TODO: ensure soft forks activated in chain_state. //// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); + const auto link = query.set_link(header, context); if (link.is_terminal()) { @@ -153,8 +154,8 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, return false; } - if (is_zero(context.height % 10'000)) - reporter::fire(event_header, context.height); + ////if (is_zero(context.height % 10'000)) + //// reporter::fire(event_header, context.height); } // Protocol presumes max_get_headers unless complete. @@ -176,7 +177,7 @@ bool protocol_header_in_31800::handle_receive_headers(const code& ec, // The distinction is ultimately arbitrary, but this signals initial currency. void protocol_header_in_31800::current() NOEXCEPT { - reporter::fire(event_current_headers, state_->height()); + ////reporter::fire(event_current_headers, state_->height()); LOGN("Headers from [" << authority() << "] complete at (" << state_->height() << ")."); } From ae1120d51fcbf356e178f3d782aa8931d92fa6ce Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 29 Jan 2024 11:12:31 -0500 Subject: [PATCH 10/27] Stub in block_chaser and rate polling. --- Makefile.am | 5 + builds/cmake/CMakeLists.txt | 1 + .../libbitcoin-node/libbitcoin-node.vcxproj | 2 + .../libbitcoin-node.vcxproj.filters | 28 +++- console/executor.cpp | 149 +++++++++--------- include/bitcoin/node.hpp | 1 + include/bitcoin/node/chasers/block_chaser.hpp | 79 ++++++++++ include/bitcoin/node/error.hpp | 3 + include/bitcoin/node/full_node.hpp | 45 +++++- include/bitcoin/node/protocols/protocol.hpp | 6 + .../node/protocols/protocol_block_in.hpp | 8 +- include/bitcoin/node/sessions/session.hpp | 7 + src/chasers/block_chaser.cpp | 137 ++++++++++++++++ src/error.cpp | 7 +- src/full_node.cpp | 105 +++++++++++- src/protocols/protocol.cpp | 10 ++ src/protocols/protocol_block_in.cpp | 42 ++++- src/sessions/session.cpp | 12 ++ test/error.cpp | 9 ++ 19 files changed, 569 insertions(+), 87 deletions(-) create mode 100644 include/bitcoin/node/chasers/block_chaser.hpp create mode 100644 src/chasers/block_chaser.cpp diff --git a/Makefile.am b/Makefile.am index 35be41f8..40103fbb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,6 +40,7 @@ src_libbitcoin_node_la_SOURCES = \ src/full_node.cpp \ src/parser.cpp \ src/settings.cpp \ + src/chasers/block_chaser.cpp \ src/protocols/protocol.cpp \ src/protocols/protocol_block_in.cpp \ src/protocols/protocol_block_out.cpp \ @@ -104,6 +105,10 @@ include_bitcoin_node_HEADERS = \ include/bitcoin/node/settings.hpp \ include/bitcoin/node/version.hpp +include_bitcoin_node_chasersdir = ${includedir}/bitcoin/node/chasers +include_bitcoin_node_chasers_HEADERS = \ + include/bitcoin/node/chasers/block_chaser.hpp + include_bitcoin_node_protocolsdir = ${includedir}/bitcoin/node/protocols include_bitcoin_node_protocols_HEADERS = \ include/bitcoin/node/protocols/mixin.hpp \ diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt index 3db37f93..a9348aec 100644 --- a/builds/cmake/CMakeLists.txt +++ b/builds/cmake/CMakeLists.txt @@ -250,6 +250,7 @@ add_library( ${CANONICAL_LIB_NAME} "../../src/full_node.cpp" "../../src/parser.cpp" "../../src/settings.cpp" + "../../src/chasers/block_chaser.cpp" "../../src/protocols/protocol.cpp" "../../src/protocols/protocol_block_in.cpp" "../../src/protocols/protocol_block_out.cpp" diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj index 0dd48cb6..6bceb448 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj @@ -73,6 +73,7 @@ + @@ -91,6 +92,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters index 7ddcf26e..c7bfe30a 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters @@ -8,34 +8,43 @@ - {5FFB5F52-0772-4404-0000-000000000003} + {5FFB5F52-0772-4404-0000-000000000004} - {5FFB5F52-0772-4404-0000-000000000004} + {5FFB5F52-0772-4404-0000-000000000005} - {5FFB5F52-0772-4404-0000-000000000005} + {5FFB5F52-0772-4404-0000-000000000006} + + + {5FFB5F52-0772-4404-0000-000000000007} - {5FFB5F52-0772-4404-0000-000000000006} + {5FFB5F52-0772-4404-0000-000000000008} - {5FFB5F52-0772-4404-0000-000000000007} + {5FFB5F52-0772-4404-0000-000000000009} - {5FFB5F52-0772-4404-0000-000000000008} + {5FFB5F52-0772-4404-0000-00000000000A} {5FFB5F52-0772-4404-0000-000000000000} - + {5FFB5F52-0772-4404-0000-000000000001} - + {5FFB5F52-0772-4404-0000-000000000002} + + {5FFB5F52-0772-4404-0000-000000000003} + + + src\chasers + src @@ -86,6 +95,9 @@ include\bitcoin + + include\bitcoin\node\chasers + include\bitcoin\node diff --git a/console/executor.cpp b/console/executor.cpp index 26b23b91..f41ddd41 100644 --- a/console/executor.cpp +++ b/console/executor.cpp @@ -665,7 +665,7 @@ void executor::read_test() const using namespace database; constexpr auto frequency = 100'000u; const auto start = unix_time(); - auto tx = 792'854'831_size; + auto tx = 664'400'000_size; // Read all data except genesis (ie. for validation). while (!cancel_ && (++tx < query_.tx_records())) @@ -918,11 +918,11 @@ void executor::read_test() const ////} //// -// arbitrary testing (non-const). -void executor::write_test() -{ - console("No write test implemented."); -} +////// arbitrary testing (non-const). +////void executor::write_test() +////{ +//// console("No write test implemented."); +////} ////void executor::write_test() ////{ @@ -938,6 +938,12 @@ void executor::write_test() //// // Assumes height is header link. //// const header_link link{ possible_narrow_cast(height) }; //// +//// if (!query_.push_confirmed(link)) +//// { +//// console("!query_.push_confirmed(link)"); +//// return; +//// } +//// //// if (!query_.push_candidate(link)) //// { //// console("!query_.push_candidate(link)"); @@ -956,71 +962,72 @@ void executor::write_test() //// height % (fine_clock::now() - start1).count()); ////} -////void executor::write_test() -////{ -//// using namespace database; -//// ////constexpr uint64_t fees = 99; -//// constexpr auto frequency = 10'000; -//// const auto start = unix_time(); -//// code ec{}; -//// -//// console(BN_OPERATION_INTERRUPT); -//// -//// auto height = zero;//// query_.get_top_confirmed(); -//// while (!cancel_ && (++height < query_.header_records())) -//// { -//// // Assumes height is header link. -//// const header_link link{ possible_narrow_cast(height) }; -//// -//// if (!query_.set_strong(link)) -//// { -//// // total sequential chain cost: 18.7 min (now 6.6). -//// console("Failure: set_strong"); -//// break; -//// } -//// else if ((ec = query_.block_confirmable(link))) -//// { -//// // must set_strong before each (no push, verifies non-use). -//// console(format("Failure: block_confirmable, %1%") % ec.message()); -//// break; -//// } -//// ////if (!query_.set_txs_connected(link)) -//// ////{ -//// //// // total sequential chain cost: 21 min. -//// //// console("Failure: set_txs_connected"); -//// //// break; -//// ////} -//// ////if (!query_.set_block_confirmable(link, fees)) -//// ////{ -//// //// // total chain cost: 1 sec. -//// //// console("Failure: set_block_confirmable"); -//// //// break; -//// //// break; -//// ////} -//// ////else if (!query_.push_candidate(link)) -//// ////{ -//// //// // total chain cost: 1 sec. -//// //// console("Failure: push_candidate"); -//// //// break; -//// ////} -//// ////else if (!query_.push_confirmed(link)) -//// ////{ -//// //// // total chain cost: 1 sec. -//// //// console("Failure: push_confirmed"); -//// //// break; -//// ////} -//// -//// if (is_zero(height % frequency)) -//// console(format("block" BN_WRITE_ROW) % -//// height % (unix_time() - start)); -//// } -//// -//// if (cancel_) -//// console(BN_OPERATION_CANCELED); -//// -//// console(format("block" BN_WRITE_ROW) % -//// height % (unix_time() - start)); -////} +void executor::write_test() +{ + using namespace database; + ////constexpr uint64_t fees = 99; + constexpr auto frequency = 10'000; + const auto start = unix_time(); + code ec{}; + + console(BN_OPERATION_INTERRUPT); + + auto height = zero;//// query_.get_top_confirmed(); + const auto records = query_.header_records(); + while (!cancel_ && (++height < records)) + { + // Assumes height is header link. + const header_link link{ possible_narrow_cast(height) }; + + if (!query_.set_strong(link)) + { + // total sequential chain cost: 18.7 min (now 6.6). + console("Failure: set_strong"); + break; + } + else if ((ec = query_.block_confirmable(link))) + { + // must set_strong before each (no push, verifies non-use). + console(format("Failure: block_confirmable, %1%") % ec.message()); + break; + } + ////if (!query_.set_txs_connected(link)) + ////{ + //// // total sequential chain cost: 21 min. + //// console("Failure: set_txs_connected"); + //// break; + ////} + ////if (!query_.set_block_confirmable(link, fees)) + ////{ + //// // total chain cost: 1 sec. + //// console("Failure: set_block_confirmable"); + //// break; + //// break; + ////} + ////else if (!query_.push_candidate(link)) + ////{ + //// // total chain cost: 1 sec. + //// console("Failure: push_candidate"); + //// break; + ////} + ////else if (!query_.push_confirmed(link)) + ////{ + //// // total chain cost: 1 sec. + //// console("Failure: push_confirmed"); + //// break; + ////} + + if (is_zero(height % frequency)) + console(format("block" BN_WRITE_ROW) % + height % (unix_time() - start)); + } + + if (cancel_) + console(BN_OPERATION_CANCELED); + + console(format("block" BN_WRITE_ROW) % + height % (unix_time() - start)); +} ////void executor::write_test() ////{ diff --git a/include/bitcoin/node.hpp b/include/bitcoin/node.hpp index b0e0b24a..5913ff37 100644 --- a/include/bitcoin/node.hpp +++ b/include/bitcoin/node.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/include/bitcoin/node/chasers/block_chaser.hpp b/include/bitcoin/node/chasers/block_chaser.hpp new file mode 100644 index 00000000..6d468538 --- /dev/null +++ b/include/bitcoin/node/chasers/block_chaser.hpp @@ -0,0 +1,79 @@ +/** + * 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_BLOCK_CHASER_HPP +#define LIBBITCOIN_NODE_CHASERS_BLOCK_CHASER_HPP + +#include +#include + +namespace libbitcoin { +namespace node { + +class full_node; + +/// Chase down blocks for the candidate header chain. +/// Notify subscribers with gap closed event. +class BCN_API block_chaser + : public network::reporter, protected network::tracker +{ +public: + typedef uint64_t object_key; + typedef network::desubscriber subscriber; + typedef subscriber::handler notifier; + DELETE_COPY_MOVE(block_chaser); + + /// Construct an instance. + /// ----------------------------------------------------------------------- + block_chaser(full_node& node) NOEXCEPT; + ~block_chaser() NOEXCEPT; + + /// Start/stop. + /// ----------------------------------------------------------------------- + void start(network::result_handler&& handler) NOEXCEPT; + void stop() NOEXCEPT; + + /// Subscriptions. + /// ----------------------------------------------------------------------- + object_key subscribe(notifier&& handler) NOEXCEPT; + bool notify(object_key key) NOEXCEPT; + + /// Properties. + /// ----------------------------------------------------------------------- + bool stopped() const NOEXCEPT; + bool stranded() const NOEXCEPT; + +private: + object_key create_key() NOEXCEPT; + void do_stop() NOEXCEPT; + + // These are thread safe (mostly). + full_node& node_; + network::asio::strand strand_; + std::atomic_bool stopped_{ true }; + + // These are not thread safe. + object_key keys_{}; + subscriber subscriber_; + network::deadline::ptr timer_; +}; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/error.hpp b/include/bitcoin/node/error.hpp index 7a3d38b9..9af40943 100644 --- a/include/bitcoin/node/error.hpp +++ b/include/bitcoin/node/error.hpp @@ -42,6 +42,9 @@ enum error_t : uint8_t // database store_uninitialized, + // network + slow_channel, + // blockchain orphan_block, insufficient_work, diff --git a/include/bitcoin/node/full_node.hpp b/include/bitcoin/node/full_node.hpp index 19c04656..e72fb68e 100644 --- a/include/bitcoin/node/full_node.hpp +++ b/include/bitcoin/node/full_node.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -32,19 +33,44 @@ class BCN_API full_node : public network::p2p { public: + typedef std::shared_ptr ptr; typedef database::store store; typedef database::query query; - typedef std::shared_ptr ptr; + + // TODO: set arguments. + typedef network::desubscriber poll_subscriber; + typedef poll_subscriber::handler poll_notifier; + typedef poll_subscriber::completer poll_completer; + + /// Constructors. + /// ----------------------------------------------------------------------- /// Construct the node. full_node(query& query, const configuration& configuration, const network::logger& log) NOEXCEPT; + /// Sequences. + /// ----------------------------------------------------------------------- + /// Start the node (seed and manual services). void start(network::result_handler&& handler) NOEXCEPT override; /// Run the node (inbound and outbound services). - void run(network::result_handler&& handler) NOEXCEPT override; + ////void run(network::result_handler&& handler) NOEXCEPT override; + + /// Subscriptions. + /// ----------------------------------------------------------------------- + + /// Subscribe to performance polling. + /// A call after close invokes handlers with error::subscriber_stopped. + virtual void subscribe_poll(object_key key, + poll_notifier&& handler) NOEXCEPT; + + /// Unsubscribe by subscription key, error::desubscribed passed to handler. + virtual void unsubscribe_poll(object_key key) NOEXCEPT; + + /// Properties. + /// ----------------------------------------------------------------------- // Configuration settings for all libraries. const configuration& config() const NOEXCEPT; @@ -53,14 +79,29 @@ class BCN_API full_node query& archive() const NOEXCEPT; protected: + /// Session attachments. network::session_manual::ptr attach_manual_session() NOEXCEPT override; network::session_inbound::ptr attach_inbound_session() NOEXCEPT override; network::session_outbound::ptr attach_outbound_session() NOEXCEPT override; + /// Override do_close to start/stop poll timer. + void do_run(const network::result_handler& handler) NOEXCEPT override; + void do_close() NOEXCEPT override; + private: + void poll(const code& ec) NOEXCEPT; + + void do_unsubscribe_poll(object_key key) NOEXCEPT; + void do_subscribe_poll(object_key key, + const poll_notifier& handler) NOEXCEPT; + // These are thread safe. const configuration& config_; query& query_; + + // These are protected by strand. + poll_subscriber poll_subscriber_; + network::deadline::ptr poll_timer_; }; } // namespace node diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index e67e34d0..593169de 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -43,6 +43,12 @@ class BCN_API protocol { } + /// Subscribe to performance polling. + void subscribe_poll(full_node::poll_notifier&& handler) const NOEXCEPT; + + /// Unsubscribe from performance polling. + void unsubscribe_poll() const 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 09cd3643..96d0f37a 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -19,6 +19,7 @@ #ifndef LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_IN_HPP #define LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_IN_HPP +#include #include #include #include @@ -45,8 +46,9 @@ class BCN_API protocol_block_in { } - /// Start protocol (strand required). + /// Start/stop protocol (strand required). void start() NOEXCEPT override; + void stopping(const code& ec) NOEXCEPT override; protected: struct track @@ -67,6 +69,9 @@ class BCN_API protocol_block_in const network::messages::block::cptr& message, const track_ptr& tracker) NOEXCEPT; + /// Handle performance poll notification. + virtual bool handle_poll(const code& ec, size_t) NOEXCEPT; + protected: /// Invoked when initial blocks sync is current. virtual void current() NOEXCEPT; @@ -83,6 +88,7 @@ class BCN_API protocol_block_in // Thread safe. const network::messages::inventory::type_id block_type_; + std::atomic bytes_{ max_size_t }; // Protected by strand. uint32_t start_{}; diff --git a/include/bitcoin/node/sessions/session.hpp b/include/bitcoin/node/sessions/session.hpp index e35902c6..1b535533 100644 --- a/include/bitcoin/node/sessions/session.hpp +++ b/include/bitcoin/node/sessions/session.hpp @@ -30,6 +30,13 @@ namespace node { class BCN_API session { public: + /// Subscribe to performance polling. + void subscribe_poll(uint64_t key, + full_node::poll_notifier&& handler) const NOEXCEPT; + + /// Unsubscribe from performance polling. + void unsubscribe_poll(uint64_t key) const NOEXCEPT; + /// Configuration settings for all libraries. const configuration& config() const NOEXCEPT; diff --git a/src/chasers/block_chaser.cpp b/src/chasers/block_chaser.cpp new file mode 100644 index 00000000..d498ef23 --- /dev/null +++ b/src/chasers/block_chaser.cpp @@ -0,0 +1,137 @@ +/** + * 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 + +#include +#include +#include + +namespace libbitcoin { +namespace node { + +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + +// TODO: replace channel_heartbeat. +block_chaser::block_chaser(full_node& node) NOEXCEPT + : node_(node), + strand_(node.service().get_executor()), + subscriber_(strand_), + timer_(std::make_shared(node.log, strand_, + node.network_settings().channel_heartbeat())), + reporter(node.log), + tracker(node.log) +{ +} + +block_chaser::~block_chaser() NOEXCEPT +{ + BC_ASSERT_MSG(stopped(), "The block chaser was not stopped."); + if (!stopped()) { LOGF("~block_chaser is not stopped."); } +} + +void block_chaser::start(network::result_handler&& handler) NOEXCEPT +{ + if (!stopped()) + { + handler(network::error::operation_failed); + return; + } + + timer_->start([this](const code& ec) NOEXCEPT + { + BC_ASSERT_MSG(stranded(), "strand"); + + if (stopped()) + return; + + if (ec) + { + LOGF("Chaser timer fail, " << ec.message()); + stop(); + return; + } + + // TODO: collect performance. + ////stop(network::error::channel_expired); + }); + + stopped_.store(false); + handler(network::error::success); +} + +void block_chaser::stop() NOEXCEPT +{ + stopped_.store(true); + + // The block_chaser can be deleted once threadpool joins after this call. + boost::asio::post(strand_, + std::bind(&block_chaser::do_stop, this)); +} + +block_chaser::object_key block_chaser::subscribe(notifier&& handler) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + const auto key = create_key(); + subscriber_.subscribe(std::move(handler), key); + return key; +} + +// TODO: closing channel notifies itself to desubscribe. +bool block_chaser::notify(object_key key) NOEXCEPT +{ + return subscriber_.notify_one(key, network::error::success); +} + +bool block_chaser::stopped() const NOEXCEPT +{ + return stopped_.load(); +} + +bool block_chaser::stranded() const NOEXCEPT +{ + return strand_.running_in_this_thread(); +} + +// private +block_chaser::object_key block_chaser::create_key() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + if (is_zero(++keys_)) + { + BC_ASSERT_MSG(false, "overflow"); + LOGF("Chaser object overflow."); + } + + return keys_; +} + +// private +void block_chaser::do_stop() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + timer_->stop(); + subscriber_.stop(network::error::service_stopped); +} + +BC_POP_WARNING() + +} // namespace database +} // namespace libbitcoin diff --git a/src/error.cpp b/src/error.cpp index e1c5bb86..a0ecada8 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -29,9 +29,14 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) // general { success, "success" }, { unknown, "unknown error" }, + + // database { store_uninitialized, "store not initialized" }, - // blocks + // network + { slow_channel, "slow channel" }, + + // blockchain { orphan_block, "orphan block" }, { insufficient_work, "insufficient work" }, { duplicate_block, "duplicate block" } diff --git a/src/full_node.cpp b/src/full_node.cpp index ac9216f1..344d5305 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -26,16 +27,26 @@ namespace libbitcoin { namespace node { +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + using namespace network; +using namespace std::placeholders; +// TODO: replace channel_heartbeat. full_node::full_node(query& query, const configuration& configuration, const logger& log) NOEXCEPT : p2p(configuration.network, log), config_(configuration), - query_(query) + query_(query), + poll_subscriber_(strand()), + poll_timer_(std::make_shared(log, strand(), + configuration.network.channel_heartbeat())) { } +// Sequences. +// ---------------------------------------------------------------------------- + void full_node::start(result_handler&& handler) NOEXCEPT { if (!query_.is_initialized()) @@ -47,11 +58,94 @@ void full_node::start(result_handler&& handler) NOEXCEPT p2p::start(std::move(handler)); } -void full_node::run(result_handler&& handler) NOEXCEPT +////void full_node::run(result_handler&& handler) NOEXCEPT +////{ +//// p2p::run(std::move(handler)); +////} + +void full_node::do_run(const result_handler& handler) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "timer"); + + if (closed()) + { + handler(network::error::service_stopped); + return; + } + + poll_timer_->start(std::bind(&full_node::poll, this, _1)); + p2p::do_run(handler); +} + +void full_node::poll(const code& ec) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "subscriber"); + + if (closed() || ec == network::error::operation_canceled) + return; + + if (ec) + { + LOGF("Poll timer error, " << ec.message()); + return; + } + + // TODO: get each channel bytes. + poll_subscriber_.notify(error::success, 42_size); + + // TODO: stop slow channel(s). + object_key key{}; + poll_subscriber_.notify_one(key, error::slow_channel, {}); +} + +void full_node::do_close() NOEXCEPT { - p2p::run(std::move(handler)); + BC_ASSERT_MSG(stranded(), "timer"); + poll_timer_->stop(); + p2p::do_close(); } +// Subscriptions. +// ---------------------------------------------------------------------------- + +void full_node::subscribe_poll(object_key key, + poll_notifier&& handler) NOEXCEPT +{ + // Public methods can complete on caller thread. + if (closed()) + { + handler(network::error::service_stopped, {}); + return; + } + + boost::asio::post(strand(), + std::bind(&full_node::do_subscribe_poll, + this, key, std::move(handler))); +} + +// private +void full_node::do_subscribe_poll(object_key key, + const poll_notifier& handler) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + poll_subscriber_.subscribe(move_copy(handler), key); +} + +void full_node::unsubscribe_poll(object_key key) NOEXCEPT +{ + boost::asio::post(strand(), + std::bind(&full_node::do_unsubscribe_poll, this, key)); +} + +void full_node::do_unsubscribe_poll(object_key key) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + poll_subscriber_.notify_one(key, network::error::desubscribed, {}); +} + +// Properties. +// ---------------------------------------------------------------------------- + full_node::query& full_node::archive() const NOEXCEPT { return query_; @@ -62,6 +156,9 @@ const configuration& full_node::config() const NOEXCEPT return config_; } +// Session attachments. +// ---------------------------------------------------------------------------- + session_manual::ptr full_node::attach_manual_session() NOEXCEPT { return p2p::attach>(*this); @@ -77,5 +174,7 @@ session_outbound::ptr full_node::attach_outbound_session() NOEXCEPT return p2p::attach>(*this); } +BC_POP_WARNING() + } // namespace node } // namespace libbitcoin diff --git a/src/protocols/protocol.cpp b/src/protocols/protocol.cpp index 2768010e..484b2e1d 100644 --- a/src/protocols/protocol.cpp +++ b/src/protocols/protocol.cpp @@ -26,6 +26,16 @@ namespace libbitcoin { namespace node { +void protocol::subscribe_poll(full_node::poll_notifier&& handler) const NOEXCEPT +{ + session_.subscribe_poll(identifier(), std::move(handler)); +} + +void protocol::unsubscribe_poll() const NOEXCEPT +{ + session_.unsubscribe_poll(identifier()); +} + const configuration& protocol::config() const NOEXCEPT { return session_.config(); diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index 9b2c8936..e5cac475 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -46,7 +47,7 @@ BC_PUSH_WARNING(NO_NEW_OR_DELETE) BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED) BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR) -// Start. +// Start/stop. // ---------------------------------------------------------------------------- void protocol_block_in::start() NOEXCEPT @@ -65,12 +66,49 @@ void protocol_block_in::start() NOEXCEPT return; } + // Subscription completion is lazy, but will complete before unsubscribe. + subscribe_poll(BIND2(handle_poll, _1, _2)); + // There is one persistent common inventory subscription. SUBSCRIBE_CHANNEL2(inventory, handle_receive_inventory, _1, _2); SEND1(create_get_inventory(), handle_send, _1); protocol::start(); } +void protocol_block_in::stopping(const code& ec) NOEXCEPT +{ + unsubscribe_poll(); + protocol::stopping(ec); +} + +// Performance polling. +// ---------------------------------------------------------------------------- + +////bool protocol_block_in::get_rate(size_t& bytes) NOEXCEPT +////{ +//// const auto cold = (bytes_ == max_size_t); +//// bytes = bytes_.exchange(zero); +//// return !cold; +////} + +bool protocol_block_in::handle_poll(const code& ec, size_t) NOEXCEPT +{ + if (ec == network::error::desubscribed || + ec == network::error::service_stopped) + return false; + + if (ec) + { + LOGF("Handle poll error, " << ec.message()); + return false; + } + + // TODO: return bytes or stop channel. + + // This is running in the network (not channel) strand. + return true; +} + // Inbound (blocks). // ---------------------------------------------------------------------------- @@ -145,6 +183,8 @@ bool protocol_block_in::handle_receive_block(const code& ec, if (stopped(ec)) return false; + bytes_ += message->cached_size; + if (tracker->hashes.empty()) { LOGF("Exhausted block tracker."); diff --git a/src/sessions/session.cpp b/src/sessions/session.cpp index 909c9854..4ec867cf 100644 --- a/src/sessions/session.cpp +++ b/src/sessions/session.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -30,6 +31,17 @@ session::session(full_node& node) NOEXCEPT { } +void session::subscribe_poll(uint64_t key, + full_node::poll_notifier&& handler) const NOEXCEPT +{ + node_.subscribe_poll(key, std::move(handler)); +} + +void session::unsubscribe_poll(uint64_t key) const NOEXCEPT +{ + node_.unsubscribe_poll(key); +} + const configuration& session::config() const NOEXCEPT { return node_.config(); diff --git a/test/error.cpp b/test/error.cpp index 1919f4d4..930f83ba 100644 --- a/test/error.cpp +++ b/test/error.cpp @@ -50,6 +50,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__store_uninitialized__true_exected_message) BOOST_REQUIRE_EQUAL(ec.message(), "store not initialized"); } +BOOST_AUTO_TEST_CASE(error_t__code__slow_channel__true_exected_message) +{ + constexpr auto value = error::slow_channel; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "slow channel"); +} + BOOST_AUTO_TEST_CASE(error_t__code__orphan_block__true_exected_message) { constexpr auto value = error::orphan_block; From afeb32e88bd8b9149d0904bc17a43171e8665591 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Tue, 30 Jan 2024 15:11:58 -0500 Subject: [PATCH 11/27] Comments, move block protocol byte accumulator. --- include/bitcoin/node/sessions/session.hpp | 2 +- src/full_node.cpp | 1 + src/protocols/protocol_block_in.cpp | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/bitcoin/node/sessions/session.hpp b/include/bitcoin/node/sessions/session.hpp index 1b535533..2118fddb 100644 --- a/include/bitcoin/node/sessions/session.hpp +++ b/include/bitcoin/node/sessions/session.hpp @@ -26,7 +26,7 @@ namespace libbitcoin { namespace node { -/// Abstract base for node sessions. +/// Concrete base class for node sessions. class BCN_API session { public: diff --git a/src/full_node.cpp b/src/full_node.cpp index 344d5305..9d7b7f66 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -58,6 +58,7 @@ void full_node::start(result_handler&& handler) NOEXCEPT p2p::start(std::move(handler)); } +// Base (p2p) invokes do_run() override. ////void full_node::run(result_handler&& handler) NOEXCEPT ////{ //// p2p::run(std::move(handler)); diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index e5cac475..0f760a37 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -84,6 +84,7 @@ void protocol_block_in::stopping(const code& ec) NOEXCEPT // Performance polling. // ---------------------------------------------------------------------------- +// Cold until first poll so that will have full interval. ////bool protocol_block_in::get_rate(size_t& bytes) NOEXCEPT ////{ //// const auto cold = (bytes_ == max_size_t); @@ -183,8 +184,6 @@ bool protocol_block_in::handle_receive_block(const code& ec, if (stopped(ec)) return false; - bytes_ += message->cached_size; - if (tracker->hashes.empty()) { LOGF("Exhausted block tracker."); @@ -311,6 +310,9 @@ bool protocol_block_in::handle_receive_block(const code& ec, LOGP("Block [" << encode_hash(message->block_ptr->hash()) << "] from [" << authority() << "]."); + // Accumulate byte count. + bytes_ += message->cached_size; + // Order is reversed, so next is at back. tracker->hashes.pop_back(); From b0b4526ad303084a77ed466a744ccd127fa6514f Mon Sep 17 00:00:00 2001 From: evoskuil Date: Tue, 30 Jan 2024 18:25:43 -0500 Subject: [PATCH 12/27] Initial implementation of block download performance counting. --- include/bitcoin/node/full_node.hpp | 23 --- include/bitcoin/node/protocols/mixin.hpp | 4 +- include/bitcoin/node/protocols/protocol.hpp | 7 +- .../node/protocols/protocol_block_in.hpp | 19 +- include/bitcoin/node/sessions/session.hpp | 7 - src/full_node.cpp | 66 +----- src/protocols/protocol.cpp | 9 +- src/protocols/protocol_block_in.cpp | 194 +++++++++--------- src/sessions/session.cpp | 12 -- 9 files changed, 117 insertions(+), 224 deletions(-) diff --git a/include/bitcoin/node/full_node.hpp b/include/bitcoin/node/full_node.hpp index e72fb68e..e1a7ad12 100644 --- a/include/bitcoin/node/full_node.hpp +++ b/include/bitcoin/node/full_node.hpp @@ -39,8 +39,6 @@ class BCN_API full_node // TODO: set arguments. typedef network::desubscriber poll_subscriber; - typedef poll_subscriber::handler poll_notifier; - typedef poll_subscriber::completer poll_completer; /// Constructors. /// ----------------------------------------------------------------------- @@ -58,17 +56,6 @@ class BCN_API full_node /// Run the node (inbound and outbound services). ////void run(network::result_handler&& handler) NOEXCEPT override; - /// Subscriptions. - /// ----------------------------------------------------------------------- - - /// Subscribe to performance polling. - /// A call after close invokes handlers with error::subscriber_stopped. - virtual void subscribe_poll(object_key key, - poll_notifier&& handler) NOEXCEPT; - - /// Unsubscribe by subscription key, error::desubscribed passed to handler. - virtual void unsubscribe_poll(object_key key) NOEXCEPT; - /// Properties. /// ----------------------------------------------------------------------- @@ -89,19 +76,9 @@ class BCN_API full_node void do_close() NOEXCEPT override; private: - void poll(const code& ec) NOEXCEPT; - - void do_unsubscribe_poll(object_key key) NOEXCEPT; - void do_subscribe_poll(object_key key, - const poll_notifier& handler) NOEXCEPT; - // These are thread safe. const configuration& config_; query& query_; - - // These are protected by strand. - poll_subscriber poll_subscriber_; - network::deadline::ptr poll_timer_; }; } // namespace node diff --git a/include/bitcoin/node/protocols/mixin.hpp b/include/bitcoin/node/protocols/mixin.hpp index dbdbe74a..5172c72f 100644 --- a/include/bitcoin/node/protocols/mixin.hpp +++ b/include/bitcoin/node/protocols/mixin.hpp @@ -68,6 +68,7 @@ class mixin Session::attach_protocols(channel); auto& self = *this; + constexpr auto performance = true; ////const auto version = channel->negotiated_version(); //// ////if (version >= network::messages::level::bip130) @@ -81,7 +82,8 @@ class mixin //// channel->attach(self)->start(); ////} - channel->attach(self)->start(); + // TODO: limit this to session_outbound through derivation. + channel->attach(self, performance)->start(); ////channel->attach(self)->start(); ////channel->attach(self)->start(); ////channel->attach(self)->start(); diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index 593169de..f619ef92 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -43,11 +43,8 @@ class BCN_API protocol { } - /// Subscribe to performance polling. - void subscribe_poll(full_node::poll_notifier&& handler) const NOEXCEPT; - - /// Unsubscribe from performance polling. - void unsubscribe_poll() const NOEXCEPT; + /// Report performance, false directs self-terminate. + bool performance(size_t bytes) const 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 96d0f37a..6ab8d957 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -19,7 +19,8 @@ #ifndef LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_IN_HPP #define LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_IN_HPP -#include +#include +#include #include #include #include @@ -38,11 +39,14 @@ class BCN_API protocol_block_in template protocol_block_in(Session& session, - const channel_ptr& channel) NOEXCEPT + const channel_ptr& channel, bool report_performance) NOEXCEPT : node::protocol(session, channel), network::tracker(session.log), + report_performance_(report_performance), block_type_(session.config().network.witness_node() ? - type_id::witness_block : type_id::block) + type_id::witness_block : type_id::block), + performance_timer_(std::make_shared( + session.log, channel->strand(), std::chrono::seconds(10))) { } @@ -69,10 +73,9 @@ class BCN_API protocol_block_in const network::messages::block::cptr& message, const track_ptr& tracker) NOEXCEPT; - /// Handle performance poll notification. - virtual bool handle_poll(const code& ec, size_t) NOEXCEPT; + /// Handle performance timer event. + virtual void handle_performance(const code& ec) NOEXCEPT; -protected: /// Invoked when initial blocks sync is current. virtual void current() NOEXCEPT; @@ -87,12 +90,14 @@ class BCN_API protocol_block_in const network::messages::inventory& message) const NOEXCEPT; // Thread safe. + const bool report_performance_; const network::messages::inventory::type_id block_type_; - std::atomic bytes_{ max_size_t }; // Protected by strand. uint32_t start_{}; + size_t bytes_{ zero }; system::chain::chain_state::ptr state_{}; + network::deadline::ptr performance_timer_; }; } // namespace node diff --git a/include/bitcoin/node/sessions/session.hpp b/include/bitcoin/node/sessions/session.hpp index 2118fddb..92eeeb53 100644 --- a/include/bitcoin/node/sessions/session.hpp +++ b/include/bitcoin/node/sessions/session.hpp @@ -30,13 +30,6 @@ namespace node { class BCN_API session { public: - /// Subscribe to performance polling. - void subscribe_poll(uint64_t key, - full_node::poll_notifier&& handler) const NOEXCEPT; - - /// Unsubscribe from performance polling. - void unsubscribe_poll(uint64_t key) const NOEXCEPT; - /// Configuration settings for all libraries. const configuration& config() const NOEXCEPT; diff --git a/src/full_node.cpp b/src/full_node.cpp index 9d7b7f66..a5e10b02 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -37,10 +37,7 @@ full_node::full_node(query& query, const configuration& configuration, const logger& log) NOEXCEPT : p2p(configuration.network, log), config_(configuration), - query_(query), - poll_subscriber_(strand()), - poll_timer_(std::make_shared(log, strand(), - configuration.network.channel_heartbeat())) + query_(query) { } @@ -74,76 +71,15 @@ void full_node::do_run(const result_handler& handler) NOEXCEPT return; } - poll_timer_->start(std::bind(&full_node::poll, this, _1)); p2p::do_run(handler); } -void full_node::poll(const code& ec) NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "subscriber"); - - if (closed() || ec == network::error::operation_canceled) - return; - - if (ec) - { - LOGF("Poll timer error, " << ec.message()); - return; - } - - // TODO: get each channel bytes. - poll_subscriber_.notify(error::success, 42_size); - - // TODO: stop slow channel(s). - object_key key{}; - poll_subscriber_.notify_one(key, error::slow_channel, {}); -} - void full_node::do_close() NOEXCEPT { BC_ASSERT_MSG(stranded(), "timer"); - poll_timer_->stop(); p2p::do_close(); } -// Subscriptions. -// ---------------------------------------------------------------------------- - -void full_node::subscribe_poll(object_key key, - poll_notifier&& handler) NOEXCEPT -{ - // Public methods can complete on caller thread. - if (closed()) - { - handler(network::error::service_stopped, {}); - return; - } - - boost::asio::post(strand(), - std::bind(&full_node::do_subscribe_poll, - this, key, std::move(handler))); -} - -// private -void full_node::do_subscribe_poll(object_key key, - const poll_notifier& handler) NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - poll_subscriber_.subscribe(move_copy(handler), key); -} - -void full_node::unsubscribe_poll(object_key key) NOEXCEPT -{ - boost::asio::post(strand(), - std::bind(&full_node::do_unsubscribe_poll, this, key)); -} - -void full_node::do_unsubscribe_poll(object_key key) NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - poll_subscriber_.notify_one(key, network::error::desubscribed, {}); -} - // Properties. // ---------------------------------------------------------------------------- diff --git a/src/protocols/protocol.cpp b/src/protocols/protocol.cpp index 484b2e1d..c20f1d99 100644 --- a/src/protocols/protocol.cpp +++ b/src/protocols/protocol.cpp @@ -26,14 +26,9 @@ namespace libbitcoin { namespace node { -void protocol::subscribe_poll(full_node::poll_notifier&& handler) const NOEXCEPT +bool protocol::performance(size_t) const NOEXCEPT { - session_.subscribe_poll(identifier(), std::move(handler)); -} - -void protocol::unsubscribe_poll() const NOEXCEPT -{ - session_.unsubscribe_poll(identifier()); + return true; } const configuration& protocol::config() const NOEXCEPT diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index 0f760a37..3b616193 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -24,6 +24,7 @@ #include #include #include +#include // The block protocol is partially obsoleted by the headers protocol. // Both block and header protocols conflate iterative requests and unsolicited @@ -47,6 +48,33 @@ BC_PUSH_WARNING(NO_NEW_OR_DELETE) BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED) BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR) +// Performance polling. +// ---------------------------------------------------------------------------- + +void protocol_block_in::handle_performance(const code& ec) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "protocol_block_in"); + + if (stopped() || ec == network::error::operation_canceled) + return; + + if (ec) + { + LOGF("Performance timer error, " << ec.message()); + return; + } + + if (!performance(bytes_)) + { + stop(error::slow_channel); + return; + }; + + log.fire(event_block, bytes_); + bytes_ = zero; + performance_timer_->start(BIND1(handle_performance, _1)); +} + // Start/stop. // ---------------------------------------------------------------------------- @@ -66,8 +94,8 @@ void protocol_block_in::start() NOEXCEPT return; } - // Subscription completion is lazy, but will complete before unsubscribe. - subscribe_poll(BIND2(handle_poll, _1, _2)); + if (report_performance_) + performance_timer_->start(BIND1(handle_performance, _1)); // There is one persistent common inventory subscription. SUBSCRIBE_CHANNEL2(inventory, handle_receive_inventory, _1, _2); @@ -77,39 +105,11 @@ void protocol_block_in::start() NOEXCEPT void protocol_block_in::stopping(const code& ec) NOEXCEPT { - unsubscribe_poll(); + BC_ASSERT_MSG(stranded(), "protocol_block_in"); + performance_timer_->stop(); protocol::stopping(ec); } -// Performance polling. -// ---------------------------------------------------------------------------- - -// Cold until first poll so that will have full interval. -////bool protocol_block_in::get_rate(size_t& bytes) NOEXCEPT -////{ -//// const auto cold = (bytes_ == max_size_t); -//// bytes = bytes_.exchange(zero); -//// return !cold; -////} - -bool protocol_block_in::handle_poll(const code& ec, size_t) NOEXCEPT -{ - if (ec == network::error::desubscribed || - ec == network::error::service_stopped) - return false; - - if (ec) - { - LOGF("Handle poll error, " << ec.message()); - return false; - } - - // TODO: return bytes or stop channel. - - // This is running in the network (not channel) strand. - return true; -} - // Inbound (blocks). // ---------------------------------------------------------------------------- @@ -235,80 +235,80 @@ bool protocol_block_in::handle_receive_block(const code& ec, state_.reset(new chain::chain_state(*state_, block.header(), coin)); BC_POP_WARNING() - auto& query = archive(); - const auto context = state_->context(); - - // TODO: ensure soft forks activated in chain_state. - //// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); + ////auto& query = archive(); + ////const auto context = state_->context(); + //// + ////// TODO: ensure soft forks activated in chain_state. + //////// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); - const auto link = query.set_link(block, context); - if (link.is_terminal()) - { - // Should only be from missing parent, and that's guarded above. - LOGF("Store block error [" << encode_hash(hash) - << "] from [" << authority() << "]."); - stop(network::error::unknown); - return false; - } - - ////// Block must be archived for populate. - ////if (!query.populate(block)) + ////const auto link = query.set_link(block, context); + ////if (link.is_terminal()) ////{ - //// // Invalid block is archived. - //// LOGR("Invalid block (populate) [" << encode_hash(hash) + //// // Should only be from missing parent, and that's guarded above. + //// LOGF("Store block error [" << encode_hash(hash) //// << "] from [" << authority() << "]."); - //// stop(network::error::protocol_violation); - //// return false; - ////} - - ////error = block.accept(context, coin.subsidy_interval_blocks, - //// coin.initial_subsidy()); - ////if (error) - ////{ - //// // Invalid block is archived. - //// LOGR("Invalid block (accept) [" << encode_hash(hash) - //// << "] from [" << authority() << "] " << error.message()); - //// stop(network::error::protocol_violation); - //// return false; - ////} - - ////error = block.connect(context); - ////if (error) - ////{ - //// // Invalid block is archived. - //// LOGR("Invalid block (connect) [" << encode_hash(hash) - //// << "] from [" << authority() << "] " << error.message()); - //// stop(network::error::protocol_violation); + //// stop(network::error::unknown); //// return false; ////} - ////// If populate, accept, or connect fail this is bypassed and a restart will - ////// initialize state_ at the prior block as top. But this block exists, so - ////// it will be skipped for download. This results in the next being orphaned - ////// following the channel stop/start or any subsequent runs on the store. - ////// This is the job of the confirmation chaser (todo). - ////if (!query.push_confirmed(link)) + ////////// Block must be archived for populate. + ////////if (!query.populate(block)) + ////////{ + //////// // Invalid block is archived. + //////// LOGR("Invalid block (populate) [" << encode_hash(hash) + //////// << "] from [" << authority() << "]."); + //////// stop(network::error::protocol_violation); + //////// return false; + ////////} + + ////////error = block.accept(context, coin.subsidy_interval_blocks, + //////// coin.initial_subsidy()); + ////////if (error) + ////////{ + //////// // Invalid block is archived. + //////// LOGR("Invalid block (accept) [" << encode_hash(hash) + //////// << "] from [" << authority() << "] " << error.message()); + //////// stop(network::error::protocol_violation); + //////// return false; + ////////} + + ////////error = block.connect(context); + ////////if (error) + ////////{ + //////// // Invalid block is archived. + //////// LOGR("Invalid block (connect) [" << encode_hash(hash) + //////// << "] from [" << authority() << "] " << error.message()); + //////// stop(network::error::protocol_violation); + //////// return false; + ////////} + + ////////// If populate, accept, or connect fail this is bypassed and a restart will + ////////// initialize state_ at the prior block as top. But this block exists, so + ////////// it will be skipped for download. This results in the next being orphaned + ////////// following the channel stop/start or any subsequent runs on the store. + ////////// This is the job of the confirmation chaser (todo). + ////////if (!query.push_confirmed(link)) + ////////{ + //////// // Invalid block is archived. + //////// LOGF("Push confirmed error [" << encode_hash(hash) + //////// << "] from [" << authority() << "]."); + //////// stop(network::error::unknown); + //////// return false; + ////////} + + ////// Size will be incorrect with multiple peers or headers protocol. + ////if (is_zero(context.height % 1'000)) ////{ - //// // Invalid block is archived. - //// LOGF("Push confirmed error [" << encode_hash(hash) - //// << "] from [" << authority() << "]."); - //// stop(network::error::unknown); - //// return false; + //// ////reporter::fire(event_block, context.height); + //// ////reporter::fire(event_archive, query.archive_size()); + //// LOGN("BLOCK: " << context.height + //// << " secs: " << (unix_time() - start_) + //// << " txs: " << query.tx_records() + //// << " archive: " << query.archive_size()); ////} - // Size will be incorrect with multiple peers or headers protocol. - if (is_zero(context.height % 1'000)) - { - ////reporter::fire(event_block, context.height); - ////reporter::fire(event_archive, query.archive_size()); - LOGN("BLOCK: " << context.height - << " secs: " << (unix_time() - start_) - << " txs: " << query.tx_records() - << " archive: " << query.archive_size()); - } - - LOGP("Block [" << encode_hash(message->block_ptr->hash()) << "] from [" - << authority() << "]."); + ////LOGP("Block [" << encode_hash(message->block_ptr->hash()) << "] from [" + //// << authority() << "]."); // Accumulate byte count. bytes_ += message->cached_size; diff --git a/src/sessions/session.cpp b/src/sessions/session.cpp index 4ec867cf..909c9854 100644 --- a/src/sessions/session.cpp +++ b/src/sessions/session.cpp @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -31,17 +30,6 @@ session::session(full_node& node) NOEXCEPT { } -void session::subscribe_poll(uint64_t key, - full_node::poll_notifier&& handler) const NOEXCEPT -{ - node_.subscribe_poll(key, std::move(handler)); -} - -void session::unsubscribe_poll(uint64_t key) const NOEXCEPT -{ - node_.unsubscribe_poll(key); -} - const configuration& session::config() const NOEXCEPT { return node_.config(); From f7fc683b8b77669e302f715c10f935380469ead8 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Tue, 30 Jan 2024 18:50:55 -0500 Subject: [PATCH 13/27] Style, comments, delint. --- console/executor.cpp | 2 -- .../bitcoin/node/protocols/protocol_block_in.hpp | 5 +++-- src/protocols/protocol_block_in.cpp | 16 ++++++++-------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/console/executor.cpp b/console/executor.cpp index f41ddd41..86157599 100644 --- a/console/executor.cpp +++ b/console/executor.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -40,7 +39,6 @@ using boost::format; using system::config::printer; using namespace network; using namespace system; -using namespace std::chrono; using namespace std::placeholders; // const executor statics diff --git a/include/bitcoin/node/protocols/protocol_block_in.hpp b/include/bitcoin/node/protocols/protocol_block_in.hpp index 6ab8d957..e0c2f773 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -19,7 +19,6 @@ #ifndef LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_IN_HPP #define LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_IN_HPP -#include #include #include #include @@ -37,6 +36,7 @@ class BCN_API protocol_block_in typedef std::shared_ptr ptr; using type_id = network::messages::inventory::type_id; + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) template protocol_block_in(Session& session, const channel_ptr& channel, bool report_performance) NOEXCEPT @@ -46,9 +46,10 @@ class BCN_API protocol_block_in block_type_(session.config().network.witness_node() ? type_id::witness_block : type_id::block), performance_timer_(std::make_shared( - session.log, channel->strand(), std::chrono::seconds(10))) + session.log, channel->strand(), network::seconds(10))) { } + BC_POP_WARNING() /// Start/stop protocol (strand required). void start() NOEXCEPT override; diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index 3b616193..556bf4b6 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -221,7 +221,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, } } - auto error = block.check(); + const auto error = block.check(); if (error) { LOGR("Invalid block (check) [" << encode_hash(hash) @@ -240,7 +240,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //// ////// TODO: ensure soft forks activated in chain_state. //////// context.forks |= (chain::forks::bip9_bit0_group | chain::forks::bip9_bit1_group); - + //// ////const auto link = query.set_link(block, context); ////if (link.is_terminal()) ////{ @@ -250,7 +250,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //// stop(network::error::unknown); //// return false; ////} - + //// ////////// Block must be archived for populate. ////////if (!query.populate(block)) ////////{ @@ -260,7 +260,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //////// stop(network::error::protocol_violation); //////// return false; ////////} - + //// ////////error = block.accept(context, coin.subsidy_interval_blocks, //////// coin.initial_subsidy()); ////////if (error) @@ -271,7 +271,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //////// stop(network::error::protocol_violation); //////// return false; ////////} - + //// ////////error = block.connect(context); ////////if (error) ////////{ @@ -281,7 +281,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //////// stop(network::error::protocol_violation); //////// return false; ////////} - + //// ////////// If populate, accept, or connect fail this is bypassed and a restart will ////////// initialize state_ at the prior block as top. But this block exists, so ////////// it will be skipped for download. This results in the next being orphaned @@ -295,7 +295,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //////// stop(network::error::unknown); //////// return false; ////////} - + //// ////// Size will be incorrect with multiple peers or headers protocol. ////if (is_zero(context.height % 1'000)) ////{ @@ -306,7 +306,7 @@ bool protocol_block_in::handle_receive_block(const code& ec, //// << " txs: " << query.tx_records() //// << " archive: " << query.archive_size()); ////} - + //// ////LOGP("Block [" << encode_hash(message->block_ptr->hash()) << "] from [" //// << authority() << "]."); From cc6d72357dd1bb03ec488dc6c5fad5faa5462de0 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Tue, 30 Jan 2024 19:05:58 -0500 Subject: [PATCH 14/27] Report rate for outbound session blocks-in protocol only. --- include/bitcoin/node/protocols/mixin.hpp | 34 ++++++++++++++++++++++-- src/full_node.cpp | 6 ++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/include/bitcoin/node/protocols/mixin.hpp b/include/bitcoin/node/protocols/mixin.hpp index 5172c72f..0eb16d40 100644 --- a/include/bitcoin/node/protocols/mixin.hpp +++ b/include/bitcoin/node/protocols/mixin.hpp @@ -68,7 +68,6 @@ class mixin Session::attach_protocols(channel); auto& self = *this; - constexpr auto performance = true; ////const auto version = channel->negotiated_version(); //// ////if (version >= network::messages::level::bip130) @@ -82,7 +81,38 @@ class mixin //// channel->attach(self)->start(); ////} - // TODO: limit this to session_outbound through derivation. + constexpr auto performance = false; + channel->attach(self, performance)->start(); + ////channel->attach(self)->start(); + ////channel->attach(self)->start(); + ////channel->attach(self)->start(); + } +}; + +typedef mixin session_manual; +typedef mixin session_inbound; + +class session_outbound + : public mixin +{ +public: + session_outbound(full_node& node, uint64_t identifier) NOEXCEPT + : mixin(node, identifier) + { + // mixin(node, identifier)... + // Set the current top for version protocol, before handshake. + // Attach and execute appropriate version protocol. + }; + +protected: + void attach_protocols( + const network::channel::ptr& channel) NOEXCEPT override + { + // Attach appropriate alert, reject, ping, and/or address protocols. + network::session_outbound::attach_protocols(channel); + + auto& self = *this; + constexpr auto performance = true; channel->attach(self, performance)->start(); ////channel->attach(self)->start(); ////channel->attach(self)->start(); diff --git a/src/full_node.cpp b/src/full_node.cpp index a5e10b02..6612e814 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -98,17 +98,17 @@ const configuration& full_node::config() const NOEXCEPT session_manual::ptr full_node::attach_manual_session() NOEXCEPT { - return p2p::attach>(*this); + return p2p::attach(*this); } session_inbound::ptr full_node::attach_inbound_session() NOEXCEPT { - return p2p::attach>(*this); + return p2p::attach(*this); } session_outbound::ptr full_node::attach_outbound_session() NOEXCEPT { - return p2p::attach>(*this); + return p2p::attach(*this); } BC_POP_WARNING() From 61529181e173f6cfcf2340f2a1e73539648c3e11 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Tue, 30 Jan 2024 22:09:32 -0500 Subject: [PATCH 15/27] Rafactor to better isolate sessions from protocols. --- Makefile.am | 15 +++-- builds/cmake/CMakeLists.txt | 5 +- .../libbitcoin-node/libbitcoin-node.vcxproj | 13 +++- .../libbitcoin-node.vcxproj.filters | 27 ++++++++- include/bitcoin/node.hpp | 8 ++- include/bitcoin/node/full_node.hpp | 1 - .../node/protocols/{mixin.hpp => attach.hpp} | 41 ++----------- include/bitcoin/node/protocols/protocol.hpp | 6 +- .../node/protocols/protocol_block_in.hpp | 2 +- include/bitcoin/node/protocols/protocols.hpp | 3 +- .../node/{sessions => protocols}/session.hpp | 14 +++-- .../bitcoin/node/sessions/session_inbound.hpp | 33 +++++++++++ .../bitcoin/node/sessions/session_manual.hpp | 33 +++++++++++ .../node/sessions/session_outbound.hpp | 46 +++++++++++++++ include/bitcoin/node/sessions/sessions.hpp | 26 ++++++++ src/full_node.cpp | 2 +- src/protocols/protocol.cpp | 4 +- src/{sessions => protocols}/session.cpp | 7 ++- src/sessions/session_inbound.cpp | 25 ++++++++ src/sessions/session_manual.cpp | 25 ++++++++ src/sessions/session_outbound.cpp | 59 +++++++++++++++++++ 21 files changed, 331 insertions(+), 64 deletions(-) rename include/bitcoin/node/protocols/{mixin.hpp => attach.hpp} (72%) rename include/bitcoin/node/{sessions => protocols}/session.hpp (76%) create mode 100644 include/bitcoin/node/sessions/session_inbound.hpp create mode 100644 include/bitcoin/node/sessions/session_manual.hpp create mode 100644 include/bitcoin/node/sessions/session_outbound.hpp create mode 100644 include/bitcoin/node/sessions/sessions.hpp rename src/{sessions => protocols}/session.cpp (91%) create mode 100644 src/sessions/session_inbound.cpp create mode 100644 src/sessions/session_manual.cpp create mode 100644 src/sessions/session_outbound.cpp diff --git a/Makefile.am b/Makefile.am index 40103fbb..e52e68a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,7 +50,10 @@ src_libbitcoin_node_la_SOURCES = \ src/protocols/protocol_header_out_70012.cpp \ src/protocols/protocol_transaction_in.cpp \ src/protocols/protocol_transaction_out.cpp \ - src/sessions/session.cpp + src/protocols/session.cpp \ + src/sessions/session_inbound.cpp \ + src/sessions/session_manual.cpp \ + src/sessions/session_outbound.cpp # local: test/libbitcoin-node-test #------------------------------------------------------------------------------ @@ -111,7 +114,7 @@ include_bitcoin_node_chasers_HEADERS = \ include_bitcoin_node_protocolsdir = ${includedir}/bitcoin/node/protocols include_bitcoin_node_protocols_HEADERS = \ - include/bitcoin/node/protocols/mixin.hpp \ + include/bitcoin/node/protocols/attach.hpp \ include/bitcoin/node/protocols/protocol.hpp \ include/bitcoin/node/protocols/protocol_block_in.hpp \ include/bitcoin/node/protocols/protocol_block_out.hpp \ @@ -121,11 +124,15 @@ include_bitcoin_node_protocols_HEADERS = \ include/bitcoin/node/protocols/protocol_header_out_70012.hpp \ include/bitcoin/node/protocols/protocol_transaction_in.hpp \ include/bitcoin/node/protocols/protocol_transaction_out.hpp \ - include/bitcoin/node/protocols/protocols.hpp + include/bitcoin/node/protocols/protocols.hpp \ + include/bitcoin/node/protocols/session.hpp include_bitcoin_node_sessionsdir = ${includedir}/bitcoin/node/sessions include_bitcoin_node_sessions_HEADERS = \ - include/bitcoin/node/sessions/session.hpp + include/bitcoin/node/sessions/session_inbound.hpp \ + include/bitcoin/node/sessions/session_manual.hpp \ + include/bitcoin/node/sessions/session_outbound.hpp \ + include/bitcoin/node/sessions/sessions.hpp # files => ${bash_completiondir} #------------------------------------------------------------------------------ diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt index a9348aec..befa95af 100644 --- a/builds/cmake/CMakeLists.txt +++ b/builds/cmake/CMakeLists.txt @@ -260,7 +260,10 @@ add_library( ${CANONICAL_LIB_NAME} "../../src/protocols/protocol_header_out_70012.cpp" "../../src/protocols/protocol_transaction_in.cpp" "../../src/protocols/protocol_transaction_out.cpp" - "../../src/sessions/session.cpp" ) + "../../src/protocols/session.cpp" + "../../src/sessions/session_inbound.cpp" + "../../src/sessions/session_manual.cpp" + "../../src/sessions/session_outbound.cpp" ) # ${CANONICAL_LIB_NAME} project specific include directory normalization for build. #------------------------------------------------------------------------------ diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj index 6bceb448..e7f163a1 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj @@ -87,7 +87,10 @@ - + + + + @@ -98,7 +101,7 @@ - + @@ -109,7 +112,11 @@ - + + + + + diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters index c7bfe30a..13e2cb81 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters @@ -84,7 +84,16 @@ src\protocols - + + src\protocols + + + src\sessions + + + src\sessions + + src\sessions @@ -113,7 +122,7 @@ include\bitcoin\node - + include\bitcoin\node\protocols @@ -146,7 +155,19 @@ include\bitcoin\node\protocols - + + include\bitcoin\node\protocols + + + include\bitcoin\node\sessions + + + include\bitcoin\node\sessions + + + include\bitcoin\node\sessions + + include\bitcoin\node\sessions diff --git a/include/bitcoin/node.hpp b/include/bitcoin/node.hpp index 5913ff37..7ebc8b00 100644 --- a/include/bitcoin/node.hpp +++ b/include/bitcoin/node.hpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -35,6 +35,10 @@ #include #include #include -#include +#include +#include +#include +#include +#include #endif diff --git a/include/bitcoin/node/full_node.hpp b/include/bitcoin/node/full_node.hpp index e1a7ad12..fe175e3a 100644 --- a/include/bitcoin/node/full_node.hpp +++ b/include/bitcoin/node/full_node.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/include/bitcoin/node/protocols/mixin.hpp b/include/bitcoin/node/protocols/attach.hpp similarity index 72% rename from include/bitcoin/node/protocols/mixin.hpp rename to include/bitcoin/node/protocols/attach.hpp index 0eb16d40..12408b0a 100644 --- a/include/bitcoin/node/protocols/mixin.hpp +++ b/include/bitcoin/node/protocols/attach.hpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -32,20 +31,21 @@ #include #include #include +#include namespace libbitcoin { namespace node { -/// Session base class template for protocol attach mixin. +/// Session base class template for protocol attachment. /// node::session does not derive from network::session (siblings). /// This avoids the diamond inheritance problem between network/node. -/// For this reason protocol contructors are templatized on Session. +/// Protocol contructors are templatized on Session, obtaining session. template -class mixin +class attach : public Session, public node::session { public: - mixin(full_node& node, uint64_t identifier) NOEXCEPT + attach(full_node& node, uint64_t identifier) NOEXCEPT : Session(node, identifier), session(node) { }; @@ -89,37 +89,6 @@ class mixin } }; -typedef mixin session_manual; -typedef mixin session_inbound; - -class session_outbound - : public mixin -{ -public: - session_outbound(full_node& node, uint64_t identifier) NOEXCEPT - : mixin(node, identifier) - { - // mixin(node, identifier)... - // Set the current top for version protocol, before handshake. - // Attach and execute appropriate version protocol. - }; - -protected: - void attach_protocols( - const network::channel::ptr& channel) NOEXCEPT override - { - // Attach appropriate alert, reject, ping, and/or address protocols. - network::session_outbound::attach_protocols(channel); - - auto& self = *this; - constexpr auto performance = true; - channel->attach(self, performance)->start(); - ////channel->attach(self)->start(); - ////channel->attach(self)->start(); - ////channel->attach(self)->start(); - } -}; - } // namespace node } // namespace libbitcoin diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index f619ef92..54792475 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include namespace libbitcoin { namespace node { @@ -35,11 +35,9 @@ class BCN_API protocol protected: typedef network::channel::ptr channel_ptr; - /// Session implements both network::session and node::session. template protocol(Session& session, const channel_ptr& channel) NOEXCEPT - : network::protocol(session, channel), - session_(session) + : network::protocol(session, channel), session_(session) { } diff --git a/include/bitcoin/node/protocols/protocol_block_in.hpp b/include/bitcoin/node/protocols/protocol_block_in.hpp index e0c2f773..8ea44d09 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -46,7 +46,7 @@ class BCN_API protocol_block_in block_type_(session.config().network.witness_node() ? type_id::witness_block : type_id::block), performance_timer_(std::make_shared( - session.log, channel->strand(), network::seconds(10))) + session.log, channel->strand(), network::seconds(3))) { } BC_POP_WARNING() diff --git a/include/bitcoin/node/protocols/protocols.hpp b/include/bitcoin/node/protocols/protocols.hpp index 422940ce..48b5d9b7 100644 --- a/include/bitcoin/node/protocols/protocols.hpp +++ b/include/bitcoin/node/protocols/protocols.hpp @@ -19,7 +19,7 @@ #ifndef LIBBITCOIN_NODE_PROTOCOLS_PROTOCOLS_HPP #define LIBBITCOIN_NODE_PROTOCOLS_PROTOCOLS_HPP -#include +#include #include #include #include @@ -29,5 +29,6 @@ #include #include #include +#include #endif diff --git a/include/bitcoin/node/sessions/session.hpp b/include/bitcoin/node/protocols/session.hpp similarity index 76% rename from include/bitcoin/node/sessions/session.hpp rename to include/bitcoin/node/protocols/session.hpp index 92eeeb53..e28386b8 100644 --- a/include/bitcoin/node/sessions/session.hpp +++ b/include/bitcoin/node/protocols/session.hpp @@ -16,8 +16,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#ifndef LIBBITCOIN_NODE_SESSION_HPP -#define LIBBITCOIN_NODE_SESSION_HPP +#ifndef LIBBITCOIN_NODE_PROTOCOLS_SESSION_HPP +#define LIBBITCOIN_NODE_PROTOCOLS_SESSION_HPP #include #include @@ -26,10 +26,14 @@ namespace libbitcoin { namespace node { -/// Concrete base class for node sessions. +/// Common protocol session context. +/// This is in protocols directory because attach requires it. class BCN_API session { public: + /// Handle performance, base returns false (implied terminate). + virtual bool performance(size_t bytes) const NOEXCEPT; + /// Configuration settings for all libraries. const configuration& config() const NOEXCEPT; @@ -37,7 +41,9 @@ class BCN_API session full_node::query& archive() const NOEXCEPT; protected: - /// Construct the session. + DEFAULT_COPY_MOVE_DESTRUCT(session); + + /// Construct/destruct the session. session(full_node& node) NOEXCEPT; private: diff --git a/include/bitcoin/node/sessions/session_inbound.hpp b/include/bitcoin/node/sessions/session_inbound.hpp new file mode 100644 index 00000000..7146e3fa --- /dev/null +++ b/include/bitcoin/node/sessions/session_inbound.hpp @@ -0,0 +1,33 @@ +/** + * 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_SESSIONS_SESSION_INBOUND_HPP +#define LIBBITCOIN_NODE_SESSIONS_SESSION_INBOUND_HPP + +#include +#include + +namespace libbitcoin { +namespace node { + +using session_inbound = attach; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/sessions/session_manual.hpp b/include/bitcoin/node/sessions/session_manual.hpp new file mode 100644 index 00000000..0d167f80 --- /dev/null +++ b/include/bitcoin/node/sessions/session_manual.hpp @@ -0,0 +1,33 @@ +/** + * 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_SESSIONS_SESSION_MANUAL_HPP +#define LIBBITCOIN_NODE_SESSIONS_SESSION_MANUAL_HPP + +#include +#include + +namespace libbitcoin { +namespace node { + +using session_manual = attach; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/sessions/session_outbound.hpp b/include/bitcoin/node/sessions/session_outbound.hpp new file mode 100644 index 00000000..27a40d84 --- /dev/null +++ b/include/bitcoin/node/sessions/session_outbound.hpp @@ -0,0 +1,46 @@ +/** + * 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_SESSIONS_SESSION_OUTBOUND_HPP +#define LIBBITCOIN_NODE_SESSIONS_SESSION_OUTBOUND_HPP + +#include +#include +#include +#include + +namespace libbitcoin { +namespace node { + +class BCN_API session_outbound + : public attach +{ +public: + session_outbound(full_node& node, uint64_t identifier) NOEXCEPT; + + bool performance(size_t) const NOEXCEPT override; + +protected: + void attach_protocols( + const network::channel::ptr& channel) NOEXCEPT override; +}; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/sessions/sessions.hpp b/include/bitcoin/node/sessions/sessions.hpp new file mode 100644 index 00000000..b2f8e786 --- /dev/null +++ b/include/bitcoin/node/sessions/sessions.hpp @@ -0,0 +1,26 @@ +/** + * 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_SESSIONS_SESSIONS_HPP +#define LIBBITCOIN_NODE_SESSIONS_SESSIONS_HPP + +#include +#include +#include + +#endif diff --git a/src/full_node.cpp b/src/full_node.cpp index 6612e814..6a1f2e8b 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include namespace libbitcoin { namespace node { diff --git a/src/protocols/protocol.cpp b/src/protocols/protocol.cpp index c20f1d99..065e8cba 100644 --- a/src/protocols/protocol.cpp +++ b/src/protocols/protocol.cpp @@ -26,9 +26,9 @@ namespace libbitcoin { namespace node { -bool protocol::performance(size_t) const NOEXCEPT +bool protocol::performance(size_t bytes) const NOEXCEPT { - return true; + return session_.performance(bytes); } const configuration& protocol::config() const NOEXCEPT diff --git a/src/sessions/session.cpp b/src/protocols/session.cpp similarity index 91% rename from src/sessions/session.cpp rename to src/protocols/session.cpp index 909c9854..e8244a7c 100644 --- a/src/sessions/session.cpp +++ b/src/protocols/session.cpp @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#include +#include #include #include @@ -30,6 +30,11 @@ session::session(full_node& node) NOEXCEPT { } +bool session::performance(size_t) const NOEXCEPT +{ + return false; +} + const configuration& session::config() const NOEXCEPT { return node_.config(); diff --git a/src/sessions/session_inbound.cpp b/src/sessions/session_inbound.cpp new file mode 100644 index 00000000..b0b3deb2 --- /dev/null +++ b/src/sessions/session_inbound.cpp @@ -0,0 +1,25 @@ +/** + * 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 + +namespace libbitcoin { +namespace node { + +} // namespace node +} // namespace libbitcoin diff --git a/src/sessions/session_manual.cpp b/src/sessions/session_manual.cpp new file mode 100644 index 00000000..c091bd46 --- /dev/null +++ b/src/sessions/session_manual.cpp @@ -0,0 +1,25 @@ +/** + * 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 + +namespace libbitcoin { +namespace node { + +} // namespace node +} // namespace libbitcoin diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp new file mode 100644 index 00000000..5022e40d --- /dev/null +++ b/src/sessions/session_outbound.cpp @@ -0,0 +1,59 @@ +/** + * 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 + +#include +#include +#include +#include + +namespace libbitcoin { +namespace node { + +session_outbound::session_outbound(full_node& node, + uint64_t identifier) NOEXCEPT + : attach(node, identifier) +{ + // attach(node, identifier)... + // Set the current top for version protocol, before handshake. + // Attach and execute appropriate version protocol. +}; + + // Overrides session::performance. +bool session_outbound::performance(size_t) const NOEXCEPT +{ + return true; +} + +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; + constexpr auto performance = true; + channel->attach(self, performance)->start(); + ////channel->attach(self)->start(); + ////channel->attach(self)->start(); + ////channel->attach(self)->start(); +} + +} // namespace node +} // namespace libbitcoin From 610272093867d49cdfa0263f8bc45a636188cac2 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Tue, 30 Jan 2024 23:48:54 -0500 Subject: [PATCH 16/27] Implement download speed standard deviation. --- include/bitcoin/node/protocols/session.hpp | 2 +- .../node/sessions/session_outbound.hpp | 7 ++++- src/protocols/session.cpp | 2 +- src/sessions/session_outbound.cpp | 27 ++++++++++++++----- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/include/bitcoin/node/protocols/session.hpp b/include/bitcoin/node/protocols/session.hpp index e28386b8..30b4f34e 100644 --- a/include/bitcoin/node/protocols/session.hpp +++ b/include/bitcoin/node/protocols/session.hpp @@ -32,7 +32,7 @@ class BCN_API session { public: /// Handle performance, base returns false (implied terminate). - virtual bool performance(size_t bytes) const NOEXCEPT; + virtual bool performance(size_t bytes) NOEXCEPT; /// Configuration settings for all libraries. const configuration& config() const NOEXCEPT; diff --git a/include/bitcoin/node/sessions/session_outbound.hpp b/include/bitcoin/node/sessions/session_outbound.hpp index 27a40d84..f795d175 100644 --- a/include/bitcoin/node/sessions/session_outbound.hpp +++ b/include/bitcoin/node/sessions/session_outbound.hpp @@ -19,6 +19,7 @@ #ifndef LIBBITCOIN_NODE_SESSIONS_SESSION_OUTBOUND_HPP #define LIBBITCOIN_NODE_SESSIONS_SESSION_OUTBOUND_HPP +#include #include #include #include @@ -33,11 +34,15 @@ class BCN_API session_outbound public: session_outbound(full_node& node, uint64_t identifier) NOEXCEPT; - bool performance(size_t) const NOEXCEPT override; + bool performance(size_t bytes) NOEXCEPT override; protected: void attach_protocols( const network::channel::ptr& channel) NOEXCEPT override; + +private: + // This is protected by strand. + std::deque speeds_; }; } // namespace node diff --git a/src/protocols/session.cpp b/src/protocols/session.cpp index e8244a7c..b671fbba 100644 --- a/src/protocols/session.cpp +++ b/src/protocols/session.cpp @@ -30,7 +30,7 @@ session::session(full_node& node) NOEXCEPT { } -bool session::performance(size_t) const NOEXCEPT +bool session::performance(size_t) NOEXCEPT { return false; } diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp index 5022e40d..e068119b 100644 --- a/src/sessions/session_outbound.cpp +++ b/src/sessions/session_outbound.cpp @@ -18,6 +18,8 @@ */ #include +#include +#include #include #include #include @@ -30,15 +32,28 @@ session_outbound::session_outbound(full_node& node, uint64_t identifier) NOEXCEPT : attach(node, identifier) { - // attach(node, identifier)... - // Set the current top for version protocol, before handshake. - // Attach and execute appropriate version protocol. }; - // Overrides session::performance. -bool session_outbound::performance(size_t) const NOEXCEPT +// Overrides session::performance. +bool session_outbound::performance(size_t bytes) NOEXCEPT { - return true; + // TODO: pass completion handler and bounce to do_performance(). + ////BC_ASSERT_MSG(stranded(), "session_outbound"); + + const auto count = config().network.outbound_connections; + speeds_.push_front(static_cast(bytes)); + speeds_.resize(count); + const auto mean = std::accumulate(speeds_.begin(), speeds_.end(), 0.0) / count; + const auto vary = std::accumulate(speeds_.begin(), speeds_.end(), 0.0, + [mean](auto sum, auto speed) NOEXCEPT + { + const auto difference = speed - mean; + return sum + (difference * difference); + }) / count; + const auto standard_deviation = std::sqrt(vary); + + // TODO: return false via completion handler if bytes less than N SD. + return standard_deviation >= 0.0; } void session_outbound::attach_protocols( From 01ab96e7eca88bf49b1f9d85dd9cbe885fc7e370 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Wed, 31 Jan 2024 14:34:06 -0500 Subject: [PATCH 17/27] Download ratcheting via standard deviation. --- include/bitcoin/node/error.hpp | 1 + include/bitcoin/node/protocols/protocol.hpp | 3 +- .../node/protocols/protocol_block_in.hpp | 10 ++- include/bitcoin/node/protocols/session.hpp | 3 +- .../node/sessions/session_outbound.hpp | 10 ++- include/bitcoin/node/settings.hpp | 11 ++- src/error.cpp | 1 + src/parser.cpp | 10 +++ src/protocols/protocol.cpp | 6 +- src/protocols/protocol_block_in.cpp | 21 ++++-- src/protocols/session.cpp | 8 ++- src/sessions/session_outbound.cpp | 69 ++++++++++++++----- src/settings.cpp | 9 ++- test/error.cpp | 9 +++ 14 files changed, 132 insertions(+), 39 deletions(-) diff --git a/include/bitcoin/node/error.hpp b/include/bitcoin/node/error.hpp index 9af40943..5d1caf8e 100644 --- a/include/bitcoin/node/error.hpp +++ b/include/bitcoin/node/error.hpp @@ -44,6 +44,7 @@ enum error_t : uint8_t // network slow_channel, + stalled_channel, // blockchain orphan_block, diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index 54792475..7b90e551 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -42,7 +42,8 @@ class BCN_API protocol } /// Report performance, false directs self-terminate. - bool performance(size_t bytes) const NOEXCEPT; + void performance(uint64_t channel, size_t speed, + network::result_handler&& handler) const 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 8ea44d09..50cb748a 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -42,11 +42,12 @@ class BCN_API protocol_block_in const channel_ptr& channel, bool report_performance) NOEXCEPT : node::protocol(session, channel), network::tracker(session.log), - report_performance_(report_performance), + report_performance_(report_performance && + !is_zero(session.config().node.sample_period_seconds)), block_type_(session.config().network.witness_node() ? type_id::witness_block : type_id::block), - performance_timer_(std::make_shared( - session.log, channel->strand(), network::seconds(3))) + performance_timer_(std::make_shared(session.log, + channel->strand(), session.config().node.sample_period())) { } BC_POP_WARNING() @@ -75,6 +76,9 @@ class BCN_API protocol_block_in const track_ptr& tracker) NOEXCEPT; /// Handle performance timer event. + virtual void handle_performance_timer(const code& ec) NOEXCEPT; + + /// Handle result of performance reporting. virtual void handle_performance(const code& ec) NOEXCEPT; /// Invoked when initial blocks sync is current. diff --git a/include/bitcoin/node/protocols/session.hpp b/include/bitcoin/node/protocols/session.hpp index 30b4f34e..6d9234df 100644 --- a/include/bitcoin/node/protocols/session.hpp +++ b/include/bitcoin/node/protocols/session.hpp @@ -32,7 +32,8 @@ class BCN_API session { public: /// Handle performance, base returns false (implied terminate). - virtual bool performance(size_t bytes) NOEXCEPT; + virtual void performance(uint64_t channel, size_t speed, + network::result_handler&& handler) NOEXCEPT; /// Configuration settings for all libraries. const configuration& config() const NOEXCEPT; diff --git a/include/bitcoin/node/sessions/session_outbound.hpp b/include/bitcoin/node/sessions/session_outbound.hpp index f795d175..80a56230 100644 --- a/include/bitcoin/node/sessions/session_outbound.hpp +++ b/include/bitcoin/node/sessions/session_outbound.hpp @@ -19,7 +19,7 @@ #ifndef LIBBITCOIN_NODE_SESSIONS_SESSION_OUTBOUND_HPP #define LIBBITCOIN_NODE_SESSIONS_SESSION_OUTBOUND_HPP -#include +#include #include #include #include @@ -34,15 +34,19 @@ class BCN_API session_outbound public: session_outbound(full_node& node, uint64_t identifier) NOEXCEPT; - bool performance(size_t bytes) NOEXCEPT override; + void performance(uint64_t channel, size_t speed, + network::result_handler&& handler) NOEXCEPT override; protected: void attach_protocols( const network::channel::ptr& channel) NOEXCEPT override; private: + void do_performance(uint64_t channel, size_t speed, + const network::result_handler& handler) NOEXCEPT; + // This is protected by strand. - std::deque speeds_; + std::unordered_map speeds_; }; } // namespace node diff --git a/include/bitcoin/node/settings.hpp b/include/bitcoin/node/settings.hpp index 1abc7cce..5ecd6ae7 100644 --- a/include/bitcoin/node/settings.hpp +++ b/include/bitcoin/node/settings.hpp @@ -61,8 +61,15 @@ class BCN_API settings settings(system::chain::selection context) NOEXCEPT; // TODO: these aren't actually node settings. - uint16_t target; - uint16_t interval; + uint16_t target{ 0 }; + uint16_t interval{ 0 }; + + /// Properties. + float allowed_deviation; + uint16_t sample_period_seconds; + + /// Helpers. + virtual network::steady_clock::duration sample_period() const NOEXCEPT; }; } // namespace node diff --git a/src/error.cpp b/src/error.cpp index a0ecada8..ac1ae9d3 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -35,6 +35,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) // network { slow_channel, "slow channel" }, + { stalled_channel, "stalled channel" }, // blockchain { orphan_block, "orphan block" }, diff --git a/src/parser.cpp b/src/parser.cpp index b55022a1..ca00b08e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -814,6 +814,16 @@ options_metadata parser::load_settings() THROWS value(&configured.node.interval), "Channel count reporting interval, defaults to 0 (0 disables)." ) + ( + "node.allowed_deviation", + value(&configured.node.allowed_deviation), + "Allowable underperformance standard deviation, defaults to 1.0." + ) + ( + "node.sample_period_seconds", + value(&configured.node.sample_period_seconds), + "Performance sampling time period, defaults to 5 (0 disables)." + ) ////( //// "node.notify_limit_hours", //// value(&configured.node.notify_limit_hours), diff --git a/src/protocols/protocol.cpp b/src/protocols/protocol.cpp index 065e8cba..4e390d9c 100644 --- a/src/protocols/protocol.cpp +++ b/src/protocols/protocol.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -26,9 +27,10 @@ namespace libbitcoin { namespace node { -bool protocol::performance(size_t bytes) const NOEXCEPT +void protocol::performance(uint64_t channel, size_t speed, + network::result_handler&& handler) const NOEXCEPT { - return session_.performance(bytes); + session_.performance(channel, speed, std::move(handler)); } const configuration& protocol::config() const NOEXCEPT diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index 556bf4b6..cd5f6407 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -51,9 +51,9 @@ BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR) // Performance polling. // ---------------------------------------------------------------------------- -void protocol_block_in::handle_performance(const code& ec) NOEXCEPT +void protocol_block_in::handle_performance_timer(const code& ec) NOEXCEPT { - BC_ASSERT_MSG(stranded(), "protocol_block_in"); + BC_ASSERT_MSG(!stranded(), "expected channel strand"); if (stopped() || ec == network::error::operation_canceled) return; @@ -61,18 +61,27 @@ void protocol_block_in::handle_performance(const code& ec) NOEXCEPT if (ec) { LOGF("Performance timer error, " << ec.message()); + stop(ec); return; } - if (!performance(bytes_)) + performance(identifier(), bytes_, BIND1(handle_performance, ec)); +} + +void protocol_block_in::handle_performance(const code& ec) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "expected network strand"); + + if (!stopped() && ec) { - stop(error::slow_channel); + LOGF("Performance error, " << ec.message()); + stop(ec); return; }; log.fire(event_block, bytes_); bytes_ = zero; - performance_timer_->start(BIND1(handle_performance, _1)); + performance_timer_->start(BIND1(handle_performance_timer, _1)); } // Start/stop. @@ -95,7 +104,7 @@ void protocol_block_in::start() NOEXCEPT } if (report_performance_) - performance_timer_->start(BIND1(handle_performance, _1)); + performance_timer_->start(BIND1(handle_performance_timer, _1)); // There is one persistent common inventory subscription. SUBSCRIBE_CHANNEL2(inventory, handle_receive_inventory, _1, _2); diff --git a/src/protocols/session.cpp b/src/protocols/session.cpp index b671fbba..f95708c1 100644 --- a/src/protocols/session.cpp +++ b/src/protocols/session.cpp @@ -18,8 +18,10 @@ */ #include +#include #include #include +#include #include namespace libbitcoin { @@ -30,9 +32,10 @@ session::session(full_node& node) NOEXCEPT { } -bool session::performance(size_t) NOEXCEPT +void session::performance(uint64_t, size_t, + network::result_handler&& handler) NOEXCEPT { - return false; + handler(error::unknown); } const configuration& session::config() const NOEXCEPT @@ -44,6 +47,5 @@ full_node::query& session::archive() const NOEXCEPT { return node_.archive(); } - } // namespace node } // namespace libbitcoin diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp index e068119b..64fd5607 100644 --- a/src/sessions/session_outbound.cpp +++ b/src/sessions/session_outbound.cpp @@ -22,38 +22,73 @@ #include #include #include +#include #include #include namespace libbitcoin { namespace node { +#define CLASS session_outbound + +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + session_outbound::session_outbound(full_node& node, uint64_t identifier) NOEXCEPT : attach(node, identifier) { }; -// Overrides session::performance. -bool session_outbound::performance(size_t bytes) NOEXCEPT +void session_outbound::performance(uint64_t channel, size_t speed, + network::result_handler&& handler) NOEXCEPT +{ + boost::asio::post(strand(), + BIND3(do_performance, channel, speed, handler)); +} + +void session_outbound::do_performance(uint64_t channel, size_t speed, + const network::result_handler& handler) NOEXCEPT { - // TODO: pass completion handler and bounce to do_performance(). - ////BC_ASSERT_MSG(stranded(), "session_outbound"); - - const auto count = config().network.outbound_connections; - speeds_.push_front(static_cast(bytes)); - speeds_.resize(count); - const auto mean = std::accumulate(speeds_.begin(), speeds_.end(), 0.0) / count; - const auto vary = std::accumulate(speeds_.begin(), speeds_.end(), 0.0, - [mean](auto sum, auto speed) NOEXCEPT + BC_ASSERT_MSG(stranded(), "session_outbound"); + + // Always remove record on stalled channel (and channel close). + if (is_zero(speed)) + { + speeds_.erase(channel); + handler(error::stalled_channel); + return; + } + + speeds_[channel] = static_cast(speed); + + const auto size = speeds_.size(); + const auto mean = std::accumulate(speeds_.begin(), speeds_.end(), 0.0, + [](double sum, const auto& element) NOEXCEPT + { + return sum + element.second; + }) / size; + + // Keep this channel if its performance deviation is at/above average. + if (speed >= mean) + { + handler(error::success); + return; + } + + const auto variance = std::accumulate(speeds_.begin(), speeds_.end(), 0.0, + [mean](double sum, const auto& element) NOEXCEPT { - const auto difference = speed - mean; + const auto difference = element.second - mean; return sum + (difference * difference); - }) / count; - const auto standard_deviation = std::sqrt(vary); + }) / size; + + const auto standard_deviation = std::sqrt(variance); + const auto allowed_deviation = this->config().node.allowed_deviation; - // TODO: return false via completion handler if bytes less than N SD. - return standard_deviation >= 0.0; + // Drop this channel if the magnitude of its below average performance + // deviation exceeds the allowed multiple of standard deviations. + const auto slow = (mean - speed) > (allowed_deviation * standard_deviation); + handler(slow ? error::slow_channel : error::success); } void session_outbound::attach_protocols( @@ -70,5 +105,7 @@ void session_outbound::attach_protocols( ////channel->attach(self)->start(); } +BC_POP_WARNING() + } // namespace node } // namespace libbitcoin diff --git a/src/settings.cpp b/src/settings.cpp index 60a0cbca..5ecb8923 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -62,8 +62,8 @@ std::filesystem::path settings::events_file() NOEXCEPT namespace node { settings::settings() NOEXCEPT - : target{ 0 }, - interval{ 0 } + : allowed_deviation{ 1.0 }, + sample_period_seconds{ 5 } { } @@ -72,5 +72,10 @@ settings::settings(chain::selection) NOEXCEPT { } +network::steady_clock::duration settings::sample_period() const NOEXCEPT +{ + return network::seconds(sample_period_seconds); +} + } // namespace node } // namespace libbitcoin diff --git a/test/error.cpp b/test/error.cpp index 930f83ba..5e1063ad 100644 --- a/test/error.cpp +++ b/test/error.cpp @@ -59,6 +59,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__slow_channel__true_exected_message) BOOST_REQUIRE_EQUAL(ec.message(), "slow channel"); } +BOOST_AUTO_TEST_CASE(error_t__code__stalled_channel__true_exected_message) +{ + constexpr auto value = error::stalled_channel; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "stalled channel"); +} + BOOST_AUTO_TEST_CASE(error_t__code__orphan_block__true_exected_message) { constexpr auto value = error::orphan_block; From 6e032806cb38c198b07e5b39b6c98adecb4b76d6 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 8 Feb 2024 01:23:48 -0500 Subject: [PATCH 18/27] Track channel download rate in bytes per second. --- include/bitcoin/node/protocols/protocol.hpp | 2 +- .../node/protocols/protocol_block_in.hpp | 4 +-- include/bitcoin/node/protocols/session.hpp | 2 +- .../node/sessions/session_outbound.hpp | 4 +-- src/protocols/protocol.cpp | 2 +- src/protocols/protocol_block_in.cpp | 25 +++++++++++++++---- src/protocols/session.cpp | 2 +- src/sessions/session_outbound.cpp | 6 ++--- 8 files changed, 31 insertions(+), 16 deletions(-) diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index 7b90e551..b40947c7 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -42,7 +42,7 @@ class BCN_API protocol } /// Report performance, false directs self-terminate. - void performance(uint64_t channel, size_t speed, + void performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) const NOEXCEPT; /// Configuration settings for all libraries. diff --git a/include/bitcoin/node/protocols/protocol_block_in.hpp b/include/bitcoin/node/protocols/protocol_block_in.hpp index 50cb748a..8d7c6a24 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -99,8 +99,8 @@ class BCN_API protocol_block_in const network::messages::inventory::type_id block_type_; // Protected by strand. - uint32_t start_{}; - size_t bytes_{ zero }; + uint64_t bytes_{ zero }; + network::steady_clock::time_point start_{}; system::chain::chain_state::ptr state_{}; network::deadline::ptr performance_timer_; }; diff --git a/include/bitcoin/node/protocols/session.hpp b/include/bitcoin/node/protocols/session.hpp index 6d9234df..c87fbdbc 100644 --- a/include/bitcoin/node/protocols/session.hpp +++ b/include/bitcoin/node/protocols/session.hpp @@ -32,7 +32,7 @@ class BCN_API session { public: /// Handle performance, base returns false (implied terminate). - virtual void performance(uint64_t channel, size_t speed, + virtual void performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) NOEXCEPT; /// Configuration settings for all libraries. diff --git a/include/bitcoin/node/sessions/session_outbound.hpp b/include/bitcoin/node/sessions/session_outbound.hpp index 80a56230..33335d1c 100644 --- a/include/bitcoin/node/sessions/session_outbound.hpp +++ b/include/bitcoin/node/sessions/session_outbound.hpp @@ -34,7 +34,7 @@ class BCN_API session_outbound public: session_outbound(full_node& node, uint64_t identifier) NOEXCEPT; - void performance(uint64_t channel, size_t speed, + void performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) NOEXCEPT override; protected: @@ -42,7 +42,7 @@ class BCN_API session_outbound const network::channel::ptr& channel) NOEXCEPT override; private: - void do_performance(uint64_t channel, size_t speed, + void do_performance(uint64_t channel, uint64_t speed, const network::result_handler& handler) NOEXCEPT; // This is protected by strand. diff --git a/src/protocols/protocol.cpp b/src/protocols/protocol.cpp index 4e390d9c..749d4449 100644 --- a/src/protocols/protocol.cpp +++ b/src/protocols/protocol.cpp @@ -27,7 +27,7 @@ namespace libbitcoin { namespace node { -void protocol::performance(uint64_t channel, size_t speed, +void protocol::performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) const NOEXCEPT { session_.performance(channel, speed, std::move(handler)); diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index cd5f6407..ec13bcd0 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -65,22 +66,36 @@ void protocol_block_in::handle_performance_timer(const code& ec) NOEXCEPT return; } - performance(identifier(), bytes_, BIND1(handle_performance, ec)); + // Compute bytes per second. + const auto now = steady_clock::now(); + const auto gap = std::chrono::duration_cast(now - start_).count(); + const auto rate = floored_divide(bytes_, to_unsigned(gap)); + + // Reset counters and log rate (bytes per second). + bytes_ = zero; + start_ = now; + log.fire(event_block, rate); + + // Channel will continue to process blocks while this call excecutes on the + // network strand. Timer will not be restarted until this call completes. + performance(identifier(), rate, BIND1(handle_performance, ec)); } void protocol_block_in::handle_performance(const code& ec) NOEXCEPT { BC_ASSERT_MSG(stranded(), "expected network strand"); - if (!stopped() && ec) + if (stopped()) + return; + + // stalled_channel or slow_channel + if (ec) { LOGF("Performance error, " << ec.message()); stop(ec); return; }; - log.fire(event_block, bytes_); - bytes_ = zero; performance_timer_->start(BIND1(handle_performance_timer, _1)); } @@ -94,7 +109,7 @@ void protocol_block_in::start() NOEXCEPT if (started()) return; - start_ = unix_time(); + start_ = steady_clock::now(); state_ = archive().get_confirmed_chain_state(config().bitcoin); if (!state_) diff --git a/src/protocols/session.cpp b/src/protocols/session.cpp index f95708c1..cbb8c68f 100644 --- a/src/protocols/session.cpp +++ b/src/protocols/session.cpp @@ -32,7 +32,7 @@ session::session(full_node& node) NOEXCEPT { } -void session::performance(uint64_t, size_t, +void session::performance(uint64_t, uint64_t, network::result_handler&& handler) NOEXCEPT { handler(error::unknown); diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp index 64fd5607..71c0097b 100644 --- a/src/sessions/session_outbound.cpp +++ b/src/sessions/session_outbound.cpp @@ -39,14 +39,14 @@ session_outbound::session_outbound(full_node& node, { }; -void session_outbound::performance(uint64_t channel, size_t speed, +void session_outbound::performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) NOEXCEPT { boost::asio::post(strand(), BIND3(do_performance, channel, speed, handler)); } -void session_outbound::do_performance(uint64_t channel, size_t speed, +void session_outbound::do_performance(uint64_t channel, uint64_t speed, const network::result_handler& handler) NOEXCEPT { BC_ASSERT_MSG(stranded(), "session_outbound"); @@ -83,7 +83,7 @@ void session_outbound::do_performance(uint64_t channel, size_t speed, }) / size; const auto standard_deviation = std::sqrt(variance); - const auto allowed_deviation = this->config().node.allowed_deviation; + const auto allowed_deviation = config().node.allowed_deviation; // Drop this channel if the magnitude of its below average performance // deviation exceeds the allowed multiple of standard deviations. From 5d51925efcd9458bac7e0527daa17b41b05aa1fb Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 8 Feb 2024 01:48:20 -0500 Subject: [PATCH 19/27] Comments. --- src/protocols/protocol_block_in.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index ec13bcd0..cd7407e0 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -66,12 +66,12 @@ void protocol_block_in::handle_performance_timer(const code& ec) NOEXCEPT return; } - // Compute bytes per second. + // Compute rate in bytes per second. const auto now = steady_clock::now(); const auto gap = std::chrono::duration_cast(now - start_).count(); const auto rate = floored_divide(bytes_, to_unsigned(gap)); - // Reset counters and log rate (bytes per second). + // Reset counters and log rate. bytes_ = zero; start_ = now; log.fire(event_block, rate); From 83688ba38b952e586983f1a4ac4cc9f66ccd87a9 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 9 Feb 2024 01:07:30 -0500 Subject: [PATCH 20/27] Stub in chasers and rate polling, move session.hpp. --- Makefile.am | 18 ++- builds/cmake/CMakeLists.txt | 6 +- .../libbitcoin-node/libbitcoin-node.vcxproj | 16 ++- .../libbitcoin-node.vcxproj.filters | 38 +++++- include/bitcoin/node.hpp | 10 +- include/bitcoin/node/chasers/chaser.hpp | 80 ++++++++++++ .../{block_chaser.hpp => chaser_check.hpp} | 19 ++- .../bitcoin/node/chasers/chaser_confirm.hpp | 78 ++++++++++++ .../bitcoin/node/chasers/chaser_header.hpp | 78 ++++++++++++ .../node/chasers/chaser_transaction.hpp | 77 ++++++++++++ .../bitcoin/node/chasers/chaser_validate.hpp | 78 ++++++++++++ include/bitcoin/node/chasers/chasers.hpp | 29 +++++ include/bitcoin/node/protocols/attach.hpp | 4 +- include/bitcoin/node/protocols/protocol.hpp | 4 +- include/bitcoin/node/protocols/protocols.hpp | 1 - .../node/{protocols => sessions}/session.hpp | 7 +- .../bitcoin/node/sessions/session_inbound.hpp | 1 + .../bitcoin/node/sessions/session_manual.hpp | 1 + .../node/sessions/session_outbound.hpp | 1 + include/bitcoin/node/sessions/sessions.hpp | 4 + .../{block_chaser.cpp => chaser_check.cpp} | 54 +++----- src/chasers/chaser_confirm.cpp | 115 ++++++++++++++++++ src/chasers/chaser_header.cpp | 115 ++++++++++++++++++ src/chasers/chaser_transaction.cpp | 115 ++++++++++++++++++ src/chasers/chaser_validate.cpp | 115 ++++++++++++++++++ src/protocols/session.cpp | 2 +- 26 files changed, 996 insertions(+), 70 deletions(-) create mode 100644 include/bitcoin/node/chasers/chaser.hpp rename include/bitcoin/node/chasers/{block_chaser.hpp => chaser_check.hpp} (83%) create mode 100644 include/bitcoin/node/chasers/chaser_confirm.hpp create mode 100644 include/bitcoin/node/chasers/chaser_header.hpp create mode 100644 include/bitcoin/node/chasers/chaser_transaction.hpp create mode 100644 include/bitcoin/node/chasers/chaser_validate.hpp create mode 100644 include/bitcoin/node/chasers/chasers.hpp rename include/bitcoin/node/{protocols => sessions}/session.hpp (89%) rename src/chasers/{block_chaser.cpp => chaser_check.cpp} (61%) create mode 100644 src/chasers/chaser_confirm.cpp create mode 100644 src/chasers/chaser_header.cpp create mode 100644 src/chasers/chaser_transaction.cpp create mode 100644 src/chasers/chaser_validate.cpp diff --git a/Makefile.am b/Makefile.am index e52e68a4..c2ca8942 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,7 +40,11 @@ src_libbitcoin_node_la_SOURCES = \ src/full_node.cpp \ src/parser.cpp \ src/settings.cpp \ - src/chasers/block_chaser.cpp \ + src/chasers/chaser_check.cpp \ + src/chasers/chaser_confirm.cpp \ + src/chasers/chaser_header.cpp \ + src/chasers/chaser_transaction.cpp \ + src/chasers/chaser_validate.cpp \ src/protocols/protocol.cpp \ src/protocols/protocol_block_in.cpp \ src/protocols/protocol_block_out.cpp \ @@ -110,7 +114,13 @@ include_bitcoin_node_HEADERS = \ include_bitcoin_node_chasersdir = ${includedir}/bitcoin/node/chasers include_bitcoin_node_chasers_HEADERS = \ - include/bitcoin/node/chasers/block_chaser.hpp + include/bitcoin/node/chasers/chaser.hpp \ + include/bitcoin/node/chasers/chaser_check.hpp \ + include/bitcoin/node/chasers/chaser_confirm.hpp \ + include/bitcoin/node/chasers/chaser_header.hpp \ + include/bitcoin/node/chasers/chaser_transaction.hpp \ + include/bitcoin/node/chasers/chaser_validate.hpp \ + include/bitcoin/node/chasers/chasers.hpp include_bitcoin_node_protocolsdir = ${includedir}/bitcoin/node/protocols include_bitcoin_node_protocols_HEADERS = \ @@ -124,11 +134,11 @@ include_bitcoin_node_protocols_HEADERS = \ include/bitcoin/node/protocols/protocol_header_out_70012.hpp \ include/bitcoin/node/protocols/protocol_transaction_in.hpp \ include/bitcoin/node/protocols/protocol_transaction_out.hpp \ - include/bitcoin/node/protocols/protocols.hpp \ - include/bitcoin/node/protocols/session.hpp + include/bitcoin/node/protocols/protocols.hpp include_bitcoin_node_sessionsdir = ${includedir}/bitcoin/node/sessions include_bitcoin_node_sessions_HEADERS = \ + include/bitcoin/node/sessions/session.hpp \ include/bitcoin/node/sessions/session_inbound.hpp \ include/bitcoin/node/sessions/session_manual.hpp \ include/bitcoin/node/sessions/session_outbound.hpp \ diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt index befa95af..a6f4b02a 100644 --- a/builds/cmake/CMakeLists.txt +++ b/builds/cmake/CMakeLists.txt @@ -250,7 +250,11 @@ add_library( ${CANONICAL_LIB_NAME} "../../src/full_node.cpp" "../../src/parser.cpp" "../../src/settings.cpp" - "../../src/chasers/block_chaser.cpp" + "../../src/chasers/chaser_check.cpp" + "../../src/chasers/chaser_confirm.cpp" + "../../src/chasers/chaser_header.cpp" + "../../src/chasers/chaser_transaction.cpp" + "../../src/chasers/chaser_validate.cpp" "../../src/protocols/protocol.cpp" "../../src/protocols/protocol_block_in.cpp" "../../src/protocols/protocol_block_out.cpp" diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj index e7f163a1..766734ab 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj @@ -73,7 +73,11 @@ - + + + + + @@ -95,7 +99,13 @@ - + + + + + + + @@ -112,7 +122,7 @@ - + diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters index 13e2cb81..0e6f8eb1 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters @@ -42,7 +42,19 @@ - + + src\chasers + + + src\chasers + + + src\chasers + + + src\chasers + + src\chasers @@ -104,7 +116,25 @@ include\bitcoin - + + include\bitcoin\node\chasers + + + include\bitcoin\node\chasers + + + include\bitcoin\node\chasers + + + include\bitcoin\node\chasers + + + include\bitcoin\node\chasers + + + include\bitcoin\node\chasers + + include\bitcoin\node\chasers @@ -155,8 +185,8 @@ include\bitcoin\node\protocols - - include\bitcoin\node\protocols + + include\bitcoin\node\sessions include\bitcoin\node\sessions diff --git a/include/bitcoin/node.hpp b/include/bitcoin/node.hpp index 7ebc8b00..bcf5f962 100644 --- a/include/bitcoin/node.hpp +++ b/include/bitcoin/node.hpp @@ -23,7 +23,13 @@ #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -35,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/bitcoin/node/chasers/chaser.hpp b/include/bitcoin/node/chasers/chaser.hpp new file mode 100644 index 00000000..0c60af0d --- /dev/null +++ b/include/bitcoin/node/chasers/chaser.hpp @@ -0,0 +1,80 @@ +/** + * 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_HPP +#define LIBBITCOIN_NODE_CHASERS_CHASER_HPP + +#include +#include + +namespace libbitcoin { +namespace node { + +class full_node; + +/// Abstract base chaser. +/// Each chaser operates on its own strand, implemented here, allowing +/// concurrent chaser operations to the extent that threads are available. +/// +class BCN_API chaser + : public network::reporter, protected network::tracker +{ +public: + typedef uint64_t object_key; + typedef network::desubscriber subscriber; + typedef subscriber::handler notifier; + DELETE_COPY_MOVE(chaser); + + /// Construct an instance. + /// ----------------------------------------------------------------------- + chaser(full_node& node) NOEXCEPT; + ~chaser() NOEXCEPT; + + /// Start/stop. + /// ----------------------------------------------------------------------- + void start(network::result_handler&& handler) NOEXCEPT; + void stop() NOEXCEPT; + + /// Subscriptions. + /// ----------------------------------------------------------------------- + object_key subscribe(notifier&& handler) NOEXCEPT; + bool notify(object_key key) NOEXCEPT; + + /// Properties. + /// ----------------------------------------------------------------------- + bool stopped() const NOEXCEPT; + bool stranded() const NOEXCEPT; + +private: + object_key create_key() NOEXCEPT; + void do_stop() NOEXCEPT; + + // These are thread safe (mostly). + full_node& node_; + network::asio::strand strand_; + std::atomic_bool stopped_{ true }; + + // These are protected by the strand. + object_key keys_{}; + subscriber subscriber_; +}; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/chasers/block_chaser.hpp b/include/bitcoin/node/chasers/chaser_check.hpp similarity index 83% rename from include/bitcoin/node/chasers/block_chaser.hpp rename to include/bitcoin/node/chasers/chaser_check.hpp index 6d468538..f2d713a0 100644 --- a/include/bitcoin/node/chasers/block_chaser.hpp +++ b/include/bitcoin/node/chasers/chaser_check.hpp @@ -16,8 +16,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#ifndef LIBBITCOIN_NODE_CHASERS_BLOCK_CHASER_HPP -#define LIBBITCOIN_NODE_CHASERS_BLOCK_CHASER_HPP +#ifndef LIBBITCOIN_NODE_CHASERS_CHASER_CHECK_HPP +#define LIBBITCOIN_NODE_CHASERS_CHASER_CHECK_HPP #include #include @@ -28,20 +28,20 @@ namespace node { class full_node; /// Chase down blocks for the candidate header chain. -/// Notify subscribers with gap closed event. -class BCN_API block_chaser - : public network::reporter, protected network::tracker +/// Notify subscribers with "block checked" event. +class BCN_API chaser_check + : public network::reporter, protected network::tracker { public: typedef uint64_t object_key; typedef network::desubscriber subscriber; typedef subscriber::handler notifier; - DELETE_COPY_MOVE(block_chaser); + DELETE_COPY_MOVE(chaser_check); /// Construct an instance. /// ----------------------------------------------------------------------- - block_chaser(full_node& node) NOEXCEPT; - ~block_chaser() NOEXCEPT; + chaser_check(full_node& node) NOEXCEPT; + ~chaser_check() NOEXCEPT; /// Start/stop. /// ----------------------------------------------------------------------- @@ -67,10 +67,9 @@ class BCN_API block_chaser network::asio::strand strand_; std::atomic_bool stopped_{ true }; - // These are not thread safe. + // These are protected by the strand. object_key keys_{}; subscriber subscriber_; - network::deadline::ptr timer_; }; } // namespace node diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp new file mode 100644 index 00000000..dc7f4659 --- /dev/null +++ b/include/bitcoin/node/chasers/chaser_confirm.hpp @@ -0,0 +1,78 @@ +/** + * 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_CONFIRM_HPP +#define LIBBITCOIN_NODE_CHASERS_CHASER_CONFIRM_HPP + +#include +#include + +namespace libbitcoin { +namespace node { + +class full_node; + +/// Chase down valid blocks for confirmation. +/// Notify subscribers with "block confirmed" event. +class BCN_API chaser_confirm + : public network::reporter, protected network::tracker +{ +public: + typedef uint64_t object_key; + typedef network::desubscriber subscriber; + typedef subscriber::handler notifier; + DELETE_COPY_MOVE(chaser_confirm); + + /// Construct an instance. + /// ----------------------------------------------------------------------- + chaser_confirm(full_node& node) NOEXCEPT; + ~chaser_confirm() NOEXCEPT; + + /// Start/stop. + /// ----------------------------------------------------------------------- + void start(network::result_handler&& handler) NOEXCEPT; + void stop() NOEXCEPT; + + /// Subscriptions. + /// ----------------------------------------------------------------------- + object_key subscribe(notifier&& handler) NOEXCEPT; + bool notify(object_key key) NOEXCEPT; + + /// Properties. + /// ----------------------------------------------------------------------- + bool stopped() const NOEXCEPT; + bool stranded() const NOEXCEPT; + +private: + object_key create_key() NOEXCEPT; + void do_stop() NOEXCEPT; + + // These are thread safe (mostly). + full_node& node_; + network::asio::strand strand_; + std::atomic_bool stopped_{ true }; + + // These are protected by the strand. + object_key keys_{}; + subscriber subscriber_; +}; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp new file mode 100644 index 00000000..4634c3aa --- /dev/null +++ b/include/bitcoin/node/chasers/chaser_header.hpp @@ -0,0 +1,78 @@ +/** + * 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_HEADER_HPP +#define LIBBITCOIN_NODE_CHASERS_CHASER_HEADER_HPP + +#include +#include + +namespace libbitcoin { +namespace node { + +class full_node; + +/// Chase down stronger header branches for the candidate chain. +/// Notify subscribers with "strong header" event. +class BCN_API chaser_header + : public network::reporter, protected network::tracker +{ +public: + typedef uint64_t object_key; + typedef network::desubscriber subscriber; + typedef subscriber::handler notifier; + DELETE_COPY_MOVE(chaser_header); + + /// Construct an instance. + /// ----------------------------------------------------------------------- + chaser_header(full_node& node) NOEXCEPT; + ~chaser_header() NOEXCEPT; + + /// Start/stop. + /// ----------------------------------------------------------------------- + void start(network::result_handler&& handler) NOEXCEPT; + void stop() NOEXCEPT; + + /// Subscriptions. + /// ----------------------------------------------------------------------- + object_key subscribe(notifier&& handler) NOEXCEPT; + bool notify(object_key key) NOEXCEPT; + + /// Properties. + /// ----------------------------------------------------------------------- + bool stopped() const NOEXCEPT; + bool stranded() const NOEXCEPT; + +private: + object_key create_key() NOEXCEPT; + void do_stop() NOEXCEPT; + + // These are thread safe (mostly). + full_node& node_; + network::asio::strand strand_; + std::atomic_bool stopped_{ true }; + + // These are protected by the strand. + object_key keys_{}; + subscriber subscriber_; +}; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/chasers/chaser_transaction.hpp b/include/bitcoin/node/chasers/chaser_transaction.hpp new file mode 100644 index 00000000..90eb9981 --- /dev/null +++ b/include/bitcoin/node/chasers/chaser_transaction.hpp @@ -0,0 +1,77 @@ +/** + * 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_TRANSACTION_HPP +#define LIBBITCOIN_NODE_CHASERS_CHASER_TRANSACTION_HPP + +#include +#include + +namespace libbitcoin { +namespace node { + +class full_node; + +/// Chase down unconfirmed transactions. +class BCN_API chaser_transaction + : public network::reporter, protected network::tracker +{ +public: + typedef uint64_t object_key; + typedef network::desubscriber subscriber; + typedef subscriber::handler notifier; + DELETE_COPY_MOVE(chaser_transaction); + + /// Construct an instance. + /// ----------------------------------------------------------------------- + chaser_transaction(full_node& node) NOEXCEPT; + ~chaser_transaction() NOEXCEPT; + + /// Start/stop. + /// ----------------------------------------------------------------------- + void start(network::result_handler&& handler) NOEXCEPT; + void stop() NOEXCEPT; + + /// Subscriptions. + /// ----------------------------------------------------------------------- + object_key subscribe(notifier&& handler) NOEXCEPT; + bool notify(object_key key) NOEXCEPT; + + /// Properties. + /// ----------------------------------------------------------------------- + bool stopped() const NOEXCEPT; + bool stranded() const NOEXCEPT; + +private: + object_key create_key() NOEXCEPT; + void do_stop() NOEXCEPT; + + // These are thread safe (mostly). + full_node& node_; + network::asio::strand strand_; + std::atomic_bool stopped_{ true }; + + // These are protected by the strand. + object_key keys_{}; + subscriber subscriber_; +}; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/chasers/chaser_validate.hpp b/include/bitcoin/node/chasers/chaser_validate.hpp new file mode 100644 index 00000000..b2328d6d --- /dev/null +++ b/include/bitcoin/node/chasers/chaser_validate.hpp @@ -0,0 +1,78 @@ +/** + * 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_VALIDATE_HPP +#define LIBBITCOIN_NODE_CHASERS_CHASER_VALIDATE_HPP + +#include +#include + +namespace libbitcoin { +namespace node { + +class full_node; + +/// Chase down blocks in the the candidate header chain for validation. +/// Notify subscribers with the "block connected" event. +class BCN_API chaser_validate + : public network::reporter, protected network::tracker +{ +public: + typedef uint64_t object_key; + typedef network::desubscriber subscriber; + typedef subscriber::handler notifier; + DELETE_COPY_MOVE(chaser_validate); + + /// Construct an instance. + /// ----------------------------------------------------------------------- + chaser_validate(full_node& node) NOEXCEPT; + ~chaser_validate() NOEXCEPT; + + /// Start/stop. + /// ----------------------------------------------------------------------- + void start(network::result_handler&& handler) NOEXCEPT; + void stop() NOEXCEPT; + + /// Subscriptions. + /// ----------------------------------------------------------------------- + object_key subscribe(notifier&& handler) NOEXCEPT; + bool notify(object_key key) NOEXCEPT; + + /// Properties. + /// ----------------------------------------------------------------------- + bool stopped() const NOEXCEPT; + bool stranded() const NOEXCEPT; + +private: + object_key create_key() NOEXCEPT; + void do_stop() NOEXCEPT; + + // These are thread safe (mostly). + full_node& node_; + network::asio::strand strand_; + std::atomic_bool stopped_{ true }; + + // These are protected by the strand. + object_key keys_{}; + subscriber subscriber_; +}; + +} // namespace node +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/node/chasers/chasers.hpp b/include/bitcoin/node/chasers/chasers.hpp new file mode 100644 index 00000000..102b6807 --- /dev/null +++ b/include/bitcoin/node/chasers/chasers.hpp @@ -0,0 +1,29 @@ +/** + * 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 . + */ +#ifndef LIBBITCOIN_NODE_CHASERS_CHASERS_HPP +#define LIBBITCOIN_NODE_CHASERS_CHASERS_HPP + +#include +#include +#include +#include +#include +#include + +#endif diff --git a/include/bitcoin/node/protocols/attach.hpp b/include/bitcoin/node/protocols/attach.hpp index 12408b0a..e3cdc125 100644 --- a/include/bitcoin/node/protocols/attach.hpp +++ b/include/bitcoin/node/protocols/attach.hpp @@ -31,7 +31,9 @@ #include #include #include -#include + +// Individual inclusion to prevent cycle. +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index b40947c7..81b79736 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -23,7 +23,9 @@ #include #include #include -#include + +// Individual inclusion to prevent cycle. +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/protocols/protocols.hpp b/include/bitcoin/node/protocols/protocols.hpp index 48b5d9b7..83a3a374 100644 --- a/include/bitcoin/node/protocols/protocols.hpp +++ b/include/bitcoin/node/protocols/protocols.hpp @@ -29,6 +29,5 @@ #include #include #include -#include #endif diff --git a/include/bitcoin/node/protocols/session.hpp b/include/bitcoin/node/sessions/session.hpp similarity index 89% rename from include/bitcoin/node/protocols/session.hpp rename to include/bitcoin/node/sessions/session.hpp index c87fbdbc..c90377f8 100644 --- a/include/bitcoin/node/protocols/session.hpp +++ b/include/bitcoin/node/sessions/session.hpp @@ -16,8 +16,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#ifndef LIBBITCOIN_NODE_PROTOCOLS_SESSION_HPP -#define LIBBITCOIN_NODE_PROTOCOLS_SESSION_HPP +#ifndef LIBBITCOIN_NODE_SESSIONS_SESSION_HPP +#define LIBBITCOIN_NODE_SESSIONS_SESSION_HPP #include #include @@ -26,8 +26,7 @@ namespace libbitcoin { namespace node { -/// Common protocol session context. -/// This is in protocols directory because attach requires it. +/// Common session context. class BCN_API session { public: diff --git a/include/bitcoin/node/sessions/session_inbound.hpp b/include/bitcoin/node/sessions/session_inbound.hpp index 7146e3fa..e0342d72 100644 --- a/include/bitcoin/node/sessions/session_inbound.hpp +++ b/include/bitcoin/node/sessions/session_inbound.hpp @@ -21,6 +21,7 @@ #include #include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/sessions/session_manual.hpp b/include/bitcoin/node/sessions/session_manual.hpp index 0d167f80..989c0b11 100644 --- a/include/bitcoin/node/sessions/session_manual.hpp +++ b/include/bitcoin/node/sessions/session_manual.hpp @@ -21,6 +21,7 @@ #include #include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/sessions/session_outbound.hpp b/include/bitcoin/node/sessions/session_outbound.hpp index 33335d1c..f2718583 100644 --- a/include/bitcoin/node/sessions/session_outbound.hpp +++ b/include/bitcoin/node/sessions/session_outbound.hpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/sessions/sessions.hpp b/include/bitcoin/node/sessions/sessions.hpp index b2f8e786..40181791 100644 --- a/include/bitcoin/node/sessions/sessions.hpp +++ b/include/bitcoin/node/sessions/sessions.hpp @@ -19,6 +19,10 @@ #ifndef LIBBITCOIN_NODE_SESSIONS_SESSIONS_HPP #define LIBBITCOIN_NODE_SESSIONS_SESSIONS_HPP +// session.hpp must be included by /protocols/attach.hpp +// and therefore cannot be included here (avoids circularity). +// However the header is included in /sessions for taxonomic consistency. +////#include #include #include #include diff --git a/src/chasers/block_chaser.cpp b/src/chasers/chaser_check.cpp similarity index 61% rename from src/chasers/block_chaser.cpp rename to src/chasers/chaser_check.cpp index d498ef23..e2cdbf86 100644 --- a/src/chasers/block_chaser.cpp +++ b/src/chasers/chaser_check.cpp @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#include +#include #include #include @@ -26,26 +26,23 @@ namespace libbitcoin { namespace node { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) - -// TODO: replace channel_heartbeat. -block_chaser::block_chaser(full_node& node) NOEXCEPT + +chaser_check::chaser_check(full_node& node) NOEXCEPT : node_(node), strand_(node.service().get_executor()), subscriber_(strand_), - timer_(std::make_shared(node.log, strand_, - node.network_settings().channel_heartbeat())), reporter(node.log), - tracker(node.log) + tracker(node.log) { } -block_chaser::~block_chaser() NOEXCEPT +chaser_check::~chaser_check() NOEXCEPT { BC_ASSERT_MSG(stopped(), "The block chaser was not stopped."); - if (!stopped()) { LOGF("~block_chaser is not stopped."); } + if (!stopped()) { LOGF("~chaser_check is not stopped."); } } -void block_chaser::start(network::result_handler&& handler) NOEXCEPT +void chaser_check::start(network::result_handler&& handler) NOEXCEPT { if (!stopped()) { @@ -53,38 +50,20 @@ void block_chaser::start(network::result_handler&& handler) NOEXCEPT return; } - timer_->start([this](const code& ec) NOEXCEPT - { - BC_ASSERT_MSG(stranded(), "strand"); - - if (stopped()) - return; - - if (ec) - { - LOGF("Chaser timer fail, " << ec.message()); - stop(); - return; - } - - // TODO: collect performance. - ////stop(network::error::channel_expired); - }); - stopped_.store(false); handler(network::error::success); } -void block_chaser::stop() NOEXCEPT +void chaser_check::stop() NOEXCEPT { stopped_.store(true); - // The block_chaser can be deleted once threadpool joins after this call. + // The chaser_check can be deleted once threadpool joins after this call. boost::asio::post(strand_, - std::bind(&block_chaser::do_stop, this)); + std::bind(&chaser_check::do_stop, this)); } -block_chaser::object_key block_chaser::subscribe(notifier&& handler) NOEXCEPT +chaser_check::object_key chaser_check::subscribe(notifier&& handler) NOEXCEPT { BC_ASSERT_MSG(stranded(), "strand"); const auto key = create_key(); @@ -93,23 +72,23 @@ block_chaser::object_key block_chaser::subscribe(notifier&& handler) NOEXCEPT } // TODO: closing channel notifies itself to desubscribe. -bool block_chaser::notify(object_key key) NOEXCEPT +bool chaser_check::notify(object_key key) NOEXCEPT { return subscriber_.notify_one(key, network::error::success); } -bool block_chaser::stopped() const NOEXCEPT +bool chaser_check::stopped() const NOEXCEPT { return stopped_.load(); } -bool block_chaser::stranded() const NOEXCEPT +bool chaser_check::stranded() const NOEXCEPT { return strand_.running_in_this_thread(); } // private -block_chaser::object_key block_chaser::create_key() NOEXCEPT +chaser_check::object_key chaser_check::create_key() NOEXCEPT { BC_ASSERT_MSG(stranded(), "strand"); @@ -123,11 +102,10 @@ block_chaser::object_key block_chaser::create_key() NOEXCEPT } // private -void block_chaser::do_stop() NOEXCEPT +void chaser_check::do_stop() NOEXCEPT { BC_ASSERT_MSG(stranded(), "strand"); - timer_->stop(); subscriber_.stop(network::error::service_stopped); } diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp new file mode 100644 index 00000000..b6b65be0 --- /dev/null +++ b/src/chasers/chaser_confirm.cpp @@ -0,0 +1,115 @@ +/** + * 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 + +#include +#include +#include + +namespace libbitcoin { +namespace node { + +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + +chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT + : node_(node), + strand_(node.service().get_executor()), + subscriber_(strand_), + reporter(node.log), + tracker(node.log) +{ +} + +chaser_confirm::~chaser_confirm() NOEXCEPT +{ + BC_ASSERT_MSG(stopped(), "The confirmation chaser was not stopped."); + if (!stopped()) { LOGF("~chaser_confirm is not stopped."); } +} + +void chaser_confirm::start(network::result_handler&& handler) NOEXCEPT +{ + if (!stopped()) + { + handler(network::error::operation_failed); + return; + } + + stopped_.store(false); + handler(network::error::success); +} + +void chaser_confirm::stop() NOEXCEPT +{ + stopped_.store(true); + + // The chaser_confirm can be deleted once threadpool joins after this call. + boost::asio::post(strand_, + std::bind(&chaser_confirm::do_stop, this)); +} + +chaser_confirm::object_key chaser_confirm::subscribe(notifier&& handler) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + const auto key = create_key(); + subscriber_.subscribe(std::move(handler), key); + return key; +} + +// TODO: closing channel notifies itself to desubscribe. +bool chaser_confirm::notify(object_key key) NOEXCEPT +{ + return subscriber_.notify_one(key, network::error::success); +} + +bool chaser_confirm::stopped() const NOEXCEPT +{ + return stopped_.load(); +} + +bool chaser_confirm::stranded() const NOEXCEPT +{ + return strand_.running_in_this_thread(); +} + +// private +chaser_confirm::object_key chaser_confirm::create_key() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + if (is_zero(++keys_)) + { + BC_ASSERT_MSG(false, "overflow"); + LOGF("Chaser object overflow."); + } + + return keys_; +} + +// private +void chaser_confirm::do_stop() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + subscriber_.stop(network::error::service_stopped); +} + +BC_POP_WARNING() + +} // namespace database +} // namespace libbitcoin diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp new file mode 100644 index 00000000..d33099d7 --- /dev/null +++ b/src/chasers/chaser_header.cpp @@ -0,0 +1,115 @@ +/** + * 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 + +#include +#include +#include + +namespace libbitcoin { +namespace node { + +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + +chaser_header::chaser_header(full_node& node) NOEXCEPT + : node_(node), + strand_(node.service().get_executor()), + subscriber_(strand_), + reporter(node.log), + tracker(node.log) +{ +} + +chaser_header::~chaser_header() NOEXCEPT +{ + BC_ASSERT_MSG(stopped(), "The header chaser was not stopped."); + if (!stopped()) { LOGF("~chaser_header is not stopped."); } +} + +void chaser_header::start(network::result_handler&& handler) NOEXCEPT +{ + if (!stopped()) + { + handler(network::error::operation_failed); + return; + } + + stopped_.store(false); + handler(network::error::success); +} + +void chaser_header::stop() NOEXCEPT +{ + stopped_.store(true); + + // The chaser_header can be deleted once threadpool joins after this call. + boost::asio::post(strand_, + std::bind(&chaser_header::do_stop, this)); +} + +chaser_header::object_key chaser_header::subscribe(notifier&& handler) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + const auto key = create_key(); + subscriber_.subscribe(std::move(handler), key); + return key; +} + +// TODO: closing channel notifies itself to desubscribe. +bool chaser_header::notify(object_key key) NOEXCEPT +{ + return subscriber_.notify_one(key, network::error::success); +} + +bool chaser_header::stopped() const NOEXCEPT +{ + return stopped_.load(); +} + +bool chaser_header::stranded() const NOEXCEPT +{ + return strand_.running_in_this_thread(); +} + +// private +chaser_header::object_key chaser_header::create_key() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + if (is_zero(++keys_)) + { + BC_ASSERT_MSG(false, "overflow"); + LOGF("Chaser object overflow."); + } + + return keys_; +} + +// private +void chaser_header::do_stop() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + subscriber_.stop(network::error::service_stopped); +} + +BC_POP_WARNING() + +} // namespace database +} // namespace libbitcoin diff --git a/src/chasers/chaser_transaction.cpp b/src/chasers/chaser_transaction.cpp new file mode 100644 index 00000000..8de97975 --- /dev/null +++ b/src/chasers/chaser_transaction.cpp @@ -0,0 +1,115 @@ +/** + * 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 + +#include +#include +#include + +namespace libbitcoin { +namespace node { + +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + +chaser_transaction::chaser_transaction(full_node& node) NOEXCEPT + : node_(node), + strand_(node.service().get_executor()), + subscriber_(strand_), + reporter(node.log), + tracker(node.log) +{ +} + +chaser_transaction::~chaser_transaction() NOEXCEPT +{ + BC_ASSERT_MSG(stopped(), "The transaction chaser was not stopped."); + if (!stopped()) { LOGF("~chaser_transaction is not stopped."); } +} + +void chaser_transaction::start(network::result_handler&& handler) NOEXCEPT +{ + if (!stopped()) + { + handler(network::error::operation_failed); + return; + } + + stopped_.store(false); + handler(network::error::success); +} + +void chaser_transaction::stop() NOEXCEPT +{ + stopped_.store(true); + + // The chaser_transaction can be deleted once threadpool joins after this call. + boost::asio::post(strand_, + std::bind(&chaser_transaction::do_stop, this)); +} + +chaser_transaction::object_key chaser_transaction::subscribe(notifier&& handler) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + const auto key = create_key(); + subscriber_.subscribe(std::move(handler), key); + return key; +} + +// TODO: closing channel notifies itself to desubscribe. +bool chaser_transaction::notify(object_key key) NOEXCEPT +{ + return subscriber_.notify_one(key, network::error::success); +} + +bool chaser_transaction::stopped() const NOEXCEPT +{ + return stopped_.load(); +} + +bool chaser_transaction::stranded() const NOEXCEPT +{ + return strand_.running_in_this_thread(); +} + +// private +chaser_transaction::object_key chaser_transaction::create_key() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + if (is_zero(++keys_)) + { + BC_ASSERT_MSG(false, "overflow"); + LOGF("Chaser object overflow."); + } + + return keys_; +} + +// private +void chaser_transaction::do_stop() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + subscriber_.stop(network::error::service_stopped); +} + +BC_POP_WARNING() + +} // namespace database +} // namespace libbitcoin diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp new file mode 100644 index 00000000..d4375212 --- /dev/null +++ b/src/chasers/chaser_validate.cpp @@ -0,0 +1,115 @@ +/** + * 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 + +#include +#include +#include + +namespace libbitcoin { +namespace node { + +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + +chaser_validate::chaser_validate(full_node& node) NOEXCEPT + : node_(node), + strand_(node.service().get_executor()), + subscriber_(strand_), + reporter(node.log), + tracker(node.log) +{ +} + +chaser_validate::~chaser_validate() NOEXCEPT +{ + BC_ASSERT_MSG(stopped(), "The validation chaser was not stopped."); + if (!stopped()) { LOGF("~chaser_validate is not stopped."); } +} + +void chaser_validate::start(network::result_handler&& handler) NOEXCEPT +{ + if (!stopped()) + { + handler(network::error::operation_failed); + return; + } + + stopped_.store(false); + handler(network::error::success); +} + +void chaser_validate::stop() NOEXCEPT +{ + stopped_.store(true); + + // The chaser_validate can be deleted once threadpool joins after this call. + boost::asio::post(strand_, + std::bind(&chaser_validate::do_stop, this)); +} + +chaser_validate::object_key chaser_validate::subscribe(notifier&& handler) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + const auto key = create_key(); + subscriber_.subscribe(std::move(handler), key); + return key; +} + +// TODO: closing channel notifies itself to desubscribe. +bool chaser_validate::notify(object_key key) NOEXCEPT +{ + return subscriber_.notify_one(key, network::error::success); +} + +bool chaser_validate::stopped() const NOEXCEPT +{ + return stopped_.load(); +} + +bool chaser_validate::stranded() const NOEXCEPT +{ + return strand_.running_in_this_thread(); +} + +// private +chaser_validate::object_key chaser_validate::create_key() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + if (is_zero(++keys_)) + { + BC_ASSERT_MSG(false, "overflow"); + LOGF("Chaser object overflow."); + } + + return keys_; +} + +// private +void chaser_validate::do_stop() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + subscriber_.stop(network::error::service_stopped); +} + +BC_POP_WARNING() + +} // namespace database +} // namespace libbitcoin diff --git a/src/protocols/session.cpp b/src/protocols/session.cpp index cbb8c68f..a1db90c8 100644 --- a/src/protocols/session.cpp +++ b/src/protocols/session.cpp @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#include +#include #include #include From ea1b8266ca43a8a1cecf18f30d63e811722ab3d7 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 9 Feb 2024 02:28:23 -0500 Subject: [PATCH 21/27] Organize files and dependencies between protocol/session. --- Makefile.am | 9 +- builds/cmake/CMakeLists.txt | 5 +- .../libbitcoin-node/libbitcoin-node.vcxproj | 9 +- .../libbitcoin-node.vcxproj.filters | 25 ++-- include/bitcoin/node.hpp | 4 +- include/bitcoin/node/chasers/chaser.hpp | 10 +- ...chaser_validate.hpp => chaser_connect.hpp} | 14 +-- include/bitcoin/node/chasers/chasers.hpp | 2 +- include/bitcoin/node/protocols/protocol.hpp | 6 +- .../node/protocols/protocol_block_in.hpp | 2 - .../protocols/protocol_header_in_31800.hpp | 1 - include/bitcoin/node/protocols/protocols.hpp | 1 - .../node/{protocols => sessions}/attach.hpp | 15 +-- include/bitcoin/node/sessions/session.hpp | 6 +- .../bitcoin/node/sessions/session_inbound.hpp | 3 +- .../bitcoin/node/sessions/session_manual.hpp | 3 +- .../node/sessions/session_outbound.hpp | 5 +- include/bitcoin/node/sessions/sessions.hpp | 6 +- src/chasers/chaser.cpp | 115 ++++++++++++++++++ ...chaser_validate.cpp => chaser_connect.cpp} | 30 ++--- src/protocols/protocol.cpp | 1 + src/{protocols => sessions}/session.cpp | 4 + 22 files changed, 195 insertions(+), 81 deletions(-) rename include/bitcoin/node/chasers/{chaser_validate.hpp => chaser_connect.hpp} (89%) rename include/bitcoin/node/{protocols => sessions}/attach.hpp (83%) create mode 100644 src/chasers/chaser.cpp rename src/chasers/{chaser_validate.cpp => chaser_connect.cpp} (71%) rename src/{protocols => sessions}/session.cpp (97%) diff --git a/Makefile.am b/Makefile.am index c2ca8942..3a5330bc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,11 +40,12 @@ src_libbitcoin_node_la_SOURCES = \ src/full_node.cpp \ src/parser.cpp \ src/settings.cpp \ + src/chasers/chaser.cpp \ src/chasers/chaser_check.cpp \ src/chasers/chaser_confirm.cpp \ + src/chasers/chaser_connect.cpp \ src/chasers/chaser_header.cpp \ src/chasers/chaser_transaction.cpp \ - src/chasers/chaser_validate.cpp \ src/protocols/protocol.cpp \ src/protocols/protocol_block_in.cpp \ src/protocols/protocol_block_out.cpp \ @@ -54,7 +55,7 @@ src_libbitcoin_node_la_SOURCES = \ src/protocols/protocol_header_out_70012.cpp \ src/protocols/protocol_transaction_in.cpp \ src/protocols/protocol_transaction_out.cpp \ - src/protocols/session.cpp \ + src/sessions/session.cpp \ src/sessions/session_inbound.cpp \ src/sessions/session_manual.cpp \ src/sessions/session_outbound.cpp @@ -117,14 +118,13 @@ include_bitcoin_node_chasers_HEADERS = \ include/bitcoin/node/chasers/chaser.hpp \ include/bitcoin/node/chasers/chaser_check.hpp \ include/bitcoin/node/chasers/chaser_confirm.hpp \ + include/bitcoin/node/chasers/chaser_connect.hpp \ include/bitcoin/node/chasers/chaser_header.hpp \ include/bitcoin/node/chasers/chaser_transaction.hpp \ - include/bitcoin/node/chasers/chaser_validate.hpp \ include/bitcoin/node/chasers/chasers.hpp include_bitcoin_node_protocolsdir = ${includedir}/bitcoin/node/protocols include_bitcoin_node_protocols_HEADERS = \ - include/bitcoin/node/protocols/attach.hpp \ include/bitcoin/node/protocols/protocol.hpp \ include/bitcoin/node/protocols/protocol_block_in.hpp \ include/bitcoin/node/protocols/protocol_block_out.hpp \ @@ -138,6 +138,7 @@ include_bitcoin_node_protocols_HEADERS = \ include_bitcoin_node_sessionsdir = ${includedir}/bitcoin/node/sessions include_bitcoin_node_sessions_HEADERS = \ + include/bitcoin/node/sessions/attach.hpp \ include/bitcoin/node/sessions/session.hpp \ include/bitcoin/node/sessions/session_inbound.hpp \ include/bitcoin/node/sessions/session_manual.hpp \ diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt index a6f4b02a..f6b9248a 100644 --- a/builds/cmake/CMakeLists.txt +++ b/builds/cmake/CMakeLists.txt @@ -250,11 +250,12 @@ add_library( ${CANONICAL_LIB_NAME} "../../src/full_node.cpp" "../../src/parser.cpp" "../../src/settings.cpp" + "../../src/chasers/chaser.cpp" "../../src/chasers/chaser_check.cpp" "../../src/chasers/chaser_confirm.cpp" + "../../src/chasers/chaser_connect.cpp" "../../src/chasers/chaser_header.cpp" "../../src/chasers/chaser_transaction.cpp" - "../../src/chasers/chaser_validate.cpp" "../../src/protocols/protocol.cpp" "../../src/protocols/protocol_block_in.cpp" "../../src/protocols/protocol_block_out.cpp" @@ -264,7 +265,7 @@ add_library( ${CANONICAL_LIB_NAME} "../../src/protocols/protocol_header_out_70012.cpp" "../../src/protocols/protocol_transaction_in.cpp" "../../src/protocols/protocol_transaction_out.cpp" - "../../src/protocols/session.cpp" + "../../src/sessions/session.cpp" "../../src/sessions/session_inbound.cpp" "../../src/sessions/session_manual.cpp" "../../src/sessions/session_outbound.cpp" ) diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj index 766734ab..ee997d55 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj @@ -73,11 +73,12 @@ + + - @@ -91,7 +92,7 @@ - + @@ -102,16 +103,15 @@ + - - @@ -122,6 +122,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters index 0e6f8eb1..b97d84a4 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters @@ -42,19 +42,22 @@ + + src\chasers + src\chasers src\chasers - + src\chasers - + src\chasers - + src\chasers @@ -96,8 +99,8 @@ src\protocols - - src\protocols + + src\sessions src\sessions @@ -125,13 +128,13 @@ include\bitcoin\node\chasers - + include\bitcoin\node\chasers - + include\bitcoin\node\chasers - + include\bitcoin\node\chasers @@ -152,9 +155,6 @@ include\bitcoin\node - - include\bitcoin\node\protocols - include\bitcoin\node\protocols @@ -185,6 +185,9 @@ include\bitcoin\node\protocols + + include\bitcoin\node\sessions + include\bitcoin\node\sessions diff --git a/include/bitcoin/node.hpp b/include/bitcoin/node.hpp index bcf5f962..69a8361d 100644 --- a/include/bitcoin/node.hpp +++ b/include/bitcoin/node.hpp @@ -26,11 +26,10 @@ #include #include #include +#include #include #include -#include #include -#include #include #include #include @@ -41,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/include/bitcoin/node/chasers/chaser.hpp b/include/bitcoin/node/chasers/chaser.hpp index 0c60af0d..46f29412 100644 --- a/include/bitcoin/node/chasers/chaser.hpp +++ b/include/bitcoin/node/chasers/chaser.hpp @@ -30,7 +30,6 @@ class full_node; /// Abstract base chaser. /// Each chaser operates on its own strand, implemented here, allowing /// concurrent chaser operations to the extent that threads are available. -/// class BCN_API chaser : public network::reporter, protected network::tracker { @@ -40,11 +39,6 @@ class BCN_API chaser typedef subscriber::handler notifier; DELETE_COPY_MOVE(chaser); - /// Construct an instance. - /// ----------------------------------------------------------------------- - chaser(full_node& node) NOEXCEPT; - ~chaser() NOEXCEPT; - /// Start/stop. /// ----------------------------------------------------------------------- void start(network::result_handler&& handler) NOEXCEPT; @@ -60,6 +54,10 @@ class BCN_API chaser bool stopped() const NOEXCEPT; bool stranded() const NOEXCEPT; +protected: + chaser(full_node& node) NOEXCEPT; + virtual ~chaser() NOEXCEPT; + private: object_key create_key() NOEXCEPT; void do_stop() NOEXCEPT; diff --git a/include/bitcoin/node/chasers/chaser_validate.hpp b/include/bitcoin/node/chasers/chaser_connect.hpp similarity index 89% rename from include/bitcoin/node/chasers/chaser_validate.hpp rename to include/bitcoin/node/chasers/chaser_connect.hpp index b2328d6d..9dfff6ff 100644 --- a/include/bitcoin/node/chasers/chaser_validate.hpp +++ b/include/bitcoin/node/chasers/chaser_connect.hpp @@ -16,8 +16,8 @@ * 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_VALIDATE_HPP -#define LIBBITCOIN_NODE_CHASERS_CHASER_VALIDATE_HPP +#ifndef LIBBITCOIN_NODE_CHASERS_CHASER_CONNECT_HPP +#define LIBBITCOIN_NODE_CHASERS_CHASER_CONNECT_HPP #include #include @@ -29,19 +29,19 @@ class full_node; /// Chase down blocks in the the candidate header chain for validation. /// Notify subscribers with the "block connected" event. -class BCN_API chaser_validate - : public network::reporter, protected network::tracker +class BCN_API chaser_connect + : public network::reporter, protected network::tracker { public: typedef uint64_t object_key; typedef network::desubscriber subscriber; typedef subscriber::handler notifier; - DELETE_COPY_MOVE(chaser_validate); + DELETE_COPY_MOVE(chaser_connect); /// Construct an instance. /// ----------------------------------------------------------------------- - chaser_validate(full_node& node) NOEXCEPT; - ~chaser_validate() NOEXCEPT; + chaser_connect(full_node& node) NOEXCEPT; + ~chaser_connect() NOEXCEPT; /// Start/stop. /// ----------------------------------------------------------------------- diff --git a/include/bitcoin/node/chasers/chasers.hpp b/include/bitcoin/node/chasers/chasers.hpp index 102b6807..b4b97f70 100644 --- a/include/bitcoin/node/chasers/chasers.hpp +++ b/include/bitcoin/node/chasers/chasers.hpp @@ -22,8 +22,8 @@ #include #include #include +#include #include #include -#include #endif diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index 81b79736..07054939 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -24,8 +24,9 @@ #include #include -// Individual inclusion to prevent cycle. +// Individual inclusion to prevent cycle (can't forward declare). #include +////class session; namespace libbitcoin { namespace node { @@ -34,6 +35,9 @@ namespace node { class BCN_API protocol : public network::protocol { +public: + DELETE_COPY_MOVE(protocol); + protected: typedef network::channel::ptr channel_ptr; diff --git a/include/bitcoin/node/protocols/protocol_block_in.hpp b/include/bitcoin/node/protocols/protocol_block_in.hpp index 8d7c6a24..b299bcf2 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -19,8 +19,6 @@ #ifndef LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_IN_HPP #define LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_IN_HPP -#include -#include #include #include #include diff --git a/include/bitcoin/node/protocols/protocol_header_in_31800.hpp b/include/bitcoin/node/protocols/protocol_header_in_31800.hpp index 865ec7ab..96263b7e 100644 --- a/include/bitcoin/node/protocols/protocol_header_in_31800.hpp +++ b/include/bitcoin/node/protocols/protocol_header_in_31800.hpp @@ -19,7 +19,6 @@ #ifndef LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_HEADER_IN_31800_HPP #define LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_HEADER_IN_31800_HPP -#include #include #include #include diff --git a/include/bitcoin/node/protocols/protocols.hpp b/include/bitcoin/node/protocols/protocols.hpp index 83a3a374..68f51c14 100644 --- a/include/bitcoin/node/protocols/protocols.hpp +++ b/include/bitcoin/node/protocols/protocols.hpp @@ -19,7 +19,6 @@ #ifndef LIBBITCOIN_NODE_PROTOCOLS_PROTOCOLS_HPP #define LIBBITCOIN_NODE_PROTOCOLS_PROTOCOLS_HPP -#include #include #include #include diff --git a/include/bitcoin/node/protocols/attach.hpp b/include/bitcoin/node/sessions/attach.hpp similarity index 83% rename from include/bitcoin/node/protocols/attach.hpp rename to include/bitcoin/node/sessions/attach.hpp index e3cdc125..78b83363 100644 --- a/include/bitcoin/node/protocols/attach.hpp +++ b/include/bitcoin/node/sessions/attach.hpp @@ -16,23 +16,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#ifndef LIBBITCOIN_NODE_PROTOCOLS_MIXIN_HPP -#define LIBBITCOIN_NODE_PROTOCOLS_MIXIN_HPP +#ifndef LIBBITCOIN_NODE_SESSIONS_ATTACH_HPP +#define LIBBITCOIN_NODE_SESSIONS_ATTACH_HPP #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include - -// Individual inclusion to prevent cycle. +#include #include namespace libbitcoin { diff --git a/include/bitcoin/node/sessions/session.hpp b/include/bitcoin/node/sessions/session.hpp index c90377f8..86772007 100644 --- a/include/bitcoin/node/sessions/session.hpp +++ b/include/bitcoin/node/sessions/session.hpp @@ -30,6 +30,8 @@ namespace node { class BCN_API session { public: + DELETE_COPY_MOVE(session); + /// Handle performance, base returns false (implied terminate). virtual void performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) NOEXCEPT; @@ -41,11 +43,13 @@ class BCN_API session full_node::query& archive() const NOEXCEPT; protected: - DEFAULT_COPY_MOVE_DESTRUCT(session); /// Construct/destruct the session. session(full_node& node) NOEXCEPT; + /// Asserts that session is stopped. + virtual ~session() NOEXCEPT; + private: // This is thread safe (mostly). full_node& node_; diff --git a/include/bitcoin/node/sessions/session_inbound.hpp b/include/bitcoin/node/sessions/session_inbound.hpp index e0342d72..d8a6ec35 100644 --- a/include/bitcoin/node/sessions/session_inbound.hpp +++ b/include/bitcoin/node/sessions/session_inbound.hpp @@ -20,8 +20,7 @@ #define LIBBITCOIN_NODE_SESSIONS_SESSION_INBOUND_HPP #include -#include -#include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/sessions/session_manual.hpp b/include/bitcoin/node/sessions/session_manual.hpp index 989c0b11..a95c254b 100644 --- a/include/bitcoin/node/sessions/session_manual.hpp +++ b/include/bitcoin/node/sessions/session_manual.hpp @@ -20,8 +20,7 @@ #define LIBBITCOIN_NODE_SESSIONS_SESSION_MANUAL_HPP #include -#include -#include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/sessions/session_outbound.hpp b/include/bitcoin/node/sessions/session_outbound.hpp index f2718583..a506cc64 100644 --- a/include/bitcoin/node/sessions/session_outbound.hpp +++ b/include/bitcoin/node/sessions/session_outbound.hpp @@ -23,8 +23,7 @@ #include #include #include -#include -#include +#include namespace libbitcoin { namespace node { @@ -35,7 +34,7 @@ class BCN_API session_outbound public: session_outbound(full_node& node, uint64_t identifier) NOEXCEPT; - void performance(uint64_t channel, uint64_t speed, + virtual void performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) NOEXCEPT override; protected: diff --git a/include/bitcoin/node/sessions/sessions.hpp b/include/bitcoin/node/sessions/sessions.hpp index 40181791..0abbc44b 100644 --- a/include/bitcoin/node/sessions/sessions.hpp +++ b/include/bitcoin/node/sessions/sessions.hpp @@ -19,10 +19,8 @@ #ifndef LIBBITCOIN_NODE_SESSIONS_SESSIONS_HPP #define LIBBITCOIN_NODE_SESSIONS_SESSIONS_HPP -// session.hpp must be included by /protocols/attach.hpp -// and therefore cannot be included here (avoids circularity). -// However the header is included in /sessions for taxonomic consistency. -////#include +#include +#include #include #include #include diff --git a/src/chasers/chaser.cpp b/src/chasers/chaser.cpp new file mode 100644 index 00000000..1ea394f8 --- /dev/null +++ b/src/chasers/chaser.cpp @@ -0,0 +1,115 @@ +/** + * 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 + +#include +#include +#include + +namespace libbitcoin { +namespace node { + +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + +chaser::chaser(full_node& node) NOEXCEPT + : node_(node), + strand_(node.service().get_executor()), + subscriber_(strand_), + reporter(node.log), + tracker(node.log) +{ +} + +chaser::~chaser() NOEXCEPT +{ + BC_ASSERT_MSG(stopped(), "The chaser was not stopped."); + if (!stopped()) { LOGF("~chaser is not stopped."); } +} + +void chaser::start(network::result_handler&& handler) NOEXCEPT +{ + if (!stopped()) + { + handler(network::error::operation_failed); + return; + } + + stopped_.store(false); + handler(network::error::success); +} + +void chaser::stop() NOEXCEPT +{ + stopped_.store(true); + + // The chaser can be deleted once threadpool joins after this call. + boost::asio::post(strand_, + std::bind(&chaser::do_stop, this)); +} + +chaser::object_key chaser::subscribe(notifier&& handler) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + const auto key = create_key(); + subscriber_.subscribe(std::move(handler), key); + return key; +} + +// TODO: closing channel notifies itself to desubscribe. +bool chaser::notify(object_key key) NOEXCEPT +{ + return subscriber_.notify_one(key, network::error::success); +} + +bool chaser::stopped() const NOEXCEPT +{ + return stopped_.load(); +} + +bool chaser::stranded() const NOEXCEPT +{ + return strand_.running_in_this_thread(); +} + +// private +chaser::object_key chaser::create_key() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + if (is_zero(++keys_)) + { + BC_ASSERT_MSG(false, "overflow"); + LOGF("Chaser object overflow."); + } + + return keys_; +} + +// private +void chaser::do_stop() NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "strand"); + + subscriber_.stop(network::error::service_stopped); +} + +BC_POP_WARNING() + +} // namespace database +} // namespace libbitcoin diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_connect.cpp similarity index 71% rename from src/chasers/chaser_validate.cpp rename to src/chasers/chaser_connect.cpp index d4375212..6dcf8b43 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_connect.cpp @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#include +#include #include #include @@ -27,22 +27,22 @@ namespace node { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) -chaser_validate::chaser_validate(full_node& node) NOEXCEPT +chaser_connect::chaser_connect(full_node& node) NOEXCEPT : node_(node), strand_(node.service().get_executor()), subscriber_(strand_), reporter(node.log), - tracker(node.log) + tracker(node.log) { } -chaser_validate::~chaser_validate() NOEXCEPT +chaser_connect::~chaser_connect() NOEXCEPT { BC_ASSERT_MSG(stopped(), "The validation chaser was not stopped."); - if (!stopped()) { LOGF("~chaser_validate is not stopped."); } + if (!stopped()) { LOGF("~chaser_connect is not stopped."); } } -void chaser_validate::start(network::result_handler&& handler) NOEXCEPT +void chaser_connect::start(network::result_handler&& handler) NOEXCEPT { if (!stopped()) { @@ -54,16 +54,16 @@ void chaser_validate::start(network::result_handler&& handler) NOEXCEPT handler(network::error::success); } -void chaser_validate::stop() NOEXCEPT +void chaser_connect::stop() NOEXCEPT { stopped_.store(true); - // The chaser_validate can be deleted once threadpool joins after this call. + // The chaser_connect can be deleted once threadpool joins after this call. boost::asio::post(strand_, - std::bind(&chaser_validate::do_stop, this)); + std::bind(&chaser_connect::do_stop, this)); } -chaser_validate::object_key chaser_validate::subscribe(notifier&& handler) NOEXCEPT +chaser_connect::object_key chaser_connect::subscribe(notifier&& handler) NOEXCEPT { BC_ASSERT_MSG(stranded(), "strand"); const auto key = create_key(); @@ -72,23 +72,23 @@ chaser_validate::object_key chaser_validate::subscribe(notifier&& handler) NOEXC } // TODO: closing channel notifies itself to desubscribe. -bool chaser_validate::notify(object_key key) NOEXCEPT +bool chaser_connect::notify(object_key key) NOEXCEPT { return subscriber_.notify_one(key, network::error::success); } -bool chaser_validate::stopped() const NOEXCEPT +bool chaser_connect::stopped() const NOEXCEPT { return stopped_.load(); } -bool chaser_validate::stranded() const NOEXCEPT +bool chaser_connect::stranded() const NOEXCEPT { return strand_.running_in_this_thread(); } // private -chaser_validate::object_key chaser_validate::create_key() NOEXCEPT +chaser_connect::object_key chaser_connect::create_key() NOEXCEPT { BC_ASSERT_MSG(stranded(), "strand"); @@ -102,7 +102,7 @@ chaser_validate::object_key chaser_validate::create_key() NOEXCEPT } // private -void chaser_validate::do_stop() NOEXCEPT +void chaser_connect::do_stop() NOEXCEPT { BC_ASSERT_MSG(stranded(), "strand"); diff --git a/src/protocols/protocol.cpp b/src/protocols/protocol.cpp index 749d4449..21ac18c6 100644 --- a/src/protocols/protocol.cpp +++ b/src/protocols/protocol.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace libbitcoin { namespace node { diff --git a/src/protocols/session.cpp b/src/sessions/session.cpp similarity index 97% rename from src/protocols/session.cpp rename to src/sessions/session.cpp index a1db90c8..bb5516a7 100644 --- a/src/protocols/session.cpp +++ b/src/sessions/session.cpp @@ -32,6 +32,10 @@ session::session(full_node& node) NOEXCEPT { } +session::~session() NOEXCEPT +{ +} + void session::performance(uint64_t, uint64_t, network::result_handler&& handler) NOEXCEPT { From 4b93e02169b87e4d2965cdbc8334cb9aa402920b Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 9 Feb 2024 02:51:53 -0500 Subject: [PATCH 22/27] Clean up chaser stubs. --- include/bitcoin/node/chasers/chaser.hpp | 3 +- include/bitcoin/node/chasers/chaser_check.hpp | 39 +-------- .../bitcoin/node/chasers/chaser_confirm.hpp | 39 +-------- .../bitcoin/node/chasers/chaser_connect.hpp | 39 +-------- .../bitcoin/node/chasers/chaser_header.hpp | 39 +-------- .../node/chasers/chaser_transaction.hpp | 39 +-------- src/chasers/chaser.cpp | 3 +- src/chasers/chaser_check.cpp | 80 +------------------ src/chasers/chaser_confirm.cpp | 80 +------------------ src/chasers/chaser_connect.cpp | 80 +------------------ src/chasers/chaser_header.cpp | 80 +------------------ src/chasers/chaser_transaction.cpp | 80 +------------------ 12 files changed, 23 insertions(+), 578 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser.hpp b/include/bitcoin/node/chasers/chaser.hpp index 46f29412..4826e23d 100644 --- a/include/bitcoin/node/chasers/chaser.hpp +++ b/include/bitcoin/node/chasers/chaser.hpp @@ -31,7 +31,8 @@ class full_node; /// Each chaser operates on its own strand, implemented here, allowing /// concurrent chaser operations to the extent that threads are available. class BCN_API chaser - : public network::reporter, protected network::tracker + : public network::enable_shared_from_base, + public network::reporter { public: typedef uint64_t object_key; diff --git a/include/bitcoin/node/chasers/chaser_check.hpp b/include/bitcoin/node/chasers/chaser_check.hpp index f2d713a0..c103ddf2 100644 --- a/include/bitcoin/node/chasers/chaser_check.hpp +++ b/include/bitcoin/node/chasers/chaser_check.hpp @@ -21,6 +21,7 @@ #include #include +#include namespace libbitcoin { namespace node { @@ -30,46 +31,10 @@ class full_node; /// Chase down blocks for the candidate header chain. /// Notify subscribers with "block checked" event. class BCN_API chaser_check - : public network::reporter, protected network::tracker + : public chaser, protected network::tracker { public: - typedef uint64_t object_key; - typedef network::desubscriber subscriber; - typedef subscriber::handler notifier; - DELETE_COPY_MOVE(chaser_check); - - /// Construct an instance. - /// ----------------------------------------------------------------------- chaser_check(full_node& node) NOEXCEPT; - ~chaser_check() NOEXCEPT; - - /// Start/stop. - /// ----------------------------------------------------------------------- - void start(network::result_handler&& handler) NOEXCEPT; - void stop() NOEXCEPT; - - /// Subscriptions. - /// ----------------------------------------------------------------------- - object_key subscribe(notifier&& handler) NOEXCEPT; - bool notify(object_key key) NOEXCEPT; - - /// Properties. - /// ----------------------------------------------------------------------- - bool stopped() const NOEXCEPT; - bool stranded() const NOEXCEPT; - -private: - object_key create_key() NOEXCEPT; - void do_stop() NOEXCEPT; - - // These are thread safe (mostly). - full_node& node_; - network::asio::strand strand_; - std::atomic_bool stopped_{ true }; - - // These are protected by the strand. - object_key keys_{}; - subscriber subscriber_; }; } // namespace node diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp index dc7f4659..32da4213 100644 --- a/include/bitcoin/node/chasers/chaser_confirm.hpp +++ b/include/bitcoin/node/chasers/chaser_confirm.hpp @@ -21,6 +21,7 @@ #include #include +#include namespace libbitcoin { namespace node { @@ -30,46 +31,10 @@ class full_node; /// Chase down valid blocks for confirmation. /// Notify subscribers with "block confirmed" event. class BCN_API chaser_confirm - : public network::reporter, protected network::tracker + : public chaser, protected network::tracker { public: - typedef uint64_t object_key; - typedef network::desubscriber subscriber; - typedef subscriber::handler notifier; - DELETE_COPY_MOVE(chaser_confirm); - - /// Construct an instance. - /// ----------------------------------------------------------------------- chaser_confirm(full_node& node) NOEXCEPT; - ~chaser_confirm() NOEXCEPT; - - /// Start/stop. - /// ----------------------------------------------------------------------- - void start(network::result_handler&& handler) NOEXCEPT; - void stop() NOEXCEPT; - - /// Subscriptions. - /// ----------------------------------------------------------------------- - object_key subscribe(notifier&& handler) NOEXCEPT; - bool notify(object_key key) NOEXCEPT; - - /// Properties. - /// ----------------------------------------------------------------------- - bool stopped() const NOEXCEPT; - bool stranded() const NOEXCEPT; - -private: - object_key create_key() NOEXCEPT; - void do_stop() NOEXCEPT; - - // These are thread safe (mostly). - full_node& node_; - network::asio::strand strand_; - std::atomic_bool stopped_{ true }; - - // These are protected by the strand. - object_key keys_{}; - subscriber subscriber_; }; } // namespace node diff --git a/include/bitcoin/node/chasers/chaser_connect.hpp b/include/bitcoin/node/chasers/chaser_connect.hpp index 9dfff6ff..925a2c6f 100644 --- a/include/bitcoin/node/chasers/chaser_connect.hpp +++ b/include/bitcoin/node/chasers/chaser_connect.hpp @@ -21,6 +21,7 @@ #include #include +#include namespace libbitcoin { namespace node { @@ -30,46 +31,10 @@ class full_node; /// Chase down blocks in the the candidate header chain for validation. /// Notify subscribers with the "block connected" event. class BCN_API chaser_connect - : public network::reporter, protected network::tracker + : public chaser, protected network::tracker { public: - typedef uint64_t object_key; - typedef network::desubscriber subscriber; - typedef subscriber::handler notifier; - DELETE_COPY_MOVE(chaser_connect); - - /// Construct an instance. - /// ----------------------------------------------------------------------- chaser_connect(full_node& node) NOEXCEPT; - ~chaser_connect() NOEXCEPT; - - /// Start/stop. - /// ----------------------------------------------------------------------- - void start(network::result_handler&& handler) NOEXCEPT; - void stop() NOEXCEPT; - - /// Subscriptions. - /// ----------------------------------------------------------------------- - object_key subscribe(notifier&& handler) NOEXCEPT; - bool notify(object_key key) NOEXCEPT; - - /// Properties. - /// ----------------------------------------------------------------------- - bool stopped() const NOEXCEPT; - bool stranded() const NOEXCEPT; - -private: - object_key create_key() NOEXCEPT; - void do_stop() NOEXCEPT; - - // These are thread safe (mostly). - full_node& node_; - network::asio::strand strand_; - std::atomic_bool stopped_{ true }; - - // These are protected by the strand. - object_key keys_{}; - subscriber subscriber_; }; } // namespace node diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp index 4634c3aa..4e2658ac 100644 --- a/include/bitcoin/node/chasers/chaser_header.hpp +++ b/include/bitcoin/node/chasers/chaser_header.hpp @@ -21,6 +21,7 @@ #include #include +#include namespace libbitcoin { namespace node { @@ -30,46 +31,10 @@ class full_node; /// Chase down stronger header branches for the candidate chain. /// Notify subscribers with "strong header" event. class BCN_API chaser_header - : public network::reporter, protected network::tracker + : public chaser, protected network::tracker { public: - typedef uint64_t object_key; - typedef network::desubscriber subscriber; - typedef subscriber::handler notifier; - DELETE_COPY_MOVE(chaser_header); - - /// Construct an instance. - /// ----------------------------------------------------------------------- chaser_header(full_node& node) NOEXCEPT; - ~chaser_header() NOEXCEPT; - - /// Start/stop. - /// ----------------------------------------------------------------------- - void start(network::result_handler&& handler) NOEXCEPT; - void stop() NOEXCEPT; - - /// Subscriptions. - /// ----------------------------------------------------------------------- - object_key subscribe(notifier&& handler) NOEXCEPT; - bool notify(object_key key) NOEXCEPT; - - /// Properties. - /// ----------------------------------------------------------------------- - bool stopped() const NOEXCEPT; - bool stranded() const NOEXCEPT; - -private: - object_key create_key() NOEXCEPT; - void do_stop() NOEXCEPT; - - // These are thread safe (mostly). - full_node& node_; - network::asio::strand strand_; - std::atomic_bool stopped_{ true }; - - // These are protected by the strand. - object_key keys_{}; - subscriber subscriber_; }; } // namespace node diff --git a/include/bitcoin/node/chasers/chaser_transaction.hpp b/include/bitcoin/node/chasers/chaser_transaction.hpp index 90eb9981..dd5a5ac3 100644 --- a/include/bitcoin/node/chasers/chaser_transaction.hpp +++ b/include/bitcoin/node/chasers/chaser_transaction.hpp @@ -21,6 +21,7 @@ #include #include +#include namespace libbitcoin { namespace node { @@ -29,46 +30,10 @@ class full_node; /// Chase down unconfirmed transactions. class BCN_API chaser_transaction - : public network::reporter, protected network::tracker + : public chaser, protected network::tracker { public: - typedef uint64_t object_key; - typedef network::desubscriber subscriber; - typedef subscriber::handler notifier; - DELETE_COPY_MOVE(chaser_transaction); - - /// Construct an instance. - /// ----------------------------------------------------------------------- chaser_transaction(full_node& node) NOEXCEPT; - ~chaser_transaction() NOEXCEPT; - - /// Start/stop. - /// ----------------------------------------------------------------------- - void start(network::result_handler&& handler) NOEXCEPT; - void stop() NOEXCEPT; - - /// Subscriptions. - /// ----------------------------------------------------------------------- - object_key subscribe(notifier&& handler) NOEXCEPT; - bool notify(object_key key) NOEXCEPT; - - /// Properties. - /// ----------------------------------------------------------------------- - bool stopped() const NOEXCEPT; - bool stranded() const NOEXCEPT; - -private: - object_key create_key() NOEXCEPT; - void do_stop() NOEXCEPT; - - // These are thread safe (mostly). - full_node& node_; - network::asio::strand strand_; - std::atomic_bool stopped_{ true }; - - // These are protected by the strand. - object_key keys_{}; - subscriber subscriber_; }; } // namespace node diff --git a/src/chasers/chaser.cpp b/src/chasers/chaser.cpp index 1ea394f8..f0e8c91b 100644 --- a/src/chasers/chaser.cpp +++ b/src/chasers/chaser.cpp @@ -31,8 +31,7 @@ chaser::chaser(full_node& node) NOEXCEPT : node_(node), strand_(node.service().get_executor()), subscriber_(strand_), - reporter(node.log), - tracker(node.log) + reporter(node.log) { } diff --git a/src/chasers/chaser_check.cpp b/src/chasers/chaser_check.cpp index e2cdbf86..19ca1cf6 100644 --- a/src/chasers/chaser_check.cpp +++ b/src/chasers/chaser_check.cpp @@ -18,9 +18,9 @@ */ #include -#include #include #include +#include namespace libbitcoin { namespace node { @@ -28,87 +28,11 @@ namespace node { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) chaser_check::chaser_check(full_node& node) NOEXCEPT - : node_(node), - strand_(node.service().get_executor()), - subscriber_(strand_), - reporter(node.log), + : chaser(node), tracker(node.log) { } -chaser_check::~chaser_check() NOEXCEPT -{ - BC_ASSERT_MSG(stopped(), "The block chaser was not stopped."); - if (!stopped()) { LOGF("~chaser_check is not stopped."); } -} - -void chaser_check::start(network::result_handler&& handler) NOEXCEPT -{ - if (!stopped()) - { - handler(network::error::operation_failed); - return; - } - - stopped_.store(false); - handler(network::error::success); -} - -void chaser_check::stop() NOEXCEPT -{ - stopped_.store(true); - - // The chaser_check can be deleted once threadpool joins after this call. - boost::asio::post(strand_, - std::bind(&chaser_check::do_stop, this)); -} - -chaser_check::object_key chaser_check::subscribe(notifier&& handler) NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - const auto key = create_key(); - subscriber_.subscribe(std::move(handler), key); - return key; -} - -// TODO: closing channel notifies itself to desubscribe. -bool chaser_check::notify(object_key key) NOEXCEPT -{ - return subscriber_.notify_one(key, network::error::success); -} - -bool chaser_check::stopped() const NOEXCEPT -{ - return stopped_.load(); -} - -bool chaser_check::stranded() const NOEXCEPT -{ - return strand_.running_in_this_thread(); -} - -// private -chaser_check::object_key chaser_check::create_key() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - if (is_zero(++keys_)) - { - BC_ASSERT_MSG(false, "overflow"); - LOGF("Chaser object overflow."); - } - - return keys_; -} - -// private -void chaser_check::do_stop() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - subscriber_.stop(network::error::service_stopped); -} - BC_POP_WARNING() } // namespace database diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index b6b65be0..7ab99e2a 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -18,9 +18,9 @@ */ #include -#include #include #include +#include namespace libbitcoin { namespace node { @@ -28,87 +28,11 @@ namespace node { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT - : node_(node), - strand_(node.service().get_executor()), - subscriber_(strand_), - reporter(node.log), + : chaser(node), tracker(node.log) { } -chaser_confirm::~chaser_confirm() NOEXCEPT -{ - BC_ASSERT_MSG(stopped(), "The confirmation chaser was not stopped."); - if (!stopped()) { LOGF("~chaser_confirm is not stopped."); } -} - -void chaser_confirm::start(network::result_handler&& handler) NOEXCEPT -{ - if (!stopped()) - { - handler(network::error::operation_failed); - return; - } - - stopped_.store(false); - handler(network::error::success); -} - -void chaser_confirm::stop() NOEXCEPT -{ - stopped_.store(true); - - // The chaser_confirm can be deleted once threadpool joins after this call. - boost::asio::post(strand_, - std::bind(&chaser_confirm::do_stop, this)); -} - -chaser_confirm::object_key chaser_confirm::subscribe(notifier&& handler) NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - const auto key = create_key(); - subscriber_.subscribe(std::move(handler), key); - return key; -} - -// TODO: closing channel notifies itself to desubscribe. -bool chaser_confirm::notify(object_key key) NOEXCEPT -{ - return subscriber_.notify_one(key, network::error::success); -} - -bool chaser_confirm::stopped() const NOEXCEPT -{ - return stopped_.load(); -} - -bool chaser_confirm::stranded() const NOEXCEPT -{ - return strand_.running_in_this_thread(); -} - -// private -chaser_confirm::object_key chaser_confirm::create_key() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - if (is_zero(++keys_)) - { - BC_ASSERT_MSG(false, "overflow"); - LOGF("Chaser object overflow."); - } - - return keys_; -} - -// private -void chaser_confirm::do_stop() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - subscriber_.stop(network::error::service_stopped); -} - BC_POP_WARNING() } // namespace database diff --git a/src/chasers/chaser_connect.cpp b/src/chasers/chaser_connect.cpp index 6dcf8b43..f850b1ec 100644 --- a/src/chasers/chaser_connect.cpp +++ b/src/chasers/chaser_connect.cpp @@ -18,9 +18,9 @@ */ #include -#include #include #include +#include namespace libbitcoin { namespace node { @@ -28,87 +28,11 @@ namespace node { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) chaser_connect::chaser_connect(full_node& node) NOEXCEPT - : node_(node), - strand_(node.service().get_executor()), - subscriber_(strand_), - reporter(node.log), + : chaser(node), tracker(node.log) { } -chaser_connect::~chaser_connect() NOEXCEPT -{ - BC_ASSERT_MSG(stopped(), "The validation chaser was not stopped."); - if (!stopped()) { LOGF("~chaser_connect is not stopped."); } -} - -void chaser_connect::start(network::result_handler&& handler) NOEXCEPT -{ - if (!stopped()) - { - handler(network::error::operation_failed); - return; - } - - stopped_.store(false); - handler(network::error::success); -} - -void chaser_connect::stop() NOEXCEPT -{ - stopped_.store(true); - - // The chaser_connect can be deleted once threadpool joins after this call. - boost::asio::post(strand_, - std::bind(&chaser_connect::do_stop, this)); -} - -chaser_connect::object_key chaser_connect::subscribe(notifier&& handler) NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - const auto key = create_key(); - subscriber_.subscribe(std::move(handler), key); - return key; -} - -// TODO: closing channel notifies itself to desubscribe. -bool chaser_connect::notify(object_key key) NOEXCEPT -{ - return subscriber_.notify_one(key, network::error::success); -} - -bool chaser_connect::stopped() const NOEXCEPT -{ - return stopped_.load(); -} - -bool chaser_connect::stranded() const NOEXCEPT -{ - return strand_.running_in_this_thread(); -} - -// private -chaser_connect::object_key chaser_connect::create_key() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - if (is_zero(++keys_)) - { - BC_ASSERT_MSG(false, "overflow"); - LOGF("Chaser object overflow."); - } - - return keys_; -} - -// private -void chaser_connect::do_stop() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - subscriber_.stop(network::error::service_stopped); -} - BC_POP_WARNING() } // namespace database diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index d33099d7..4b898ef4 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -18,9 +18,9 @@ */ #include -#include #include #include +#include namespace libbitcoin { namespace node { @@ -28,87 +28,11 @@ namespace node { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) chaser_header::chaser_header(full_node& node) NOEXCEPT - : node_(node), - strand_(node.service().get_executor()), - subscriber_(strand_), - reporter(node.log), + : chaser(node), tracker(node.log) { } -chaser_header::~chaser_header() NOEXCEPT -{ - BC_ASSERT_MSG(stopped(), "The header chaser was not stopped."); - if (!stopped()) { LOGF("~chaser_header is not stopped."); } -} - -void chaser_header::start(network::result_handler&& handler) NOEXCEPT -{ - if (!stopped()) - { - handler(network::error::operation_failed); - return; - } - - stopped_.store(false); - handler(network::error::success); -} - -void chaser_header::stop() NOEXCEPT -{ - stopped_.store(true); - - // The chaser_header can be deleted once threadpool joins after this call. - boost::asio::post(strand_, - std::bind(&chaser_header::do_stop, this)); -} - -chaser_header::object_key chaser_header::subscribe(notifier&& handler) NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - const auto key = create_key(); - subscriber_.subscribe(std::move(handler), key); - return key; -} - -// TODO: closing channel notifies itself to desubscribe. -bool chaser_header::notify(object_key key) NOEXCEPT -{ - return subscriber_.notify_one(key, network::error::success); -} - -bool chaser_header::stopped() const NOEXCEPT -{ - return stopped_.load(); -} - -bool chaser_header::stranded() const NOEXCEPT -{ - return strand_.running_in_this_thread(); -} - -// private -chaser_header::object_key chaser_header::create_key() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - if (is_zero(++keys_)) - { - BC_ASSERT_MSG(false, "overflow"); - LOGF("Chaser object overflow."); - } - - return keys_; -} - -// private -void chaser_header::do_stop() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - subscriber_.stop(network::error::service_stopped); -} - BC_POP_WARNING() } // namespace database diff --git a/src/chasers/chaser_transaction.cpp b/src/chasers/chaser_transaction.cpp index 8de97975..ed3d4328 100644 --- a/src/chasers/chaser_transaction.cpp +++ b/src/chasers/chaser_transaction.cpp @@ -18,9 +18,9 @@ */ #include -#include #include #include +#include namespace libbitcoin { namespace node { @@ -28,87 +28,11 @@ namespace node { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) chaser_transaction::chaser_transaction(full_node& node) NOEXCEPT - : node_(node), - strand_(node.service().get_executor()), - subscriber_(strand_), - reporter(node.log), + : chaser(node), tracker(node.log) { } -chaser_transaction::~chaser_transaction() NOEXCEPT -{ - BC_ASSERT_MSG(stopped(), "The transaction chaser was not stopped."); - if (!stopped()) { LOGF("~chaser_transaction is not stopped."); } -} - -void chaser_transaction::start(network::result_handler&& handler) NOEXCEPT -{ - if (!stopped()) - { - handler(network::error::operation_failed); - return; - } - - stopped_.store(false); - handler(network::error::success); -} - -void chaser_transaction::stop() NOEXCEPT -{ - stopped_.store(true); - - // The chaser_transaction can be deleted once threadpool joins after this call. - boost::asio::post(strand_, - std::bind(&chaser_transaction::do_stop, this)); -} - -chaser_transaction::object_key chaser_transaction::subscribe(notifier&& handler) NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - const auto key = create_key(); - subscriber_.subscribe(std::move(handler), key); - return key; -} - -// TODO: closing channel notifies itself to desubscribe. -bool chaser_transaction::notify(object_key key) NOEXCEPT -{ - return subscriber_.notify_one(key, network::error::success); -} - -bool chaser_transaction::stopped() const NOEXCEPT -{ - return stopped_.load(); -} - -bool chaser_transaction::stranded() const NOEXCEPT -{ - return strand_.running_in_this_thread(); -} - -// private -chaser_transaction::object_key chaser_transaction::create_key() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - if (is_zero(++keys_)) - { - BC_ASSERT_MSG(false, "overflow"); - LOGF("Chaser object overflow."); - } - - return keys_; -} - -// private -void chaser_transaction::do_stop() NOEXCEPT -{ - BC_ASSERT_MSG(stranded(), "strand"); - - subscriber_.stop(network::error::service_stopped); -} - BC_POP_WARNING() } // namespace database From 6bd8b909b3918a4897b9e4d78e426c325004d64e Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 9 Feb 2024 02:52:38 -0500 Subject: [PATCH 23/27] Make protocol trackers protected. --- include/bitcoin/node/protocols/protocol_block_in.hpp | 2 +- include/bitcoin/node/protocols/protocol_block_out.hpp | 2 +- include/bitcoin/node/protocols/protocol_header_in_31800.hpp | 2 +- include/bitcoin/node/protocols/protocol_header_in_70012.hpp | 2 +- include/bitcoin/node/protocols/protocol_header_out_31800.hpp | 2 +- include/bitcoin/node/protocols/protocol_header_out_70012.hpp | 2 +- include/bitcoin/node/protocols/protocol_transaction_in.hpp | 2 +- include/bitcoin/node/protocols/protocol_transaction_out.hpp | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/bitcoin/node/protocols/protocol_block_in.hpp b/include/bitcoin/node/protocols/protocol_block_in.hpp index b299bcf2..ab96b25c 100644 --- a/include/bitcoin/node/protocols/protocol_block_in.hpp +++ b/include/bitcoin/node/protocols/protocol_block_in.hpp @@ -28,7 +28,7 @@ namespace node { class BCN_API protocol_block_in : public node::protocol, - network::tracker + protected network::tracker { public: typedef std::shared_ptr ptr; diff --git a/include/bitcoin/node/protocols/protocol_block_out.hpp b/include/bitcoin/node/protocols/protocol_block_out.hpp index a5293322..e9b87b59 100644 --- a/include/bitcoin/node/protocols/protocol_block_out.hpp +++ b/include/bitcoin/node/protocols/protocol_block_out.hpp @@ -28,7 +28,7 @@ namespace node { class BCN_API protocol_block_out : public node::protocol, - network::tracker + protected network::tracker { public: typedef std::shared_ptr ptr; diff --git a/include/bitcoin/node/protocols/protocol_header_in_31800.hpp b/include/bitcoin/node/protocols/protocol_header_in_31800.hpp index 96263b7e..463945a0 100644 --- a/include/bitcoin/node/protocols/protocol_header_in_31800.hpp +++ b/include/bitcoin/node/protocols/protocol_header_in_31800.hpp @@ -28,7 +28,7 @@ namespace node { class BCN_API protocol_header_in_31800 : public node::protocol, - network::tracker + protected network::tracker { public: typedef std::shared_ptr ptr; diff --git a/include/bitcoin/node/protocols/protocol_header_in_70012.hpp b/include/bitcoin/node/protocols/protocol_header_in_70012.hpp index ff269b1e..1f17a04c 100644 --- a/include/bitcoin/node/protocols/protocol_header_in_70012.hpp +++ b/include/bitcoin/node/protocols/protocol_header_in_70012.hpp @@ -28,7 +28,7 @@ namespace node { class BCN_API protocol_header_in_70012 : public protocol_header_in_31800, - network::tracker + protected network::tracker { public: typedef std::shared_ptr ptr; diff --git a/include/bitcoin/node/protocols/protocol_header_out_31800.hpp b/include/bitcoin/node/protocols/protocol_header_out_31800.hpp index dda4c9a3..9e10bdbc 100644 --- a/include/bitcoin/node/protocols/protocol_header_out_31800.hpp +++ b/include/bitcoin/node/protocols/protocol_header_out_31800.hpp @@ -28,7 +28,7 @@ namespace node { class BCN_API protocol_header_out_31800 : public node::protocol, - network::tracker + protected network::tracker { public: typedef std::shared_ptr ptr; diff --git a/include/bitcoin/node/protocols/protocol_header_out_70012.hpp b/include/bitcoin/node/protocols/protocol_header_out_70012.hpp index 83d86305..54d583c0 100644 --- a/include/bitcoin/node/protocols/protocol_header_out_70012.hpp +++ b/include/bitcoin/node/protocols/protocol_header_out_70012.hpp @@ -28,7 +28,7 @@ namespace node { class BCN_API protocol_header_out_70012 : public protocol_header_out_31800, - network::tracker + protected network::tracker { public: typedef std::shared_ptr ptr; diff --git a/include/bitcoin/node/protocols/protocol_transaction_in.hpp b/include/bitcoin/node/protocols/protocol_transaction_in.hpp index 4318e715..d52e0bde 100644 --- a/include/bitcoin/node/protocols/protocol_transaction_in.hpp +++ b/include/bitcoin/node/protocols/protocol_transaction_in.hpp @@ -28,7 +28,7 @@ namespace node { class BCN_API protocol_transaction_in : public node::protocol, - network::tracker + protected network::tracker { public: typedef std::shared_ptr ptr; diff --git a/include/bitcoin/node/protocols/protocol_transaction_out.hpp b/include/bitcoin/node/protocols/protocol_transaction_out.hpp index 7d22b8b5..a9d23559 100644 --- a/include/bitcoin/node/protocols/protocol_transaction_out.hpp +++ b/include/bitcoin/node/protocols/protocol_transaction_out.hpp @@ -28,7 +28,7 @@ namespace node { class BCN_API protocol_transaction_out : public node::protocol, - network::tracker + protected network::tracker { public: typedef std::shared_ptr ptr; From 7d84eee726a9d7a48fbcfe60c0462eaf376a7f16 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 9 Feb 2024 02:53:07 -0500 Subject: [PATCH 24/27] Add protocol empty virtual destructor. --- include/bitcoin/node/protocols/protocol.hpp | 4 +++- src/protocols/protocol.cpp | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/bitcoin/node/protocols/protocol.hpp b/include/bitcoin/node/protocols/protocol.hpp index 07054939..9b95c553 100644 --- a/include/bitcoin/node/protocols/protocol.hpp +++ b/include/bitcoin/node/protocols/protocol.hpp @@ -47,8 +47,10 @@ class BCN_API protocol { } + virtual ~protocol() NOEXCEPT; + /// Report performance, false directs self-terminate. - void performance(uint64_t channel, uint64_t speed, + virtual void performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) const NOEXCEPT; /// Configuration settings for all libraries. diff --git a/src/protocols/protocol.cpp b/src/protocols/protocol.cpp index 21ac18c6..7b07f73e 100644 --- a/src/protocols/protocol.cpp +++ b/src/protocols/protocol.cpp @@ -28,6 +28,10 @@ namespace libbitcoin { namespace node { +protocol::~protocol() NOEXCEPT +{ +} + void protocol::performance(uint64_t channel, uint64_t speed, network::result_handler&& handler) const NOEXCEPT { From 18e24e9562c12f2563b0251426a4716eb89a1d84 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 9 Feb 2024 02:53:25 -0500 Subject: [PATCH 25/27] Add session_outbound tracking. --- include/bitcoin/node/sessions/session_outbound.hpp | 3 ++- src/sessions/session_outbound.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/bitcoin/node/sessions/session_outbound.hpp b/include/bitcoin/node/sessions/session_outbound.hpp index a506cc64..cef4ffad 100644 --- a/include/bitcoin/node/sessions/session_outbound.hpp +++ b/include/bitcoin/node/sessions/session_outbound.hpp @@ -29,7 +29,8 @@ namespace libbitcoin { namespace node { class BCN_API session_outbound - : public attach + : public attach, + protected network::tracker { public: session_outbound(full_node& node, uint64_t identifier) NOEXCEPT; diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp index 71c0097b..f090a0e1 100644 --- a/src/sessions/session_outbound.cpp +++ b/src/sessions/session_outbound.cpp @@ -35,7 +35,8 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) session_outbound::session_outbound(full_node& node, uint64_t identifier) NOEXCEPT - : attach(node, identifier) + : attach(node, identifier), + network::tracker(node.log) { }; From afdc8bf8c0dffab6b7396d126a6b0718f2d46fd4 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 9 Feb 2024 13:59:43 -0500 Subject: [PATCH 26/27] Comments, remove dead code, enable run(). --- include/bitcoin/node/full_node.hpp | 9 +++------ src/full_node.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/bitcoin/node/full_node.hpp b/include/bitcoin/node/full_node.hpp index fe175e3a..a28d65ad 100644 --- a/include/bitcoin/node/full_node.hpp +++ b/include/bitcoin/node/full_node.hpp @@ -36,9 +36,6 @@ class BCN_API full_node typedef database::store store; typedef database::query query; - // TODO: set arguments. - typedef network::desubscriber poll_subscriber; - /// Constructors. /// ----------------------------------------------------------------------- @@ -52,13 +49,13 @@ class BCN_API full_node /// Start the node (seed and manual services). void start(network::result_handler&& handler) NOEXCEPT override; - /// Run the node (inbound and outbound services). - ////void run(network::result_handler&& handler) NOEXCEPT override; + /// Run the node (inbound/outbound services and blockchain chasers). + void run(network::result_handler&& handler) NOEXCEPT override; /// Properties. /// ----------------------------------------------------------------------- - // Configuration settings for all libraries. + /// Configuration settings for all libraries. const configuration& config() const NOEXCEPT; /// Thread safe synchronous archival interface. diff --git a/src/full_node.cpp b/src/full_node.cpp index 6a1f2e8b..c190d375 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -56,10 +56,10 @@ void full_node::start(result_handler&& handler) NOEXCEPT } // Base (p2p) invokes do_run() override. -////void full_node::run(result_handler&& handler) NOEXCEPT -////{ -//// p2p::run(std::move(handler)); -////} +void full_node::run(result_handler&& handler) NOEXCEPT +{ + p2p::run(std::move(handler)); +} void full_node::do_run(const result_handler& handler) NOEXCEPT { From b7964bcd2168d9d7eb2395237a506f00853a0cb3 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 9 Feb 2024 17:20:29 -0500 Subject: [PATCH 27/27] Defer block_in timer initialization until required. --- src/protocols/protocol_block_in.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp index cd7407e0..9fee68e7 100644 --- a/src/protocols/protocol_block_in.cpp +++ b/src/protocols/protocol_block_in.cpp @@ -109,7 +109,6 @@ void protocol_block_in::start() NOEXCEPT if (started()) return; - start_ = steady_clock::now(); state_ = archive().get_confirmed_chain_state(config().bitcoin); if (!state_) @@ -119,7 +118,10 @@ void protocol_block_in::start() NOEXCEPT } if (report_performance_) + { + start_ = steady_clock::now(); performance_timer_->start(BIND1(handle_performance_timer, _1)); + } // There is one persistent common inventory subscription. SUBSCRIBE_CHANNEL2(inventory, handle_receive_inventory, _1, _2);