From 20ce07cb7057251b47f24ebb007d24648679b118 Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Sat, 10 Oct 2026 12:28:45 -0400 Subject: [PATCH 1/2] Add node.batch_silent as the silent payment drain target. --- include/bitcoin/node/chasers/chaser_validate.hpp | 1 + include/bitcoin/node/settings.hpp | 1 + src/chasers/chaser_validate.cpp | 1 + src/chasers/chaser_validate_batch.cpp | 2 +- src/settings.cpp | 1 + test/settings.cpp | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/bitcoin/node/chasers/chaser_validate.hpp b/include/bitcoin/node/chasers/chaser_validate.hpp index 74c5e03f..9cc052c0 100644 --- a/include/bitcoin/node/chasers/chaser_validate.hpp +++ b/include/bitcoin/node/chasers/chaser_validate.hpp @@ -186,6 +186,7 @@ class BCN_API chaser_validate const size_t maximum_backlog_; const size_t maximum_height_; const uint64_t batch_target_; + const uint64_t silent_target_; const bool batch_enabled_; const bool node_witness_; const bool filter_; diff --git a/include/bitcoin/node/settings.hpp b/include/bitcoin/node/settings.hpp index 2f417f6c..e27ba7a4 100644 --- a/include/bitcoin/node/settings.hpp +++ b/include/bitcoin/node/settings.hpp @@ -49,6 +49,7 @@ class BCN_API settings double minimum_fee_rate; double minimum_bump_rate; uint64_t batch_signatures; + uint64_t batch_silent; uint16_t current_connections; uint16_t announcement_cache; uint16_t fee_estimate_horizon; diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index 8bddbd29..e53e9210 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -44,6 +44,7 @@ chaser_validate::chaser_validate(full_node& node) NOEXCEPT maximum_backlog_(node.node_settings().maximum_concurrency_()), maximum_height_(node.node_settings().maximum_height_()), batch_target_(node.node_settings().batch_signatures), + silent_target_(node.node_settings().batch_silent), batch_enabled_(node.node_settings().batch_signatures_enabled() && system::batched::accelerated()), node_witness_(node.node_settings().require_witness), diff --git a/src/chasers/chaser_validate_batch.cpp b/src/chasers/chaser_validate_batch.cpp index 1ad9731f..efd4adf1 100644 --- a/src/chasers/chaser_validate_batch.cpp +++ b/src/chasers/chaser_validate_batch.cpp @@ -293,7 +293,7 @@ bool chaser_validate::is_silent_capturing(const header_link& link) NOEXCEPT bool chaser_validate::is_silent_mature(bool residual) NOEXCEPT { const auto rows = archive().silent_records(silent_bank_.load()); - return is_nonzero(rows) && (residual || rows >= batch_target_); + return is_nonzero(rows) && (residual || rows >= silent_target_); } std::string chaser_validate::log_rate(const std::string& name, diff --git a/src/settings.cpp b/src/settings.cpp index 3e9e9fa8..68765ae6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -41,6 +41,7 @@ settings::settings() NOEXCEPT provide_privacy{ false }, limited_blocks{ false }, batch_signatures{ 0 }, + batch_silent{ 0 }, minimum_fee_rate{ 0.0 }, minimum_bump_rate{ 0.0 }, allowed_deviation{ 1.5 }, diff --git a/test/settings.cpp b/test/settings.cpp index e56df1a8..8dbe0053 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -46,6 +46,7 @@ BOOST_AUTO_TEST_CASE(settings__node__default_context__expected) BOOST_REQUIRE_EQUAL(node.minimum_bump_rate, 0.0); BOOST_REQUIRE_EQUAL(node.allowed_deviation, 1.5); BOOST_REQUIRE_EQUAL(node.batch_signatures, 0_u64); + BOOST_REQUIRE_EQUAL(node.batch_silent, 0_u64); BOOST_REQUIRE_EQUAL(node.current_connections, 10_u16); BOOST_REQUIRE_EQUAL(node.announcement_cache, 42_u16); BOOST_REQUIRE_EQUAL(node.fee_estimate_horizon, 0u); From 75c3fcfe8a5005215d4ee0a611bb5185f39e979c Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Sat, 10 Oct 2026 12:55:30 -0400 Subject: [PATCH 2/2] Rename batch_signatures to batch_verify and enable silent batching by batch_silent. --- .../bitcoin/node/chasers/chaser_validate.hpp | 5 +-- include/bitcoin/node/settings.hpp | 5 +-- src/chasers/chaser_validate.cpp | 33 +++++++++++++------ src/chasers/chaser_validate_batch.cpp | 8 ++--- src/chasers/chaser_validate_capture.cpp | 2 +- src/settings.cpp | 11 +++++-- test/chasers/chaser_validate.cpp | 4 +-- test/settings.cpp | 5 +-- 8 files changed, 47 insertions(+), 26 deletions(-) diff --git a/include/bitcoin/node/chasers/chaser_validate.hpp b/include/bitcoin/node/chasers/chaser_validate.hpp index 9cc052c0..5dc7eada 100644 --- a/include/bitcoin/node/chasers/chaser_validate.hpp +++ b/include/bitcoin/node/chasers/chaser_validate.hpp @@ -185,9 +185,10 @@ class BCN_API chaser_validate const uint64_t initial_subsidy_; const size_t maximum_backlog_; const size_t maximum_height_; - const uint64_t batch_target_; + const uint64_t verify_target_; const uint64_t silent_target_; - const bool batch_enabled_; + const bool verify_enabled_; + const bool silent_enabled_; const bool node_witness_; const bool filter_; }; diff --git a/include/bitcoin/node/settings.hpp b/include/bitcoin/node/settings.hpp index e27ba7a4..54d002d9 100644 --- a/include/bitcoin/node/settings.hpp +++ b/include/bitcoin/node/settings.hpp @@ -48,7 +48,7 @@ class BCN_API settings float allowed_deviation; double minimum_fee_rate; double minimum_bump_rate; - uint64_t batch_signatures; + uint64_t batch_verify; uint64_t batch_silent; uint16_t current_connections; uint16_t announcement_cache; @@ -73,7 +73,8 @@ class BCN_API settings virtual uint64_t services_provided() const NOEXCEPT; virtual uint64_t services_required() const NOEXCEPT; virtual bool fee_estimate_enabled() const NOEXCEPT; - virtual bool batch_signatures_enabled() const NOEXCEPT; + virtual bool batch_verify_enabled() const NOEXCEPT; + virtual bool batch_silent_enabled() const NOEXCEPT; virtual network::steady_clock::duration sample_period() const NOEXCEPT; virtual network::steady_clock::duration compact_timeout() const NOEXCEPT; virtual network::wall_clock::duration currency_window() const NOEXCEPT; diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index e53e9210..b98de698 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -43,9 +43,11 @@ chaser_validate::chaser_validate(full_node& node) NOEXCEPT initial_subsidy_(node.system_settings().initial_subsidy()), maximum_backlog_(node.node_settings().maximum_concurrency_()), maximum_height_(node.node_settings().maximum_height_()), - batch_target_(node.node_settings().batch_signatures), + verify_target_(node.node_settings().batch_verify), silent_target_(node.node_settings().batch_silent), - batch_enabled_(node.node_settings().batch_signatures_enabled() && + verify_enabled_(node.node_settings().batch_verify_enabled() && + system::batched::accelerated()), + silent_enabled_(node.node_settings().batch_silent_enabled() && system::batched::accelerated()), node_witness_(node.node_settings().require_witness), filter_(node.archive().filter_enabled()) @@ -54,10 +56,14 @@ chaser_validate::chaser_validate(full_node& node) NOEXCEPT code chaser_validate::start() NOEXCEPT { - if (node_settings().batch_signatures_enabled() && !batch_enabled_) - LOGN("Signature batching disabled (" - << (system::batched::compiled() ? "no device" : "not compiled") - << ")."); + const auto reason = system::batched::compiled() ? "no device" : + "not compiled"; + + if (node_settings().batch_verify_enabled() && !verify_enabled_) + LOGN("Signature batching disabled (" << reason << ")."); + + if (node_settings().batch_silent_enabled() && !silent_enabled_) + LOGN("Silent batching disabled (" << reason << ")."); set_position(archive().get_fork()); if (const auto ec = start_batch()) @@ -299,15 +305,22 @@ void chaser_validate::complete_block(const code& ec, const header_link& link, // Batch jobs (self-serviced from any thread). // ------------------------------------------------------------------------ - if (closed() || !batch_enabled_) + if (closed()) + return; + + // Silent batch drains when mature or recent, independent of signatures. + if (silent_enabled_) + { + const auto recent = !bypass && is_current_header(link); + process_silent_batch(recent || is_residual()); + } + + if (!verify_enabled_) return; // Capturing disabled when confirmed chain current (and not under bypass). const auto current = !capturing && !bypass; - // Silent batch drains when mature or recent, independent of signatures. - process_silent_batch(current || is_residual()); - if (batched) { process_batch(is_residual()); diff --git a/src/chasers/chaser_validate_batch.cpp b/src/chasers/chaser_validate_batch.cpp index efd4adf1..964a6392 100644 --- a/src/chasers/chaser_validate_batch.cpp +++ b/src/chasers/chaser_validate_batch.cpp @@ -50,7 +50,7 @@ code chaser_validate::start_batch() NOEXCEPT // Prevalid is not a validation state, so dropped blocks validate in // place. - if (!batch_enabled_) + if (!verify_enabled_) { LOGN("Dropping staged batch rows (" << query.prevalid_records(bank) << ")."); @@ -280,14 +280,14 @@ bool chaser_validate::is_mature(bool residual) NOEXCEPT // Verify residuals whenever, and non-residuals when mature. return residual || - (ecdsa >= batch_target_) || - (schnorr >= batch_target_); + (ecdsa >= verify_target_) || + (schnorr >= verify_target_); } // Silent batch is committed while the candidate is not current. bool chaser_validate::is_silent_capturing(const header_link& link) NOEXCEPT { - return batch_enabled_ && !is_current_header(link); + return silent_enabled_ && !is_current_header(link); } bool chaser_validate::is_silent_mature(bool residual) NOEXCEPT diff --git a/src/chasers/chaser_validate_capture.cpp b/src/chasers/chaser_validate_capture.cpp index b2aa0955..e98140e4 100644 --- a/src/chasers/chaser_validate_capture.cpp +++ b/src/chasers/chaser_validate_capture.cpp @@ -67,7 +67,7 @@ void chaser_validate::do_fire(missed miss, size_t count) NOEXCEPT signatures chaser_validate::get_capture(const header_link& link) NOEXCEPT { - if (!batch_enabled_ || link.is_terminal() || is_current_header(link)) + if (!verify_enabled_ || link.is_terminal() || is_current_header(link)) return { false }; // The capture populates this thread's accumulators (commit_capture consumes). diff --git a/src/settings.cpp b/src/settings.cpp index 68765ae6..84c0b167 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -40,7 +40,7 @@ settings::settings() NOEXCEPT provide_filters{ false }, provide_privacy{ false }, limited_blocks{ false }, - batch_signatures{ 0 }, + batch_verify{ 0 }, batch_silent{ 0 }, minimum_fee_rate{ 0.0 }, minimum_bump_rate{ 0.0 }, @@ -136,9 +136,14 @@ bool settings::fee_estimate_enabled() const NOEXCEPT return to_bool(fee_estimate_horizon_()); } -bool settings::batch_signatures_enabled() const NOEXCEPT +bool settings::batch_verify_enabled() const NOEXCEPT { - return to_bool(batch_signatures); + return to_bool(batch_verify); +} + +bool settings::batch_silent_enabled() const NOEXCEPT +{ + return to_bool(batch_silent); } network::steady_clock::duration settings::sample_period() const NOEXCEPT diff --git a/test/chasers/chaser_validate.cpp b/test/chasers/chaser_validate.cpp index f4ff2c4f..d8766551 100644 --- a/test/chasers/chaser_validate.cpp +++ b/test/chasers/chaser_validate.cpp @@ -412,7 +412,7 @@ struct validate_staged_fixture validate_staged_fixture() : validate_setup_fixture(validate_staged, [](configuration& config) { - config.node.batch_signatures = 1; + config.node.batch_verify = 1; }) { } @@ -424,7 +424,7 @@ struct validate_staged_second_fixture validate_staged_second_fixture() : validate_setup_fixture(validate_staged_second, [](configuration& config) { - config.node.batch_signatures = 1; + config.node.batch_verify = 1; }) { } diff --git a/test/settings.cpp b/test/settings.cpp index 8dbe0053..097cf077 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(settings__node__default_context__expected) BOOST_REQUIRE_EQUAL(node.minimum_fee_rate_(), 0_u64); BOOST_REQUIRE_EQUAL(node.minimum_bump_rate, 0.0); BOOST_REQUIRE_EQUAL(node.allowed_deviation, 1.5); - BOOST_REQUIRE_EQUAL(node.batch_signatures, 0_u64); + BOOST_REQUIRE_EQUAL(node.batch_verify, 0_u64); BOOST_REQUIRE_EQUAL(node.batch_silent, 0_u64); BOOST_REQUIRE_EQUAL(node.current_connections, 10_u16); BOOST_REQUIRE_EQUAL(node.announcement_cache, 42_u16); @@ -68,7 +68,8 @@ BOOST_AUTO_TEST_CASE(settings__node__default_context__expected) BOOST_REQUIRE_EQUAL(node.maximum_concurrency_(), 50'000_size); BOOST_REQUIRE_EQUAL(node.fee_estimate_horizon_(), 0_size); BOOST_REQUIRE(!node.fee_estimate_enabled()); - BOOST_REQUIRE(!node.batch_signatures_enabled()); + BOOST_REQUIRE(!node.batch_verify_enabled()); + BOOST_REQUIRE(!node.batch_silent_enabled()); BOOST_REQUIRE(node.sample_period() == steady_clock::duration(seconds(10))); BOOST_REQUIRE(node.currency_window() == steady_clock::duration(minutes(1440))); BOOST_REQUIRE(node.thread_priority_() == network::processing_priority::high);