diff --git a/.github/workflows/ci-expanded.yml b/.github/workflows/ci-expanded.yml index 03638d894..e029f10af 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 a9ab16c9b..d56bac147 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,9 +45,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: | @@ -60,14 +57,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/database/impl/primitives/hashhead.ipp b/include/bitcoin/database/impl/primitives/hashhead.ipp index c4e9050fc..6b5f012c0 100644 --- a/include/bitcoin/database/impl/primitives/hashhead.ipp +++ b/include/bitcoin/database/impl/primitives/hashhead.ipp @@ -218,6 +218,23 @@ size_t CLASS::poisson_span(double load_factor) NOEXCEPT deviations * std::sqrt(load_factor) + minimum)); } +// False positive over poisson bucket occupancy. +TEMPLATE +double CLASS::false_positive(size_t k, double load_factor) NOEXCEPT +{ + using namespace system; + auto rate = 0.0; + auto poisson = std::exp(-load_factor); + const auto span = poisson_span(load_factor); + for (auto n = one; n <= span; ++n) + { + poisson *= load_factor / to_floating(n); + rate += poisson * bloom_false_positive(k, n); + } + + return rate; +} + // False positive over poisson bucket occupancy, weighted by the occupancy. TEMPLATE double CLASS::expected_walk(size_t k, double load_factor) NOEXCEPT diff --git a/include/bitcoin/database/impl/primitives/hashmap.ipp b/include/bitcoin/database/impl/primitives/hashmap.ipp index 287dcb0b4..94a0d2cd3 100644 --- a/include/bitcoin/database/impl/primitives/hashmap.ipp +++ b/include/bitcoin/database/impl/primitives/hashmap.ipp @@ -99,6 +99,24 @@ uint32_t CLASS::derive_buckets(uint64_t expected, uint32_t low, return head::derive_buckets(expected, low, high); } +TEMPLATE +size_t CLASS::optimal_k(size_t count, size_t buckets) NOEXCEPT +{ + return head::optimal_k(count, buckets); +} + +TEMPLATE +double CLASS::false_positive(size_t k, double load_factor) NOEXCEPT +{ + return head::false_positive(k, load_factor); +} + +TEMPLATE +double CLASS::expected_walk(size_t k, double load_factor) NOEXCEPT +{ + return head::expected_walk(k, load_factor); +} + TEMPLATE size_t CLASS::filter_k() const NOEXCEPT { diff --git a/include/bitcoin/database/impl/primitives/hashmaps.ipp b/include/bitcoin/database/impl/primitives/hashmaps.ipp index f6701f16c..fa2f595f1 100644 --- a/include/bitcoin/database/impl/primitives/hashmaps.ipp +++ b/include/bitcoin/database/impl/primitives/hashmaps.ipp @@ -98,6 +98,24 @@ uint32_t CLASS::derive_buckets(uint64_t expected, uint32_t low, return head::derive_buckets(expected, low, high); } +TEMPLATE +size_t CLASS::optimal_k(size_t count, size_t buckets) NOEXCEPT +{ + return head::optimal_k(count, buckets); +} + +TEMPLATE +double CLASS::false_positive(size_t k, double load_factor) NOEXCEPT +{ + return head::false_positive(k, load_factor); +} + +TEMPLATE +double CLASS::expected_walk(size_t k, double load_factor) NOEXCEPT +{ + return head::expected_walk(k, load_factor); +} + TEMPLATE size_t CLASS::filter_k() const NOEXCEPT { diff --git a/include/bitcoin/database/impl/query/batch/ecdsa.ipp b/include/bitcoin/database/impl/query/batch/ecdsa.ipp index df484d51c..fcf76eab8 100644 --- a/include/bitcoin/database/impl/query/batch/ecdsa.ipp +++ b/include/bitcoin/database/impl/query/batch/ecdsa.ipp @@ -34,7 +34,7 @@ size_t CLASS::ecdsa_records(bool bank) const NOEXCEPT TEMPLATE bool CLASS::verify_ecdsa_signatures(const stopper& cancel, - header_links& links, bool& device, bool bank) NOEXCEPT + header_links& links, bool& device, bool bank, bool gpu) NOEXCEPT { auto& bank_table = store_.ecdsa_bank(bank); const auto correlate_ptr = bank_table.correlate.get_memory(); @@ -64,7 +64,7 @@ bool CLASS::verify_ecdsa_signatures(const stopper& cancel, }; // False return only implies canceled. - links = ecdsa::batch::verify(device, cancel, batch); + links = ecdsa::batch::verify(device, cancel, batch, gpu); return !cancel; } diff --git a/include/bitcoin/database/impl/query/batch/schnorr.ipp b/include/bitcoin/database/impl/query/batch/schnorr.ipp index 46477c147..cca9c71de 100644 --- a/include/bitcoin/database/impl/query/batch/schnorr.ipp +++ b/include/bitcoin/database/impl/query/batch/schnorr.ipp @@ -33,7 +33,7 @@ size_t CLASS::schnorr_records(bool bank) const NOEXCEPT TEMPLATE bool CLASS::verify_schnorr_signatures(const stopper& cancel, - header_links& links, bool& device, bool bank) NOEXCEPT + header_links& links, bool& device, bool bank, bool gpu) NOEXCEPT { auto& bank_table = store_.schnorr_bank(bank); const auto correlate_ptr = bank_table.correlate.get_memory(); @@ -63,7 +63,7 @@ bool CLASS::verify_schnorr_signatures(const stopper& cancel, }; // False return only implies canceled. - links = schnorr::batch::verify(device, cancel, batch); + links = schnorr::batch::verify(device, cancel, batch, gpu); return !cancel; } diff --git a/include/bitcoin/database/impl/query/batch/silent.ipp b/include/bitcoin/database/impl/query/batch/silent.ipp index 14488e962..feb4d715b 100644 --- a/include/bitcoin/database/impl/query/batch/silent.ipp +++ b/include/bitcoin/database/impl/query/batch/silent.ipp @@ -72,7 +72,8 @@ bool CLASS::scan_silent(const stopper& cancel, // False return only implies canceled. // Callbacks invoked on caller thread if turbo is false. - system::scan::batch::scan(cancel, batch, keys, callback, store_.turbo()); + const auto minimum = store_.gpu_scan_minimum(); + scan::batch::scan(cancel, batch, keys, minimum, callback, store_.turbo()); return !cancel; } @@ -366,8 +367,8 @@ bool CLASS::get_silent_prevouts(data_chunk& prevouts, // compute on the processor), and each tx is then published by its correlate // (an invalid tx with no outputs). TEMPLATE -code CLASS::compute_silents(const stopper& cancel, bool& device, - bool bank) NOEXCEPT +code CLASS::compute_silents(const stopper& cancel, bool& device, bool bank, + bool gpu) NOEXCEPT { using namespace system; auto& bank_table = store_.silent_bank(bank); @@ -422,16 +423,16 @@ code CLASS::compute_silents(const stopper& cancel, bool& device, }; data_chunk valid(txs); - const silent::batch batch{ { sums, txs }, { hashes, txs } }; + const silent::batch rows{ { sums, txs }, { hashes, txs } }; const auto compute = [&]() NOEXCEPT { - return silent::batch::compute(points, valid, device, cancel, batch); + return silent::batch::compute(points, valid, device, cancel, rows, gpu); }; // The device computes concurrently with the write, the processor before. bool success{}; std::future computed{}; - const auto accelerated = batched::accelerated(); + const auto accelerated = gpu && batched::accelerated(); if (accelerated) computed = std::async(std::launch::async, compute); else diff --git a/include/bitcoin/database/impl/store/store.ipp b/include/bitcoin/database/impl/store/store.ipp index 6cefbb466..964d05517 100644 --- a/include/bitcoin/database/impl/store/store.ipp +++ b/include/bitcoin/database/impl/store/store.ipp @@ -204,6 +204,12 @@ bool CLASS::turbo() const NOEXCEPT return configuration_.turbo; } +TEMPLATE +size_t CLASS::gpu_scan_minimum() const NOEXCEPT +{ + return configuration_.gpu_scan_minimum; +} + TEMPLATE bool CLASS::mark_unconfirmable() const NOEXCEPT { diff --git a/include/bitcoin/database/primitives/hashhead.hpp b/include/bitcoin/database/primitives/hashhead.hpp index d1f43bf7d..131bcfd19 100644 --- a/include/bitcoin/database/primitives/hashhead.hpp +++ b/include/bitcoin/database/primitives/hashhead.hpp @@ -40,6 +40,13 @@ class hashhead using bytes = typename Link::bytes; + /// Bucket filter, disabled if the cell has no bits beyond the link. + static constexpr size_t filter_bits = to_bits(CellSize) - Link::bits; + static constexpr size_t filter_k_max = (filter_bits < two) ? zero : + std::min(filter_bits, bits / + system::ceilinged_log2(filter_bits)); + using filter_t = system::bloom; + /// A hash head is disabled if it has no buckets. hashhead(storage& head, size_t buckets, size_t expected=zero) NOEXCEPT; @@ -59,6 +66,12 @@ class hashhead /// Optimal filter k-value for expected load factor. static size_t optimal_k(size_t count, size_t buckets) NOEXCEPT; + /// Expected filter false positive rate of a new key at load factor. + static double false_positive(size_t k, double load_factor) NOEXCEPT; + + /// Expected filter false positive walk of a new key at load factor. + static double expected_walk(size_t k, double load_factor) NOEXCEPT; + /// Buckets for expected elements, scaled by memory between load factors. static uint32_t derive_buckets(uint64_t expected, uint32_t low, uint32_t high) NOEXCEPT; @@ -101,12 +114,10 @@ class hashhead static constexpr size_t cell_size = CellSize; static constexpr size_t link_size = Link::size; static constexpr size_t link_bits = Link::bits; - static constexpr size_t m = to_bits(cell_size) - link_bits; + static constexpr size_t m = filter_bits; static constexpr size_t k_default = system::floored_log2(m); - static constexpr size_t k_max = (m < two) ? zero : std::min(m, - bits / system::ceilinged_log2(m)); + static constexpr size_t k_max = filter_k_max; - using filter_t = system::bloom; using cell = unsigned_type; using filter = filter_t::type; using link = Link::integer; @@ -127,7 +138,6 @@ class hashhead static double bloom_false_positive(size_t k, size_t n) NOEXCEPT; static size_t poisson_span(double load_factor) NOEXCEPT; - static double expected_walk(size_t k, double load_factor) NOEXCEPT; inline cell get_cell(const Link& index) const NOEXCEPT; inline bool set_cell(bool& collision, bytes& next, const Link& current, diff --git a/include/bitcoin/database/primitives/hashmap.hpp b/include/bitcoin/database/primitives/hashmap.hpp index f55cb5641..8700d9032 100644 --- a/include/bitcoin/database/primitives/hashmap.hpp +++ b/include/bitcoin/database/primitives/hashmap.hpp @@ -72,6 +72,22 @@ class hashmap static uint32_t derive_buckets(uint64_t expected, uint32_t low, uint32_t high) NOEXCEPT; + /// Bucket filter (hashhead::filter_t). + using filter_t = typename hashhead::filter_t; + static constexpr size_t filter_bits = + hashhead::filter_bits; + static constexpr size_t filter_k_max = + hashhead::filter_k_max; + + /// Optimal filter k-value for expected load factor (hashhead::optimal_k). + static size_t optimal_k(size_t count, size_t buckets) NOEXCEPT; + + /// Expected filter false positive rate (hashhead::false_positive). + static double false_positive(size_t k, double load_factor) NOEXCEPT; + + /// Expected filter false positive walk (hashhead::expected_walk). + static double expected_walk(size_t k, double load_factor) NOEXCEPT; + /// Filter selections, derived at construct, overridden by set_filter_k. size_t filter_k() const NOEXCEPT; diff --git a/include/bitcoin/database/primitives/hashmaps.hpp b/include/bitcoin/database/primitives/hashmaps.hpp index a04efc887..4fbf34814 100644 --- a/include/bitcoin/database/primitives/hashmaps.hpp +++ b/include/bitcoin/database/primitives/hashmaps.hpp @@ -81,6 +81,22 @@ class hashmaps static uint32_t derive_buckets(uint64_t expected, uint32_t low, uint32_t high) NOEXCEPT; + /// Bucket filter (hashhead::filter_t). + using filter_t = typename hashhead::filter_t; + static constexpr size_t filter_bits = + hashhead::filter_bits; + static constexpr size_t filter_k_max = + hashhead::filter_k_max; + + /// Optimal filter k-value for expected load factor (hashhead::optimal_k). + static size_t optimal_k(size_t count, size_t buckets) NOEXCEPT; + + /// Expected filter false positive rate (hashhead::false_positive). + static double false_positive(size_t k, double load_factor) NOEXCEPT; + + /// Expected filter false positive walk (hashhead::expected_walk). + static double expected_walk(size_t k, double load_factor) NOEXCEPT; + /// Filter selections, derived at construct, overridden by set_filter_k. size_t filter_k() const NOEXCEPT; diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 2d31f12af..622b364f8 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -758,8 +758,8 @@ class query const header_link& link, const block_view& block) const NOEXCEPT; /// Compute a bank's silent payment batch, then set its scan records. - code compute_silents(const stopper& cancel, bool& device, - bool bank) NOEXCEPT; + code compute_silents(const stopper& cancel, bool& device, bool bank, + bool gpu) NOEXCEPT; /// Commit a block's captured ecdsa signature groups (band-expanded). bool set_signatures(const system::chain::ecdsa_signatures& sigs, @@ -799,9 +799,9 @@ class query /// Verify all signatures in table, false implies cancel, device set if /// verified on the device. bool verify_ecdsa_signatures(const stopper& cancel, header_links&, - bool& device, bool bank) NOEXCEPT; + bool& device, bool bank, bool gpu) NOEXCEPT; bool verify_schnorr_signatures(const stopper& cancel, header_links&, - bool& device, bool bank) NOEXCEPT; + bool& device, bool bank, bool gpu) NOEXCEPT; /// Purge all entries in table. bool purge_prevalids(bool bank) NOEXCEPT; diff --git a/include/bitcoin/database/settings.hpp b/include/bitcoin/database/settings.hpp index 18765d21b..796ee209b 100644 --- a/include/bitcoin/database/settings.hpp +++ b/include/bitcoin/database/settings.hpp @@ -73,6 +73,9 @@ struct BCD_API settings /// Enable concurrency in individual client-server queries. bool turbo{ false }; + /// Minimum transactions for a silent payment scan on the device. + uint32_t gpu_scan_minimum{ 65'536 }; + /// Mark blocks as unconfirmable (disorganize vs. stall). bool mark_unconfirmable{ true }; diff --git a/include/bitcoin/database/store.hpp b/include/bitcoin/database/store.hpp index 9205b87f5..83f3394d6 100644 --- a/include/bitcoin/database/store.hpp +++ b/include/bitcoin/database/store.hpp @@ -88,6 +88,9 @@ class store /// Allows full throttle concurrent query execution (may use 100% CPU). bool turbo() const NOEXCEPT; + /// Minimum transactions for a silent payment scan on the device. + size_t gpu_scan_minimum() const NOEXCEPT; + /// Mark blocks as unconfirmable (disorganize vs. stall), configuration. bool mark_unconfirmable() const NOEXCEPT; diff --git a/test/primitives/hashhead.cpp b/test/primitives/hashhead.cpp index a46307e2d..28cd609d8 100644 --- a/test/primitives/hashhead.cpp +++ b/test/primitives/hashhead.cpp @@ -194,6 +194,18 @@ BOOST_AUTO_TEST_CASE(hashhead__optimal_k__load_factor__banded) BOOST_REQUIRE_EQUAL(filtered_::optimal_k(200, 10), 1u); } +BOOST_AUTO_TEST_CASE(hashhead__false_positive__zero_load__zero) +{ + BOOST_REQUIRE_EQUAL(filtered_::false_positive(4, 0.0), 0.0); + BOOST_REQUIRE_EQUAL(filtered_::expected_walk(4, 0.0), 0.0); +} + +BOOST_AUTO_TEST_CASE(hashhead__false_positive__load__increasing_below_walk) +{ + BOOST_REQUIRE_LT(filtered_::false_positive(4, 1.0), filtered_::false_positive(4, 2.0)); + BOOST_REQUIRE_LT(filtered_::false_positive(4, 2.0), filtered_::expected_walk(4, 2.0)); +} + BOOST_AUTO_TEST_CASE(hashhead__construct__expected__derived_k) { data_chunk data{}; diff --git a/test/query/batch/ecdsa.cpp b/test/query/batch/ecdsa.cpp index 8274cf277..ac1ed9343 100644 --- a/test/query/batch/ecdsa.cpp +++ b/test/query/batch/ecdsa.cpp @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__empty__empty) header_links links{}; bool device{}; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 0u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); BOOST_REQUIRE(links.empty()); } @@ -75,10 +75,25 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_valid__empt header_links links{}; bool device{}; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 1u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); BOOST_REQUIRE(links.empty()); } +BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_valid_without_gpu__empty) +{ + const database::settings configuration{}; + test::chunk_store store{ configuration }; + test::query_accessor query{ store }; + BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42, false)); + + header_links links{}; + bool device{}; + BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 1u); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, false)); + BOOST_REQUIRE(links.empty()); + BOOST_REQUIRE(!device); +} + BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_invalid__expected_link) { const database::settings configuration{}; @@ -90,7 +105,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_invalid__ex header_links links{}; bool device{}; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 1u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); BOOST_REQUIRE_EQUAL(links.size(), 1u); BOOST_REQUIRE_EQUAL(links.front(), expected); } @@ -115,7 +130,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__various__expect header_links links{}; bool device{}; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 8u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); BOOST_REQUIRE_EQUAL(links.size(), 2u); const auto back = links.back(); @@ -136,9 +151,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__banks__independ header_links links{}; bool device{}; - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); BOOST_REQUIRE(links.empty()); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, true)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, true, true)); BOOST_REQUIRE_EQUAL(links.size(), 1u); BOOST_REQUIRE_EQUAL(links.front(), expected); diff --git a/test/query/batch/schnorr.cpp b/test/query/batch/schnorr.cpp index 825a82c55..8e550f4d3 100644 --- a/test/query/batch/schnorr.cpp +++ b/test/query/batch/schnorr.cpp @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__empty__empty) header_links links{}; bool device{}; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 0u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, true)); BOOST_REQUIRE(links.empty()); } @@ -75,10 +75,25 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_valid__em header_links links{}; bool device{}; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 1u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, true)); BOOST_REQUIRE(links.empty()); } +BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_valid_without_gpu__empty) +{ + const database::settings configuration{}; + test::chunk_store store{ configuration }; + test::query_accessor query{ store }; + BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 42)); + + header_links links{}; + bool device{}; + BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 1u); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, false)); + BOOST_REQUIRE(links.empty()); + BOOST_REQUIRE(!device); +} + BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_invalid__expected_link) { const database::settings configuration{}; @@ -90,7 +105,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_invalid__ header_links links{}; bool device{}; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 1u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, true)); BOOST_REQUIRE_EQUAL(links.size(), 1u); BOOST_REQUIRE_EQUAL(links.front(), expected); } @@ -115,7 +130,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__various__expe header_links links{}; bool device{}; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 8u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, true)); BOOST_REQUIRE_EQUAL(links.size(), 2u); const auto back = links.back(); diff --git a/test/query/batch/silent.cpp b/test/query/batch/silent.cpp index 12fc24aa3..7cf2b7317 100644 --- a/test/query/batch/silent.cpp +++ b/test/query/batch/silent.cpp @@ -477,7 +477,7 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__banked_row__scanned) const stopper cancel{}; bool device{}; BOOST_REQUIRE(query.set_silents(rows, link, block, false)); - BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false), database::error::success); + BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false, true), database::error::success); BOOST_REQUIRE_EQUAL(query.scan_records(), 1u); std::vector links{}; @@ -490,6 +490,38 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__banked_row__scanned) BOOST_REQUIRE_EQUAL(links, std::vector{ tx.value }); } +BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__banked_row_without_gpu__scanned) +{ + database::settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_REQUIRE(!store.create(test::events_handler)); + BOOST_REQUIRE(query.initialize(test::genesis)); + + const auto block = silent_block(); + BOOST_REQUIRE(query.set(block, database::context{ 0, 1, 0 }, {}, false, false)); + const auto link = query.to_header(block.hash()); + const auto tx = query.to_tx(simple_send().hash(false)); + + size_t rows{}; + const stopper cancel{}; + bool device{}; + BOOST_REQUIRE(query.set_silents(rows, link, block, false)); + BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false, false), database::error::success); + BOOST_REQUIRE_EQUAL(query.scan_records(), 1u); + BOOST_REQUIRE(!device); + + std::vector links{}; + const auto handler = [&](const code&, tx_link_t link, const ec_compressed&) NOEXCEPT + { + links.push_back(link); + }; + + BOOST_REQUIRE(query.scan_silent(cancel, get_keys(), handler)); + BOOST_REQUIRE_EQUAL(links, std::vector{ tx.value }); +} + BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__empty__success) { database::settings settings{}; @@ -501,7 +533,7 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__empty__success) const stopper cancel{}; bool device{}; - BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false), database::error::success); + BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false, true), database::error::success); BOOST_REQUIRE_EQUAL(query.scan_records(), 0u); } @@ -543,7 +575,7 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__presilent_banked_row__ bool device{}; BOOST_REQUIRE(query.set_silents(rows, link, block, false)); BOOST_REQUIRE_EQUAL(query.presilent_records(false), 1u); - BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false), database::error::success); + BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false, true), database::error::success); BOOST_REQUIRE(is_scanned(query.get_block_state(link))); } diff --git a/test/settings.cpp b/test/settings.cpp index a0fdbc271..8df3f602b 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -24,6 +24,7 @@ BOOST_AUTO_TEST_CASE(settings__construct__default__expected) { database::settings configuration; BOOST_REQUIRE_EQUAL(configuration.turbo, false); + BOOST_REQUIRE_EQUAL(configuration.gpu_scan_minimum, 65'536u); BOOST_REQUIRE_EQUAL(configuration.mark_unconfirmable, true); BOOST_REQUIRE_EQUAL(configuration.interval_depth, 255u); BOOST_REQUIRE_EQUAL(configuration.envelope.interval_depth, 255u);