diff --git a/include/bitcoin/database/impl/query/batch/ecdsa.ipp b/include/bitcoin/database/impl/query/batch/ecdsa.ipp index fcf76eab8..b6ff22de5 100644 --- a/include/bitcoin/database/impl/query/batch/ecdsa.ipp +++ b/include/bitcoin/database/impl/query/batch/ecdsa.ipp @@ -33,8 +33,8 @@ 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, bool gpu) NOEXCEPT +bool CLASS::verify_ecdsa_signatures(const stopper& cancel, bool& use_gpu, + header_links& links, bool bank) 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, gpu); + links = ecdsa::batch::verify(cancel, use_gpu, batch); return !cancel; } diff --git a/include/bitcoin/database/impl/query/batch/schnorr.ipp b/include/bitcoin/database/impl/query/batch/schnorr.ipp index cca9c71de..73b5b97e7 100644 --- a/include/bitcoin/database/impl/query/batch/schnorr.ipp +++ b/include/bitcoin/database/impl/query/batch/schnorr.ipp @@ -32,8 +32,8 @@ 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, bool gpu) NOEXCEPT +bool CLASS::verify_schnorr_signatures(const stopper& cancel, bool& use_gpu, + header_links& links, bool bank) 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, gpu); + links = schnorr::batch::verify(cancel, use_gpu, batch); return !cancel; } diff --git a/include/bitcoin/database/impl/query/batch/silent.ipp b/include/bitcoin/database/impl/query/batch/silent.ipp index feb4d715b..8ac11f370 100644 --- a/include/bitcoin/database/impl/query/batch/silent.ipp +++ b/include/bitcoin/database/impl/query/batch/silent.ipp @@ -19,7 +19,6 @@ #ifndef LIBBITCOIN_DATABASE_QUERY_BATCH_SILENT_IPP #define LIBBITCOIN_DATABASE_QUERY_BATCH_SILENT_IPP -#include #include #include #include @@ -188,38 +187,28 @@ scan_link CLASS::get_scan_floor(size_t height) const NOEXCEPT TEMPLATE bool CLASS::set_silent(const header_link& link, const block& block) NOEXCEPT { - return set_silent_(link, *block.transactions_ptr()); + return set_silent_(link, block, block.transactions()); } TEMPLATE bool CLASS::set_silent(const header_link& link, const block_view& block) NOEXCEPT { - return set_silent_(link, block.views()); + return set_silent_(link, block, block.views().size()); } // Ineligible txs have no records. TEMPLATE bool CLASS::set_silent(const tx_link& link, const transaction& tx) NOEXCEPT { - using namespace system::wallet; - ec_compressed point{}; - std::vector prefixes{}; - return !get_prefixes(prefixes, tx) - || !silent_payment::summarize(point, tx) - || set_silent_(link, point, prefixes); + return set_silent_(link, tx); } TEMPLATE bool CLASS::set_silent(const tx_link& link, const transaction_view& tx) NOEXCEPT { - using namespace system::wallet; - ec_compressed point{}; - std::vector prefixes{}; - return !get_prefixes(prefixes, tx) - || !silent_payment::summarize(point, tx) - || set_silent_(link, point, prefixes); + return set_silent_(link, tx); } // batch @@ -299,14 +288,14 @@ TEMPLATE bool CLASS::set_silents(size_t& rows, const header_link& link, const block& block, bool bank) NOEXCEPT { - return set_silents_(rows, link, *block.transactions_ptr(), bank); + return set_silents_(rows, link, block, block.transactions(), bank); } TEMPLATE bool CLASS::set_silents(size_t& rows, const header_link& link, const block_view& block, bool bank) NOEXCEPT { - return set_silents_(rows, link, block.views(), bank); + return set_silents_(rows, link, block, block.views().size(), bank); } // Pooled txs linked below the coinbase are not selected (see set_silent). @@ -325,12 +314,12 @@ bool CLASS::get_silent_prevouts(data_chunk& prevouts, stream::out::data ostream(prevouts); write::bytes::ostream sink(ostream); + using namespace system::wallet; const auto first = links.front(); - std::vector prefixes{}; for (auto index = one; index < txs.size(); ++index) { if (!is_silent_selected(links.at(index), first) || - !get_prefixes(prefixes, txs.at(index))) + !silent_payment::has_outputs(txs.at(index))) continue; table::transaction::get_puts record{}; @@ -363,12 +352,12 @@ bool CLASS::get_silent_prevouts(data_chunk& prevouts, // The bank is quiescent (drain claimed, no writers), so it is read across the // scan write, which is sourced directly from its columns. Scan rows are // allocated for every bank tx and prefix, so the prefixes and outputs are -// written in parallel while the points compute on the device (or after they -// compute on the processor), and each tx is then published by its correlate +// written in parallel while points compute on gpu (or after they compute on +// cpu), 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, - bool gpu) NOEXCEPT +code CLASS::compute_silents(const stopper& cancel, bool& use_gpu, + bool bank) NOEXCEPT { using namespace system; auto& bank_table = store_.silent_bank(bank); @@ -422,22 +411,6 @@ code CLASS::compute_silents(const stopper& cancel, bool& device, bool bank, std::next(pointer_cast(point_ptr.data()), fk.value), txs }; - data_chunk valid(txs); - const silent::batch rows{ { sums, txs }, { hashes, txs } }; - const auto compute = [&]() NOEXCEPT - { - 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 = gpu && batched::accelerated(); - if (accelerated) - computed = std::async(std::launch::async, compute); - else - success = compute(); - using scan_int = scan_link::integer; using prefix_int = prefix_link::integer; using outputs_record = table::scan_outputs::record; @@ -447,26 +420,31 @@ code CLASS::compute_silents(const stopper& cancel, bool& device, bool bank, std::atomic_bool failed{}; std_vector indexes(txs); std::iota(indexes.begin(), indexes.end(), zero); - std::for_each(poolstl::execution::par, indexes.cbegin(), indexes.cend(), - [&](size_t tx) NOEXCEPT - { - const auto& output = *std::next(outputs, tx); - const auto first = from_little_endian(output.first); - const auto count = from_little_endian(output.count); - const auto link = possible_narrow_cast(fk.value + tx); - const auto row = possible_narrow_cast(pk.value + first); - const span_t span{ {}, { std::next(prefixes, first), count } }; - const outputs_record record{ {}, row, count }; + const auto put = [&](size_t tx) NOEXCEPT + { + const auto& output = *std::next(outputs, tx); + const auto first = from_little_endian(output.first); + const auto count = from_little_endian(output.count); + const auto link = possible_narrow_cast(fk.value + tx); + const auto row = possible_narrow_cast(pk.value + first); + const span_t span{ {}, { std::next(prefixes, first), count } }; + const outputs_record record{ {}, row, count }; - if (!store_.scan_prefix.put(scan_prefix_ptr, row, span) || - !store_.scan.outputs.put(link, record)) - failed.store(true); - }); + if (!store_.scan_prefix.put(scan_prefix_ptr, row, span) || + !store_.scan.outputs.put(link, record)) + failed.store(true); + }; - if (accelerated) - success = computed.get(); + const auto write = [&]() NOEXCEPT + { + constexpr auto policy = poolstl::execution::par; + std::for_each(policy, indexes.cbegin(), indexes.cend(), put); + }; - if (!success) + // Write is concurrent with gpu, after cpu. + data_chunk valid(txs); + const silent::batch in{ { sums, txs }, { hashes, txs } }; + if (!silent::batch::compute(cancel, use_gpu, points, valid, in, write)) return error::query_canceled; if (failed.load()) @@ -501,99 +479,104 @@ code CLASS::compute_silents(const stopper& cancel, bool& device, bool bank, // protected // ---------------------------------------------------------------------------- -// Ineligible txs have no records. The block's records and its scanned state -// are written in one transactor scope, and once both allocations succeed the -// writes cannot fail. +// Pooled txs linked below the coinbase were indexed (see set_silent). TEMPLATE -template -bool CLASS::set_silent_(const header_link& link, - const Transactions& txs) NOEXCEPT +template +bool CLASS::set_silent_(const header_link& link, const Block& block, + size_t count) NOEXCEPT { - struct capture - { - tx_link link{}; - ec_compressed point{}; - std::vector prefixes{}; - }; - - const auto count = txs.size(); + using namespace system::wallet; const auto links = to_transactions(link); if (links.size() != count) return false; - // Object txs are held by pointer, views by value. - const auto to_tx = [](const auto& tx) NOEXCEPT -> decltype(auto) + auto& rows = silent_payment::rows::local(); + silent_payment::collect(rows, block, [&](size_t position) NOEXCEPT { - using type = std::decay_t; - if constexpr (is_same_type) - return (tx); - else - return (*tx); - }; + return is_silent_selected(links.at(position), links.front()); + }, true); + + // ======================================================================== + const auto scope = get_transactor(); + // Clean single allocation failure (e.g. disk full). + return put_scan_(rows, links) && store_.state.set(to_state(link), + table::state::merge{ {}, block_state::scanned }); + // ======================================================================== +} + +// Ineligible txs have no records. +TEMPLATE +template +bool CLASS::set_silent_(const tx_link& link, const Transaction& tx) NOEXCEPT +{ using namespace system::wallet; - size_t rows{}; - std::vector captures{}; - const auto first = links.front(); - for (auto index = one; index < count; ++index) - { - capture item{ links.at(index) }; - const auto& tx = to_tx(txs.at(index)); - if (is_silent_selected(item.link, first) && - get_prefixes(item.prefixes, tx) && - silent_payment::summarize(item.point, tx)) - { - rows += item.prefixes.size(); - captures.push_back(std::move(item)); - } - } + if (link.is_terminal()) + return false; - using namespace system; - using word_t = table::scan_correlate::tx::integer; - using point_t = table::scan_point::put_ref; - using prefix_t = table::scan_prefix::put_refs; - const table::state::merge scanned{ {}, block_state::scanned }; + auto& rows = silent_payment::rows::local(); + if (!silent_payment::collect(rows, tx, true)) + return true; // ======================================================================== const auto scope = get_transactor(); - if (is_zero(rows)) - return store_.state.set(to_state(link), scanned); + // Clean single allocation failure (e.g. disk full). + return put_scan_(rows, { &link.value, one }); + // ======================================================================== +} + +// Caller holds the transactor. Prefixes are allocated before txs, as they are +// reached only through txs, and the correlate publishes each tx last. +TEMPLATE +bool CLASS::put_scan_(const system::wallet::silent_payment::rows& rows, + const std::span& links) NOEXCEPT +{ + using namespace system; + if (rows.empty()) + return true; - // Allocate the block's outputs, then its txs across all columns. Outputs - // are reached only through txs, so failure strands no unwritten tx. + const auto txs = rows.positions.size(); const auto pk = store_.scan_prefix.allocate( - possible_narrow_cast(rows)); + possible_narrow_cast(rows.prefixes.size())); if (pk.is_terminal()) return false; const auto fk = store_.scan.allocate( - possible_narrow_cast(captures.size())); + possible_narrow_cast(txs)); if (fk.is_terminal()) return false; // Guard against remap (required for nomaps::put(fk)). + using word_t = table::scan_correlate::tx::integer; const auto guard = store_.scan.guard(); const auto words = pointer_cast(guard.data()); + if (!store_.scan_prefix.put(pk, table::scan_prefix::put_span + { + {}, rows.prefixes + }) || + !store_.scan.point.put(fk, table::scan_point::put_span + { + {}, rows.points + }) || + !store_.scan.outputs.put(fk, table::scan_outputs::put_counts + { + {}, rows.outputs, pk.value + })) + return false; - auto tx = fk; - auto out = pk; - for (const auto& item: captures) + // The guard is the correlate column, published last (get_silent_frontier). + static_assert(schema::scan_correlate::minrow == sizeof(word_t)); + for (size_t tx{}; tx < txs; ++tx) { - const auto outputs = item.prefixes.size(); - if (!store_.scan_prefix.put(out, prefix_t{ {}, item.prefixes }) || - !store_.scan.point.put(tx, point_t{ {}, item.point }) || - !put_silent_(tx, item.link, out, outputs, words)) - return false; - - tx += one; - out += outputs; + const auto position = rows.positions.at(tx); + std::atomic_ref word{ *std::next(words, fk.value + tx) }; + word.store(native_to_little_end(*std::next(links.begin(), position)), + std::memory_order_release); } - store_.scan.complete(fk, - possible_narrow_cast(captures.size())); - return store_.state.set(to_state(link), scanned); - // ======================================================================== + store_.scan.complete(fk, possible_narrow_cast(txs)); + return true; } // Caller holds the transactor. @@ -610,61 +593,27 @@ bool CLASS::set_scanned_(bool bank) NOEXCEPT // Pooled txs linked below the coinbase were indexed (see set_silent). TEMPLATE -template -bool CLASS::set_silents_(size_t& rows, const header_link& link, - const Transactions& txs, bool bank) NOEXCEPT +template +bool CLASS::set_silents_(size_t& count, const header_link& link, + const Block& block, size_t txs, bool bank) NOEXCEPT { - struct capture - { - tx_link link{}; - ec_compressed sum{}; - ec_secret hash{}; - std::vector prefixes{}; - }; - - rows = zero; - const auto count = txs.size(); - if (is_one(count)) - return set_block_scanned(link); - + using namespace system; + using namespace system::wallet; + count = zero; const auto links = to_transactions(link); - if (links.size() != count) + if (links.size() != txs) return false; - // Object txs are held by pointer, views by value. - const auto to_tx = [](const auto& tx) NOEXCEPT -> decltype(auto) + auto& rows = silent_payment::rows::local(); + silent_payment::collect(rows, block, [&](size_t position) NOEXCEPT { - using type = std::decay_t; - if constexpr (is_same_type) - return (tx); - else - return (*tx); - }; - - using namespace system::wallet; - std::vector captures{}; - const auto first = links.front(); - for (auto index = one; index < count; ++index) - { - capture item{ links.at(index) }; - const auto& tx = to_tx(txs.at(index)); - if (is_silent_selected(item.link, first) && - get_prefixes(item.prefixes, tx) && - silent_payment::prepare(item.sum, item.hash, tx)) - { - rows += item.prefixes.size(); - captures.push_back(std::move(item)); - } - } + return is_silent_selected(links.at(position), links.front()); + }, false); - if (is_zero(rows)) + if (rows.empty()) return set_block_scanned(link); - using correlate_t = table::silent_correlate::record; - using sum_t = table::silent_sum::put_ref; - using hash_t = table::silent_hash::put_ref; - using outputs_t = table::silent_outputs::record; - using prefix_t = table::silent_prefix::put_refs; + count = rows.prefixes.size(); // ======================================================================== const auto scope = get_transactor(); @@ -677,38 +626,40 @@ bool CLASS::set_silents_(size_t& rows, const header_link& link, // Allocate the block's outputs, then its txs across all columns. Outputs // are reached only through txs, so failure strands no unwritten tx. - using namespace system; const auto pk = bank_prefix.allocate( - possible_narrow_cast(rows)); + possible_narrow_cast(count)); if (pk.is_terminal()) return false; const auto fk = bank_table.allocate( - possible_narrow_cast(captures.size())); + possible_narrow_cast(rows.positions.size())); if (fk.is_terminal()) return false; // Guard against remap (required for nomaps::put(fk)). const auto guard = bank_table.guard(); - auto tx = fk; - auto out = pk; - for (const auto& item: captures) - { - const auto outputs = item.prefixes.size(); - if (!bank_table.correlate.put(tx, correlate_t{ {}, item.link.value }) || - !bank_table.sum.put(tx, sum_t{ {}, item.sum }) || - !bank_table.hash.put(tx, hash_t{ {}, item.hash }) || - !bank_table.outputs.put(tx, outputs_t{ {}, out.value, - possible_narrow_cast(outputs) }) || - !bank_prefix.put(out, prefix_t{ {}, item.prefixes })) - return false; - - tx += one; - out += outputs; - } - - return true; + return + bank_table.correlate.put(fk, table::silent_correlate::put_rows + { + {}, rows.positions, links + }) && + bank_table.sum.put(fk, table::silent_sum::put_span + { + {}, rows.points + }) && + bank_table.hash.put(fk, table::silent_hash::put_span + { + {}, rows.hashes + }) && + bank_table.outputs.put(fk, table::silent_outputs::put_counts + { + {}, rows.outputs, pk.value + }) && + bank_prefix.put(pk, table::silent_prefix::put_span + { + {}, rows.prefixes + }); // ======================================================================== } @@ -719,83 +670,6 @@ bool CLASS::is_silent_selected(const tx_link& link, return link >= coinbase || !is_pooled(link); } -// The prefix is ec_xonly[0..7] read as little-endian. -TEMPLATE -template -bool CLASS::get_prefixes(std::vector& out, - const Transaction& tx) NOEXCEPT -{ - using namespace system; - using namespace system::wallet; - silent_payment::scan_outputs outputs{}; - if (!silent_payment::get_outputs(outputs, tx)) - return false; - - out.resize(outputs.size()); - std::transform(outputs.cbegin(), outputs.cend(), out.begin(), - [](const auto& output) NOEXCEPT - { - return unsafe_from_little_endian(output.key.data()); - }); - - return true; -} - -TEMPLATE -bool CLASS::set_silent_(const tx_link& link, const ec_compressed& point, - const std::vector& prefixes) NOEXCEPT -{ - if (link.is_terminal()) - return false; - - using namespace system; - using word_t = table::scan_correlate::tx::integer; - using point_t = table::scan_point::put_ref; - using prefix_t = table::scan_prefix::put_refs; - const auto outputs = prefixes.size(); - - // ======================================================================== - const auto scope = get_transactor(); - - // Allocate the tx across all columns, and its outputs. - const auto fk = store_.scan.allocate(one); - const auto pk = store_.scan_prefix.allocate( - possible_narrow_cast(outputs)); - if (fk.is_terminal() || pk.is_terminal()) - return false; - - // Guard against remap (required for nomaps::put(fk)). - const auto guard = store_.scan.guard(); - const auto words = pointer_cast(guard.data()); - if (!store_.scan_prefix.put(pk, prefix_t{ {}, prefixes }) || - !store_.scan.point.put(fk, point_t{ {}, point }) || - !put_silent_(fk, link, pk, outputs, words)) - return false; - - store_.scan.complete(fk, one); - return true; - // ======================================================================== -} - -TEMPLATE -bool CLASS::put_silent_(const scan_link& fk, const tx_link& link, - const prefix_link& first, size_t outputs, - table::scan_correlate::tx::integer* words) NOEXCEPT -{ - using namespace system; - using outputs_t = table::scan_outputs::record; - if (!store_.scan.outputs.put(fk, outputs_t{ {}, first.value, - possible_narrow_cast(outputs) })) - return false; - - // The guard is the correlate column, published last (get_silent_frontier). - using word_t = table::scan_correlate::tx::integer; - static_assert(schema::scan_correlate::minrow == sizeof(word_t)); - std::atomic_ref word{ *std::next(words, fk.value) }; - word.store(native_to_little_end(link.value), std::memory_order_release); - return true; -} - // Rows are read in chunks so the guard is not held across a long seek. TEMPLATE void CLASS::seek_scan_start(size_t& row, size_t& last, diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 6f431cd4c..8b321d8f8 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -763,8 +763,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, - bool gpu) NOEXCEPT; + code compute_silents(const stopper& cancel, bool& use_gpu, + bool bank) NOEXCEPT; /// Commit a block's captured ecdsa signature groups (band-expanded). bool set_signatures(const system::chain::ecdsa_signatures& sigs, @@ -801,12 +801,11 @@ class query /// if none mapped), a scan from it covers all blocks at or above height. scan_link get_scan_floor(size_t height) const NOEXCEPT; - /// 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, bool gpu) NOEXCEPT; - bool verify_schnorr_signatures(const stopper& cancel, header_links&, - bool& device, bool bank, bool gpu) NOEXCEPT; + /// Verify all signatures in table, false implies cancel. + bool verify_ecdsa_signatures(const stopper& cancel, bool& use_gpu, + header_links& links, bool bank) NOEXCEPT; + bool verify_schnorr_signatures(const stopper& cancel, bool& use_gpu, + header_links& links, bool bank) NOEXCEPT; /// Purge all entries in table. bool purge_prevalids(bool bank) NOEXCEPT; @@ -1195,29 +1194,23 @@ class query code set_txs(const header_link& key, tx_links&& links, size_t light, size_t heavy, hash_option&& interval, bool strong) NOEXCEPT; - /// Silent payment prefixes of a transaction's outputs, false if none. - template - static bool get_prefixes(std::vector& out, - const Transaction& tx) NOEXCEPT; - - /// Set silent payment records of a non-coinbase tx. - bool set_silent_(const tx_link& link, const ec_compressed& point, - const std::vector& prefixes) NOEXCEPT; - /// Advance row to the first row linked above floor, an unpublished row /// lowering last to itself (the row at or past which rows are unknown). void seek_scan_start(size_t& row, size_t& last, tx_link::integer floor) const NOEXCEPT; - /// Set silent payment records of a block's txs and its scanned state. - template - bool set_silent_(const header_link& link, - const Transactions& txs) NOEXCEPT; + /// Set silent payment records of a block's selected txs and its scanned + /// state, or of a tx. + template + bool set_silent_(const header_link& link, const Block& block, + size_t count) NOEXCEPT; + template + bool set_silent_(const tx_link& link, const Transaction& tx) NOEXCEPT; - /// Write a scan tx's outputs and publish it, caller must hold transactor. - bool put_silent_(const scan_link& fk, const tx_link& link, - const prefix_link& first, size_t outputs, - table::scan_correlate::tx::integer* words) NOEXCEPT; + /// Write scan records, the tx fk of each by its position in links, caller + /// must hold transactor. + bool put_scan_(const system::wallet::silent_payment::rows& rows, + const std::span& links) NOEXCEPT; /// A block's tx is indexed unless linked below its coinbase and pooled. bool is_silent_selected(const tx_link& link, @@ -1226,10 +1219,10 @@ class query /// Mark the blocks of a bank's presilent table scanned. bool set_scanned_(bool bank) NOEXCEPT; - /// Commit the silent payment batch rows of a block's txs. - template - bool set_silents_(size_t& rows, const header_link& link, - const Transactions& txs, bool bank) NOEXCEPT; + /// Commit the silent payment batch rows of a block's selected txs. + template + bool set_silents_(size_t& count, const header_link& link, + const Block& block, size_t txs, bool bank) NOEXCEPT; /// Pooling. /// ----------------------------------------------------------------------- diff --git a/include/bitcoin/database/settings.hpp b/include/bitcoin/database/settings.hpp index e7b053a95..b2b04d992 100644 --- a/include/bitcoin/database/settings.hpp +++ b/include/bitcoin/database/settings.hpp @@ -73,7 +73,7 @@ struct BCD_API settings /// Enable concurrency in individual client-server queries. bool turbo{ false }; - /// Minimum transactions for a silent payment scan on the device. + /// Minimum transactions for a silent payment scan on gpu. uint32_t gpu_scan_minimum{ 65'536 }; /// Mark blocks as unconfirmable (disorganize vs. stall). diff --git a/include/bitcoin/database/store.hpp b/include/bitcoin/database/store.hpp index f70cb5cb9..adc40d8a2 100644 --- a/include/bitcoin/database/store.hpp +++ b/include/bitcoin/database/store.hpp @@ -88,7 +88,7 @@ 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. + /// Minimum transactions for a silent payment scan on gpu. size_t gpu_scan_minimum() const NOEXCEPT; /// Mark blocks as unconfirmable (disorganize vs. stall), configuration. diff --git a/include/bitcoin/database/tables/caches/silent.hpp b/include/bitcoin/database/tables/caches/silent.hpp index 346f1a707..c0f2ab11d 100644 --- a/include/bitcoin/database/tables/caches/silent.hpp +++ b/include/bitcoin/database/tables/caches/silent.hpp @@ -60,6 +60,30 @@ struct silent_correlate tx::integer tx_fk{}; }; + + /// The tx fk of each row, by its block position. + struct put_rows + : public schema::silent_correlate + { + inline link count() const NOEXCEPT + { + using namespace system; + return possible_narrow_cast(positions.size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + for (const auto position: positions) + sink.write_little_endian( + *std::next(links.begin(), position)); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const std::span positions; + const std::span links; + }; }; /// silent_sum is an array of silent payment batch input key sums. @@ -85,6 +109,27 @@ struct silent_sum const system::ec_compressed& sum; }; + + struct put_span + : public schema::silent_sum + { + inline link count() const NOEXCEPT + { + using namespace system; + return possible_narrow_cast(sums.size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + for (const auto& sum: sums) + sink.write_bytes(sum); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const std::span sums; + }; }; /// silent_hash is an array of silent payment batch input hashes. @@ -110,6 +155,27 @@ struct silent_hash const system::ec_secret& hash; }; + + struct put_span + : public schema::silent_hash + { + inline link count() const NOEXCEPT + { + using namespace system; + return possible_narrow_cast(hashes.size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + for (const auto& hash: hashes) + sink.write_bytes(hash); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const std::span hashes; + }; }; /// silent_outputs is an array of silent payment batch tx prefix spans. @@ -146,6 +212,34 @@ struct silent_outputs prefix::integer first{}; uint32_t outputs{}; }; + + /// The prefix span of each row, prefixes contiguous from first. + struct put_counts + : public schema::silent_outputs + { + inline link count() const NOEXCEPT + { + using namespace system; + return possible_narrow_cast(outputs.size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + auto next = first; + for (const auto output: outputs) + { + sink.write_little_endian(next); + sink.write_little_endian(output); + next += output; + } + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const std::span outputs; + const prefix::integer first; + }; }; /// silent_prefix is an array of silent payment batch output key prefixes. @@ -176,6 +270,27 @@ struct silent_prefix const std::vector& prefixes; }; + + struct put_span + : public schema::silent_prefix + { + inline link count() const NOEXCEPT + { + using namespace system; + return possible_narrow_cast(prefixes.size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + for (const auto& prefix: prefixes) + sink.write_bytes(prefix); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const std::span prefixes; + }; }; /// Aggregate (files) diff --git a/include/bitcoin/database/tables/indexes/scan.hpp b/include/bitcoin/database/tables/indexes/scan.hpp index 382331b6e..7326e3ee0 100644 --- a/include/bitcoin/database/tables/indexes/scan.hpp +++ b/include/bitcoin/database/tables/indexes/scan.hpp @@ -85,6 +85,27 @@ struct scan_point const system::ec_compressed& point; }; + + struct put_span + : public schema::scan_point + { + inline link count() const NOEXCEPT + { + using namespace system; + return possible_narrow_cast(points.size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + for (const auto& point: points) + sink.write_bytes(point); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const std::span points; + }; }; /// scan_outputs is an array of silent payment transaction prefix spans. @@ -121,6 +142,34 @@ struct scan_outputs prefix::integer first{}; uint32_t outputs{}; }; + + /// The prefix span of each row, prefixes contiguous from first. + struct put_counts + : public schema::scan_outputs + { + inline link count() const NOEXCEPT + { + using namespace system; + return possible_narrow_cast(outputs.size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + auto next = first; + for (const auto output: outputs) + { + sink.write_little_endian(next); + sink.write_little_endian(output); + next += output; + } + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const std::span outputs; + const prefix::integer first; + }; }; /// scan_prefix is an array of silent payment output key prefixes. diff --git a/test/query/batch/ecdsa.cpp b/test/query/batch/ecdsa.cpp index ac1ed9343..a20c48093 100644 --- a/test/query/batch/ecdsa.cpp +++ b/test/query/batch/ecdsa.cpp @@ -59,9 +59,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__empty__empty) test::query_accessor query{ store }; header_links links{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 0u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, use_gpu, links, false)); BOOST_REQUIRE(links.empty()); } @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_valid__empt BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42, false)); header_links links{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 1u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, use_gpu, links, false)); BOOST_REQUIRE(links.empty()); } @@ -87,11 +87,11 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_valid_witho BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42, false)); header_links links{}; - bool device{}; + bool use_gpu{ false }; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 1u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, false)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, use_gpu, links, false)); BOOST_REQUIRE(links.empty()); - BOOST_REQUIRE(!device); + BOOST_REQUIRE(!use_gpu); } BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_invalid__expected_link) @@ -103,9 +103,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_invalid__ex BOOST_REQUIRE(set_one(query, sighash_bad, ecdsa_compressed, ecdsa_signature, expected, false)); header_links links{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 1u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, use_gpu, links, false)); BOOST_REQUIRE_EQUAL(links.size(), 1u); BOOST_REQUIRE_EQUAL(links.front(), expected); } @@ -128,9 +128,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__various__expect BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 6, false)); header_links links{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), 8u); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, use_gpu, links, false)); BOOST_REQUIRE_EQUAL(links.size(), 2u); const auto back = links.back(); @@ -150,10 +150,10 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__banks__independ BOOST_REQUIRE_EQUAL(query.ecdsa_records(true), 1u); header_links links{}; - bool device{}; - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, false, true)); + bool use_gpu{ true }; + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, use_gpu, links, false)); BOOST_REQUIRE(links.empty()); - BOOST_REQUIRE(query.verify_ecdsa_signatures({}, links, device, true, true)); + BOOST_REQUIRE(query.verify_ecdsa_signatures({}, use_gpu, links, 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 8e550f4d3..686fe5f24 100644 --- a/test/query/batch/schnorr.cpp +++ b/test/query/batch/schnorr.cpp @@ -59,9 +59,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__empty__empty) test::query_accessor query{ store }; header_links links{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 0u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, true)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, use_gpu, links, false)); BOOST_REQUIRE(links.empty()); } @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_valid__em BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 42)); header_links links{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 1u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, true)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, use_gpu, links, false)); BOOST_REQUIRE(links.empty()); } @@ -87,11 +87,11 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_valid_wit BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 42)); header_links links{}; - bool device{}; + bool use_gpu{ false }; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 1u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, false)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, use_gpu, links, false)); BOOST_REQUIRE(links.empty()); - BOOST_REQUIRE(!device); + BOOST_REQUIRE(!use_gpu); } BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_invalid__expected_link) @@ -103,9 +103,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_invalid__ BOOST_REQUIRE(set_one(query, sighash_bad, schnorr_xonly, schnorr_signature, expected)); header_links links{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 1u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, true)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, use_gpu, links, false)); BOOST_REQUIRE_EQUAL(links.size(), 1u); BOOST_REQUIRE_EQUAL(links.front(), expected); } @@ -128,9 +128,9 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__various__expe BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 6)); header_links links{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE_EQUAL(query.schnorr0_records(), 8u); - BOOST_REQUIRE(query.verify_schnorr_signatures({}, links, device, false, true)); + BOOST_REQUIRE(query.verify_schnorr_signatures({}, use_gpu, links, false)); 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 7cf2b7317..d5e68dd4c 100644 --- a/test/query/batch/silent.cpp +++ b/test/query/batch/silent.cpp @@ -475,9 +475,9 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__banked_row__scanned) size_t rows{}; const stopper cancel{}; - bool device{}; + bool use_gpu{ true }; BOOST_REQUIRE(query.set_silents(rows, link, block, false)); - BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false, true), database::error::success); + BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, use_gpu, false), database::error::success); BOOST_REQUIRE_EQUAL(query.scan_records(), 1u); std::vector links{}; @@ -506,11 +506,11 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__banked_row_without_gpu size_t rows{}; const stopper cancel{}; - bool device{}; + bool use_gpu{ false }; 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.compute_silents(cancel, use_gpu, false), database::error::success); BOOST_REQUIRE_EQUAL(query.scan_records(), 1u); - BOOST_REQUIRE(!device); + BOOST_REQUIRE(!use_gpu); std::vector links{}; const auto handler = [&](const code&, tx_link_t link, const ec_compressed&) NOEXCEPT @@ -532,8 +532,8 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__empty__success) BOOST_REQUIRE(query.initialize(test::genesis)); const stopper cancel{}; - bool device{}; - BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, device, false, true), database::error::success); + bool use_gpu{ true }; + BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, use_gpu, false), database::error::success); BOOST_REQUIRE_EQUAL(query.scan_records(), 0u); } @@ -572,10 +572,10 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__compute_silents__presilent_banked_row__ size_t rows{}; const stopper cancel{}; - bool device{}; + bool use_gpu{ true }; 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, true), database::error::success); + BOOST_REQUIRE_EQUAL(query.compute_silents(cancel, use_gpu, false), database::error::success); BOOST_REQUIRE(is_scanned(query.get_block_state(link))); }