diff --git a/.github/workflows/ci-expanded.yml b/.github/workflows/ci-expanded.yml index 883c834c..423b704c 100644 --- a/.github/workflows/ci-expanded.yml +++ b/.github/workflows/ci-expanded.yml @@ -24,9 +24,6 @@ jobs: env: CONCURRENCY_GROUP: ${{ github.workflow }}-${{ github.repository_owner == 'libbitcoin' && (github.event.pull_request.number || github.run_id) || github.ref }} - permissions: - actions: write - steps: - name: state run: | @@ -39,14 +36,6 @@ jobs: echo "base_ref : ${{ github.base_ref }}" echo "head_ref : ${{ github.head_ref }}" - - name: cancel on pull_request closed - if: github.event_name == 'pull_request' && github.event.action == 'closed' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh api --method POST \ - -H "Accept: application/vnd.github+json" "/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel" - gnu: if: github.event_name != 'pull_request' || github.event.action != 'closed' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 692e1554..ec69da99 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,9 +43,6 @@ jobs: env: CONCURRENCY_GROUP: ${{ github.workflow }}-${{ github.repository_owner == 'libbitcoin' && (github.event.pull_request.number || github.run_id) || github.ref }} - permissions: - actions: write - steps: - name: state run: | @@ -58,14 +55,6 @@ jobs: echo "base_ref : ${{ github.base_ref }}" echo "head_ref : ${{ github.head_ref }}" - - name: cancel on pull_request closed - if: github.event_name == 'pull_request' && github.event.action == 'closed' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh api --method POST \ - -H "Accept: application/vnd.github+json" "/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel" - gnu: if: github.event_name != 'pull_request' || github.event.action != 'closed' diff --git a/include/bitcoin/node/chasers/chaser_validate.hpp b/include/bitcoin/node/chasers/chaser_validate.hpp index d8a4062f..3bb1ef09 100644 --- a/include/bitcoin/node/chasers/chaser_validate.hpp +++ b/include/bitcoin/node/chasers/chaser_validate.hpp @@ -183,6 +183,7 @@ class BCN_API chaser_validate const size_t maximum_height_; const uint64_t verify_target_; const uint64_t silent_target_; + const bool gpu_; const bool verify_enabled_; const bool silent_enabled_; const bool node_witness_; diff --git a/include/bitcoin/node/settings.hpp b/include/bitcoin/node/settings.hpp index 54d002d9..7040e860 100644 --- a/include/bitcoin/node/settings.hpp +++ b/include/bitcoin/node/settings.hpp @@ -45,6 +45,9 @@ class BCN_API settings bool provide_filters; bool provide_privacy; bool limited_blocks; + bool use_gpu; + bool cpu_batch_verify; + bool cpu_batch_silent; float allowed_deviation; double minimum_fee_rate; double minimum_bump_rate; @@ -73,8 +76,11 @@ 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 use_gpu_() const NOEXCEPT; virtual bool batch_verify_enabled() const NOEXCEPT; virtual bool batch_silent_enabled() const NOEXCEPT; + virtual bool batch_verify_() const NOEXCEPT; + virtual bool batch_silent_() 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 a67a6c4c..b551ac29 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -45,10 +45,9 @@ chaser_validate::chaser_validate(full_node& node) NOEXCEPT maximum_height_(node.node_settings().maximum_height_()), verify_target_(node.node_settings().batch_verify), silent_target_(node.node_settings().batch_silent), - verify_enabled_(node.node_settings().batch_verify_enabled() && - system::batched::accelerated()), - silent_enabled_(node.node_settings().batch_silent_enabled() && - system::batched::accelerated()), + gpu_(node.node_settings().use_gpu_()), + verify_enabled_(node.node_settings().batch_verify_()), + silent_enabled_(node.node_settings().batch_silent_()), node_witness_(node.node_settings().require_witness), filter_(node.archive().filter_enabled()) { @@ -56,8 +55,8 @@ chaser_validate::chaser_validate(full_node& node) NOEXCEPT code chaser_validate::start() NOEXCEPT { - const auto reason = system::batched::compiled() ? "no device" : - "not compiled"; + const auto reason = !system::batched::compiled() ? "not compiled" : + !node_settings().use_gpu ? "gpu disabled" : "no gpu"; if (node_settings().batch_verify_enabled() && !verify_enabled_) LOGN("Signature batching disabled (" << reason << ")."); @@ -65,6 +64,12 @@ code chaser_validate::start() NOEXCEPT if (node_settings().batch_silent_enabled() && !silent_enabled_) LOGN("Silent batching disabled (" << reason << ")."); + if (verify_enabled_ && !gpu_) + LOGN("Signature batching on the cpu (" << reason << ")."); + + if (silent_enabled_ && !gpu_) + LOGN("Silent batching on the cpu (" << reason << ")."); + set_position(archive().get_fork()); if (const auto ec = start_batch()) return fault(ec); diff --git a/src/chasers/chaser_validate_batch.cpp b/src/chasers/chaser_validate_batch.cpp index 6bddb869..0024da34 100644 --- a/src/chasers/chaser_validate_batch.cpp +++ b/src/chasers/chaser_validate_batch.cpp @@ -119,14 +119,15 @@ code chaser_validate::do_process_batch(bool bank, bool startup) NOEXCEPT { auto& query = archive(); auto prevalids = query.get_prevalids(bank); + const auto& cancel = stopping_; const auto ecdsa = query.ecdsa_records(bank); if (is_nonzero(ecdsa)) { bool device{}; - header_links invalids{}; + header_links fails{}; const auto start = network::logger::now(); - if (!query.verify_ecdsa_signatures(stopping_, invalids, device, bank)) + if (!query.verify_ecdsa_signatures(cancel, fails, device, bank, gpu_)) { LOGN("Batch verify ecdsa canceled (" << ecdsa << ")."); return network::error::operation_canceled; @@ -140,7 +141,7 @@ code chaser_validate::do_process_batch(bool bank, bool startup) NOEXCEPT duration_cast(elapsed).count(), device)); } - if (!mark_invalids(prevalids, invalids, startup)) + if (!mark_invalids(prevalids, fails, startup)) return error::batch1; } @@ -148,9 +149,9 @@ code chaser_validate::do_process_batch(bool bank, bool startup) NOEXCEPT if (is_nonzero(schnorr)) { bool device{}; - header_links invalids{}; + header_links fails{}; const auto start = network::logger::now(); - if (!query.verify_schnorr_signatures(stopping_, invalids, device, bank)) + if (!query.verify_schnorr_signatures(cancel, fails, device, bank, gpu_)) { LOGN("Batch verify schnorr canceled (" << schnorr << ")."); return network::error::operation_canceled; @@ -164,7 +165,7 @@ code chaser_validate::do_process_batch(bool bank, bool startup) NOEXCEPT duration_cast(elapsed).count(), device)); } - if (!mark_invalids(prevalids, invalids, startup)) + if (!mark_invalids(prevalids, fails, startup)) return error::batch2; } @@ -389,7 +390,7 @@ code chaser_validate::do_process_silent_batch(bool bank) NOEXCEPT bool device{}; const auto rows = query.silent_records(bank); const auto start = network::logger::now(); - const auto ec = query.compute_silents(stopping_, device, bank); + const auto ec = query.compute_silents(stopping_, device, bank, gpu_); if (ec == database::error::query_canceled) { LOGN("Batch silent canceled (" << rows << ")."); diff --git a/src/configuration.cpp b/src/configuration.cpp index 42871f3a..046310a1 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -47,6 +47,19 @@ code configuration::initialize() NOEXCEPT if (silent && node.limited_blocks && node.silent_start_height <= bypassed) return network::error::invalid_configuration; + // Batch tables are unused when their batching does not run. + if (!node.batch_verify_()) + { + database.ecdsa.size = 0; + database.schnorr.size = 0; + } + + if (!node.batch_silent_()) + database.silent.size = 0; + + if (!node.use_gpu_()) + database.gpu_scan_minimum = max_uint32; + database.initialize(bitcoin, node.limited_blocks, node.silent_start_height); return network.initialize(); } diff --git a/src/settings.cpp b/src/settings.cpp index 84c0b167..b9f6ef39 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -40,6 +40,9 @@ settings::settings() NOEXCEPT provide_filters{ false }, provide_privacy{ false }, limited_blocks{ false }, + use_gpu{ true }, + cpu_batch_verify{ false }, + cpu_batch_silent{ false }, batch_verify{ 0 }, batch_silent{ 0 }, minimum_fee_rate{ 0.0 }, @@ -136,6 +139,11 @@ bool settings::fee_estimate_enabled() const NOEXCEPT return to_bool(fee_estimate_horizon_()); } +bool settings::use_gpu_() const NOEXCEPT +{ + return use_gpu && system::batched::accelerated(); +} + bool settings::batch_verify_enabled() const NOEXCEPT { return to_bool(batch_verify); @@ -146,6 +154,16 @@ bool settings::batch_silent_enabled() const NOEXCEPT return to_bool(batch_silent); } +bool settings::batch_verify_() const NOEXCEPT +{ + return batch_verify_enabled() && (cpu_batch_verify || use_gpu_()); +} + +bool settings::batch_silent_() const NOEXCEPT +{ + return batch_silent_enabled() && (cpu_batch_silent || use_gpu_()); +} + network::steady_clock::duration settings::sample_period() const NOEXCEPT { return network::seconds(sample_period_seconds); diff --git a/test/chasers/chaser_validate.cpp b/test/chasers/chaser_validate.cpp index 9445b5be..8b4b0d89 100644 --- a/test/chasers/chaser_validate.cpp +++ b/test/chasers/chaser_validate.cpp @@ -477,6 +477,20 @@ struct validate_windowed_fixture } }; +struct validate_windowed_cpu_fixture + : validate_setup_fixture +{ + validate_windowed_cpu_fixture() + : validate_setup_fixture(validate_noncandidate, [](configuration& config) + { + config.node.use_gpu = false; + config.node.batch_verify = 1; + config.node.cpu_batch_verify = true; + }) + { + } +}; + struct validate_immature_fixture : validate_setup_fixture { @@ -654,6 +668,18 @@ BOOST_FIXTURE_TEST_CASE(chaser_validate__windowed__invalid_ecdsa_signature__unco BOOST_REQUIRE(await([&]() { return is_zero(query_.ecdsa0_records()) && is_zero(query_.prevalid0_records()); })); } +BOOST_FIXTURE_TEST_CASE(chaser_validate__windowed__cpu_invalid_ecdsa_signature__unconfirmable, validate_windowed_cpu_fixture) +{ + const auto link = query_.to_header(validate_x1().hash()); + chain::ecdsa_signatures signatures{}; + BOOST_REQUIRE(signatures.append(null_hash, validate_generator, ec_signature{})); + BOOST_REQUIRE(query_.set_signatures(signatures, link, false)); + BOOST_REQUIRE(query_.set_prevalid(link, false)); + node_.notify(node::error::success, chases::windowed{ 1 }); + BOOST_REQUIRE(stated(validate_x1(), database::is_unconfirmable)); + BOOST_REQUIRE(await([&]() { return is_zero(query_.ecdsa0_records()) && is_zero(query_.prevalid0_records()); })); +} + BOOST_FIXTURE_TEST_CASE(chaser_validate__windowed__invalid_schnorr_signature__unconfirmable, validate_windowed_fixture) { const auto link = query_.to_header(validate_x1().hash()); diff --git a/test/configuration.cpp b/test/configuration.cpp index e83201d8..bd4134ca 100644 --- a/test/configuration.cpp +++ b/test/configuration.cpp @@ -82,4 +82,40 @@ BOOST_AUTO_TEST_CASE(configuration__initialize__unlimited_silent_at_bypassed__su BOOST_REQUIRE(!instance.initialize()); } +BOOST_AUTO_TEST_CASE(configuration__initialize__cpu_batching_without_gpu__tables_sized) +{ + node::configuration instance(chain::selection::mainnet); + instance.node.use_gpu = false; + instance.node.batch_verify = 1; + instance.node.batch_silent = 1; + instance.node.cpu_batch_verify = true; + instance.node.cpu_batch_silent = true; + instance.database.ecdsa.size = 42; + instance.database.schnorr.size = 42; + instance.database.silent.size = 42; + BOOST_REQUIRE(!instance.initialize()); + BOOST_REQUIRE_EQUAL(instance.database.ecdsa.size, 42u); + BOOST_REQUIRE_EQUAL(instance.database.schnorr.size, 42u); + BOOST_REQUIRE_EQUAL(instance.database.silent.size, 42u); + BOOST_REQUIRE_EQUAL(instance.database.gpu_scan_minimum, max_uint32); +} + +BOOST_AUTO_TEST_CASE(configuration__initialize__no_batching_without_gpu__tables_zero) +{ + node::configuration instance(chain::selection::mainnet); + instance.node.use_gpu = false; + instance.node.batch_verify = 1; + instance.node.batch_silent = 1; + instance.node.cpu_batch_verify = false; + instance.node.cpu_batch_silent = false; + instance.database.ecdsa.size = 42; + instance.database.schnorr.size = 42; + instance.database.silent.size = 42; + BOOST_REQUIRE(!instance.initialize()); + BOOST_REQUIRE_EQUAL(instance.database.ecdsa.size, 0u); + BOOST_REQUIRE_EQUAL(instance.database.schnorr.size, 0u); + BOOST_REQUIRE_EQUAL(instance.database.silent.size, 0u); + BOOST_REQUIRE_EQUAL(instance.database.gpu_scan_minimum, max_uint32); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/settings.cpp b/test/settings.cpp index 097cf077..5ab448ab 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -41,6 +41,9 @@ BOOST_AUTO_TEST_CASE(settings__node__default_context__expected) BOOST_REQUIRE_EQUAL(node.provide_filters, false); BOOST_REQUIRE_EQUAL(node.provide_privacy, false); BOOST_REQUIRE_EQUAL(node.limited_blocks, false); + BOOST_REQUIRE_EQUAL(node.use_gpu, true); + BOOST_REQUIRE_EQUAL(node.cpu_batch_verify, false); + BOOST_REQUIRE_EQUAL(node.cpu_batch_silent, false); BOOST_REQUIRE_EQUAL(node.minimum_fee_rate, 0.0); BOOST_REQUIRE_EQUAL(node.minimum_fee_rate_(), 0_u64); BOOST_REQUIRE_EQUAL(node.minimum_bump_rate, 0.0); @@ -68,8 +71,11 @@ 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_EQUAL(node.use_gpu_(), system::batched::accelerated()); BOOST_REQUIRE(!node.batch_verify_enabled()); BOOST_REQUIRE(!node.batch_silent_enabled()); + BOOST_REQUIRE(!node.batch_verify_()); + BOOST_REQUIRE(!node.batch_silent_()); 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); @@ -90,4 +96,63 @@ BOOST_AUTO_TEST_CASE(settings__services_provided__filters_privacy__network_witne BOOST_REQUIRE_EQUAL(node.services_provided(), 0x0849_u64); } +BOOST_AUTO_TEST_CASE(settings__use_gpu___disabled__false) +{ + node::settings node{}; + node.use_gpu = false; + BOOST_REQUIRE(!node.use_gpu_()); +} + +BOOST_AUTO_TEST_CASE(settings__batch_verify___cpu_without_gpu__true) +{ + node::settings node{}; + node.use_gpu = false; + node.batch_verify = 1; + node.cpu_batch_verify = true; + BOOST_REQUIRE(node.batch_verify_()); +} + +BOOST_AUTO_TEST_CASE(settings__batch_verify___no_cpu_without_gpu__false) +{ + node::settings node{}; + node.use_gpu = false; + node.batch_verify = 1; + node.cpu_batch_verify = false; + BOOST_REQUIRE(!node.batch_verify_()); +} + +BOOST_AUTO_TEST_CASE(settings__batch_verify___cpu_unconfigured__false) +{ + node::settings node{}; + node.batch_verify = 0; + node.cpu_batch_verify = true; + BOOST_REQUIRE(!node.batch_verify_()); +} + +BOOST_AUTO_TEST_CASE(settings__batch_silent___cpu_without_gpu__true) +{ + node::settings node{}; + node.use_gpu = false; + node.batch_silent = 1; + node.cpu_batch_silent = true; + BOOST_REQUIRE(node.batch_silent_()); +} + +BOOST_AUTO_TEST_CASE(settings__batch_silent___no_cpu_without_gpu__false) +{ + node::settings node{}; + node.use_gpu = false; + node.batch_silent = 1; + node.cpu_batch_silent = false; + BOOST_REQUIRE(!node.batch_silent_()); +} + +BOOST_AUTO_TEST_CASE(settings__batch_silent___cpu_unconfigured__false) +{ + node::settings node{}; + node.batch_silent = 0; + node.cpu_batch_silent = true; + BOOST_REQUIRE(!node.batch_silent_()); +} + BOOST_AUTO_TEST_SUITE_END()