diff --git a/Makefile.am b/Makefile.am index 5dcaedea9..095699911 100644 --- a/Makefile.am +++ b/Makefile.am @@ -101,6 +101,7 @@ test_libbitcoin_database_test_SOURCES = \ test/query/properties_block.cpp \ test/query/properties_tx.cpp \ test/query/sequences.cpp \ + test/query/signatures.cpp \ test/query/sizes.cpp \ test/query/address/address_balance.cpp \ test/query/address/address_history.cpp \ @@ -134,7 +135,9 @@ test_libbitcoin_database_test_SOURCES = \ test/tables/archives/transaction.cpp \ test/tables/archives/txs.cpp \ test/tables/caches/duplicate.cpp \ + test/tables/caches/ecdsa.cpp \ test/tables/caches/prevout.cpp \ + test/tables/caches/schnorr.cpp \ test/tables/caches/validated_bk.cpp \ test/tables/caches/validated_tx.cpp \ test/tables/indexes/height.cpp \ @@ -217,6 +220,7 @@ include_bitcoin_database_impl_query_HEADERS = \ include/bitcoin/database/impl/query/properties_tx.ipp \ include/bitcoin/database/impl/query/query.ipp \ include/bitcoin/database/impl/query/sequences.ipp \ + include/bitcoin/database/impl/query/signatures.ipp \ include/bitcoin/database/impl/query/sizes.ipp include_bitcoin_database_impl_query_addressdir = ${includedir}/bitcoin/database/impl/query/address @@ -316,7 +320,9 @@ include_bitcoin_database_tables_archives_HEADERS = \ include_bitcoin_database_tables_cachesdir = ${includedir}/bitcoin/database/tables/caches include_bitcoin_database_tables_caches_HEADERS = \ include/bitcoin/database/tables/caches/duplicate.hpp \ + include/bitcoin/database/tables/caches/ecdsa.hpp \ include/bitcoin/database/tables/caches/prevout.hpp \ + include/bitcoin/database/tables/caches/schnorr.hpp \ include/bitcoin/database/tables/caches/validated_bk.hpp \ include/bitcoin/database/tables/caches/validated_tx.hpp diff --git a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj index ed7e9387b..e580d4c1b 100644 --- a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj @@ -184,6 +184,7 @@ + @@ -196,7 +197,9 @@ + + diff --git a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters index 4aac69976..7a3eb8dd2 100644 --- a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters @@ -228,6 +228,9 @@ src\query + + src\query + src\query @@ -264,9 +267,15 @@ src\tables\caches + + src\tables\caches + src\tables\caches + + src\tables\caches + src\tables\caches diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj index 975ce9478..8f7f605e1 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj @@ -186,7 +186,9 @@ + + @@ -260,6 +262,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters index f867d21d4..9ce1ddeb1 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -269,9 +269,15 @@ include\bitcoin\database\tables\caches + + include\bitcoin\database\tables\caches + include\bitcoin\database\tables\caches + + include\bitcoin\database\tables\caches + include\bitcoin\database\tables\caches @@ -487,6 +493,9 @@ include\bitcoin\database\impl\query + + include\bitcoin\database\impl\query + include\bitcoin\database\impl\query diff --git a/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj b/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj index fb97dc000..ae03f69dd 100644 --- a/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj +++ b/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj @@ -184,6 +184,7 @@ + @@ -196,7 +197,9 @@ + + diff --git a/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters index 4aac69976..7a3eb8dd2 100644 --- a/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters +++ b/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters @@ -228,6 +228,9 @@ src\query + + src\query + src\query @@ -264,9 +267,15 @@ src\tables\caches + + src\tables\caches + src\tables\caches + + src\tables\caches + src\tables\caches diff --git a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj index 0642cc7e9..cd33d4049 100644 --- a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj @@ -186,7 +186,9 @@ + + @@ -260,6 +262,7 @@ + diff --git a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters index f867d21d4..9ce1ddeb1 100644 --- a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -269,9 +269,15 @@ include\bitcoin\database\tables\caches + + include\bitcoin\database\tables\caches + include\bitcoin\database\tables\caches + + include\bitcoin\database\tables\caches + include\bitcoin\database\tables\caches @@ -487,6 +493,9 @@ include\bitcoin\database\impl\query + + include\bitcoin\database\impl\query + include\bitcoin\database\impl\query diff --git a/include/bitcoin/database.hpp b/include/bitcoin/database.hpp index c7fbe314c..2959ad983 100644 --- a/include/bitcoin/database.hpp +++ b/include/bitcoin/database.hpp @@ -67,7 +67,9 @@ #include #include #include +#include #include +#include #include #include #include diff --git a/include/bitcoin/database/impl/query/extent.ipp b/include/bitcoin/database/impl/query/extent.ipp index b330dab21..d30e24579 100644 --- a/include/bitcoin/database/impl/query/extent.ipp +++ b/include/bitcoin/database/impl/query/extent.ipp @@ -91,6 +91,8 @@ size_t CLASS::store_body_size() const NOEXCEPT + candidate_body_size() + confirmed_body_size() + strong_tx_body_size() + + ecdsa_body_size() + + schnorr_body_size() + duplicate_body_size() + prevout_body_size() + validated_bk_body_size() @@ -120,6 +122,8 @@ size_t CLASS::store_head_size() const NOEXCEPT + candidate_head_size() + confirmed_head_size() + strong_tx_head_size() + + ecdsa_head_size() + + schnorr_head_size() + duplicate_head_size() + prevout_head_size() + validated_bk_head_size() @@ -144,6 +148,8 @@ DEFINE_SIZES(tx) DEFINE_SIZES(candidate) DEFINE_SIZES(confirmed) DEFINE_SIZES(strong_tx) +DEFINE_SIZES(ecdsa) +DEFINE_SIZES(schnorr) DEFINE_SIZES(duplicate) DEFINE_SIZES(prevout) DEFINE_SIZES(validated_bk) @@ -181,6 +187,8 @@ DEFINE_RECORDS(tx) DEFINE_RECORDS(candidate) DEFINE_RECORDS(confirmed) DEFINE_RECORDS(strong_tx) +DEFINE_RECORDS(ecdsa) +DEFINE_RECORDS(schnorr) DEFINE_RECORDS(duplicate) DEFINE_RECORDS(filter_bk) DEFINE_RECORDS(address) diff --git a/include/bitcoin/database/impl/query/signatures.ipp b/include/bitcoin/database/impl/query/signatures.ipp new file mode 100644 index 000000000..9d352430c --- /dev/null +++ b/include/bitcoin/database/impl/query/signatures.ipp @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#ifndef LIBBITCOIN_DATABASE_QUERY_SIGNATURES_IPP +#define LIBBITCOIN_DATABASE_QUERY_SIGNATURES_IPP + +#include + +namespace libbitcoin { +namespace database { + +TEMPLATE +bool CLASS::set_signature(const hash_digest& digest, const ec_compressed& point, + const ec_signature& signature, const header_link& link) NOEXCEPT +{ + // ======================================================================== + const auto scope = store_.get_transactor(); + + // Clean single allocation failure (e.g. disk full). + return store_.ecdsa.put(table::ecdsa::record + { + {}, + digest, + point, + signature, + link + }); + // ======================================================================== +} + +TEMPLATE +bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point, + const ec_signature& signature, const header_link& link) NOEXCEPT +{ + // ======================================================================== + const auto scope = store_.get_transactor(); + + // Clean single allocation failure (e.g. disk full). + return store_.schnorr.put(table::schnorr::record + { + {}, + digest, + point, + signature, + link + }); + // ======================================================================== +} + +} // namespace database +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/database/impl/store.ipp b/include/bitcoin/database/impl/store.ipp index 575859e2d..29199dced 100644 --- a/include/bitcoin/database/impl/store.ipp +++ b/include/bitcoin/database/impl/store.ipp @@ -103,6 +103,12 @@ const std::unordered_map CLASS::tables { table_t::strong_tx_body, "strong_tx_body" }, // Caches. + { table_t::ecdsa_table, "ecdsa_table" }, + { table_t::ecdsa_head, "ecdsa_head" }, + { table_t::ecdsa_body, "ecdsa_body" }, + { table_t::schnorr_table, "schnorr_table" }, + { table_t::schnorr_head, "schnorr_head" }, + { table_t::schnorr_body, "schnorr_body" }, { table_t::duplicate_table, "duplicate_table" }, { table_t::duplicate_head, "duplicate_head" }, { table_t::duplicate_body, "duplicate_body" }, @@ -137,90 +143,105 @@ CLASS::store(const settings& config) NOEXCEPT header_head_(head(config.path / schema::dir::heads, schema::archive::header), 1, 0, random), header_body_(body(config.path, schema::archive::header), config.header_size, config.header_rate, sequential), - header(header_head_, header_body_, config.header_buckets), input_head_(head(config.path / schema::dir::heads, schema::archive::input), 1, 0, random), input_body_(body(config.path, schema::archive::input), config.input_size, config.input_rate, sequential), - input(input_head_, input_body_), output_head_(head(config.path / schema::dir::heads, schema::archive::output), 1, 0, random), output_body_(body(config.path, schema::archive::output), config.output_size, config.output_rate, sequential), - output(output_head_, output_body_), point_head_(head(config.path / schema::dir::heads, schema::archive::point), 1, 0, random), point_body_(body(config.path, schema::archive::point), config.point_size, config.point_rate, sequential), - point(point_head_, point_body_, config.point_buckets), ins_head_(head(config.path / schema::dir::heads, schema::archive::ins), 1, 0, random), ins_body_(body(config.path, schema::archive::ins), config.ins_size, config.ins_rate, sequential), - ins(ins_head_, ins_body_), outs_head_(head(config.path / schema::dir::heads, schema::archive::outs), 1, 0, random), outs_body_(body(config.path, schema::archive::outs), config.outs_size, config.outs_rate, sequential), - outs(outs_head_, outs_body_), tx_head_(head(config.path / schema::dir::heads, schema::archive::tx), 1, 0, random), tx_body_(body(config.path, schema::archive::tx), config.tx_size, config.tx_rate, sequential), - tx(tx_head_, tx_body_, config.tx_buckets), txs_head_(head(config.path / schema::dir::heads, schema::archive::txs), 1, 0, random), txs_body_(body(config.path, schema::archive::txs), config.txs_size, config.txs_rate, sequential), - txs(txs_head_, txs_body_, config.txs_buckets), // Indexes. // ------------------------------------------------------------------------ candidate_head_(head(config.path / schema::dir::heads, schema::indexes::candidate), 1, 0, random), candidate_body_(body(config.path, schema::indexes::candidate), config.candidate_size, config.candidate_rate, sequential), - candidate(candidate_head_, candidate_body_), confirmed_head_(head(config.path / schema::dir::heads, schema::indexes::confirmed), 1, 0, random), confirmed_body_(body(config.path, schema::indexes::confirmed), config.confirmed_size, config.confirmed_rate, sequential), - confirmed(confirmed_head_, confirmed_body_), strong_tx_head_(head(config.path / schema::dir::heads, schema::indexes::strong_tx), 1, 0, random), strong_tx_body_(body(config.path, schema::indexes::strong_tx), config.strong_tx_size, config.strong_tx_rate, sequential), - strong_tx(strong_tx_head_, strong_tx_body_, config.strong_tx_buckets), // Caches. // ------------------------------------------------------------------------ + ecdsa_head_(head(config.path / schema::dir::heads, schema::caches::ecdsa), 1, 0, random), + ecdsa_body_(body(config.path, schema::caches::ecdsa), config.ecdsa_size, config.ecdsa_rate, sequential), + + schnorr_head_(head(config.path / schema::dir::heads, schema::caches::schnorr), 1, 0, random), + schnorr_body_(body(config.path, schema::caches::schnorr), config.schnorr_size, config.schnorr_rate, sequential), + duplicate_head_(head(config.path / schema::dir::heads, schema::caches::duplicate), 1, 0, random), duplicate_body_(body(config.path, schema::caches::duplicate), config.duplicate_size, config.duplicate_rate, sequential), - duplicate(duplicate_head_, duplicate_body_, config.duplicate_buckets), prevout_head_(head(config.path / schema::dir::heads, schema::caches::prevout), 1, 0, random), prevout_body_(body(config.path, schema::caches::prevout), config.prevout_size, config.prevout_rate, sequential), - prevout(prevout_head_, prevout_body_, config.prevout_buckets), validated_bk_head_(head(config.path / schema::dir::heads, schema::caches::validated_bk), 1, 0, random), validated_bk_body_(body(config.path, schema::caches::validated_bk), config.validated_bk_size, config.validated_bk_rate, sequential), - validated_bk(validated_bk_head_, validated_bk_body_, config.validated_bk_buckets), validated_tx_head_(head(config.path / schema::dir::heads, schema::caches::validated_tx), 1, 0, random), validated_tx_body_(body(config.path, schema::caches::validated_tx), config.validated_tx_size, config.validated_tx_rate, sequential), - validated_tx(validated_tx_head_, validated_tx_body_, config.validated_tx_buckets), // Optionals. // ------------------------------------------------------------------------ address_head_(head(config.path / schema::dir::heads, schema::optionals::address), 1, 0, random), address_body_(body(config.path, schema::optionals::address), config.address_size, config.address_rate, sequential), - address(address_head_, address_body_, config.address_buckets), filter_bk_head_(head(config.path / schema::dir::heads, schema::optionals::filter_bk), 1, 0, random), filter_bk_body_(body(config.path, schema::optionals::filter_bk), config.filter_bk_size, config.filter_bk_rate, sequential), - filter_bk(filter_bk_head_, filter_bk_body_, config.filter_bk_buckets), filter_tx_head_(head(config.path / schema::dir::heads, schema::optionals::filter_tx), 1, 0, random), filter_tx_body_(body(config.path, schema::optionals::filter_tx), config.filter_tx_size, config.filter_tx_rate, sequential), - filter_tx(filter_tx_head_, filter_tx_body_, config.filter_tx_buckets), // Locks. // ------------------------------------------------------------------------ flush_lock_(lock(config.path, schema::locks::flush)), - process_lock_(lock(config.path, schema::locks::process)) + process_lock_(lock(config.path, schema::locks::process)), + + // Tables. + // ------------------------------------------------------------------------ + + header(header_head_, header_body_, config.header_buckets), + input(input_head_, input_body_), + output(output_head_, output_body_), + point(point_head_, point_body_, config.point_buckets), + ins(ins_head_, ins_body_), + outs(outs_head_, outs_body_), + tx(tx_head_, tx_body_, config.tx_buckets), + txs(txs_head_, txs_body_, config.txs_buckets), + + candidate(candidate_head_, candidate_body_), + confirmed(confirmed_head_, confirmed_body_), + strong_tx(strong_tx_head_, strong_tx_body_, config.strong_tx_buckets), + + ecdsa(ecdsa_head_, ecdsa_body_), + schnorr(schnorr_head_, schnorr_body_), + duplicate(duplicate_head_, duplicate_body_, config.duplicate_buckets), + prevout(prevout_head_, prevout_body_, config.prevout_buckets), + validated_bk(validated_bk_head_, validated_bk_body_, config.validated_bk_buckets), + validated_tx(validated_tx_head_, validated_tx_body_, config.validated_tx_buckets), + + address(address_head_, address_body_, config.address_buckets), + filter_bk(filter_bk_head_, filter_bk_body_, config.filter_bk_buckets), + filter_tx(filter_tx_head_, filter_tx_body_, config.filter_tx_buckets) { } @@ -294,6 +315,10 @@ code CLASS::create(const event_handler& handler) NOEXCEPT create(ec, strong_tx_head_, table_t::strong_tx_head); create(ec, strong_tx_body_, table_t::strong_tx_body); + create(ec, ecdsa_head_, table_t::ecdsa_head); + create(ec, ecdsa_body_, table_t::ecdsa_body); + create(ec, schnorr_head_, table_t::schnorr_head); + create(ec, schnorr_body_, table_t::schnorr_body); create(ec, duplicate_head_, table_t::duplicate_head); create(ec, duplicate_body_, table_t::duplicate_body); create(ec, prevout_head_, table_t::prevout_head); @@ -337,6 +362,8 @@ code CLASS::create(const event_handler& handler) NOEXCEPT populate(ec, confirmed, table_t::confirmed_table); populate(ec, strong_tx, table_t::strong_tx_table); + populate(ec, ecdsa, table_t::ecdsa_table); + populate(ec, schnorr, table_t::schnorr_table); populate(ec, duplicate, table_t::duplicate_table); populate(ec, prevout, table_t::prevout_table); populate(ec, validated_bk, table_t::validated_bk_table); @@ -410,6 +437,8 @@ code CLASS::open(const event_handler& handler) NOEXCEPT verify(ec, confirmed, table_t::confirmed_table); verify(ec, strong_tx, table_t::strong_tx_table); + verify(ec, ecdsa, table_t::ecdsa_table); + verify(ec, schnorr, table_t::schnorr_table); verify(ec, duplicate, table_t::duplicate_table); verify(ec, prevout, table_t::prevout_table); verify(ec, validated_bk, table_t::validated_bk_table); @@ -526,6 +555,8 @@ code CLASS::snapshot(const event_handler& handler, bool prune) NOEXCEPT flush(ec, confirmed_body_, table_t::confirmed_body); flush(ec, strong_tx_body_, table_t::strong_tx_body); + flush(ec, ecdsa_body_, table_t::ecdsa_body); + flush(ec, schnorr_body_, table_t::schnorr_body); flush(ec, duplicate_body_, table_t::duplicate_body); if (!prune) flush(ec, prevout_body_, table_t::prevout_body); flush(ec, validated_bk_body_, table_t::validated_bk_body); @@ -588,6 +619,10 @@ code CLASS::reload(const event_handler& handler) NOEXCEPT reload(ec, strong_tx_head_, table_t::strong_tx_head); reload(ec, strong_tx_body_, table_t::strong_tx_body); + reload(ec, ecdsa_head_, table_t::ecdsa_head); + reload(ec, ecdsa_body_, table_t::ecdsa_body); + reload(ec, schnorr_head_, table_t::schnorr_head); + reload(ec, schnorr_body_, table_t::schnorr_body); reload(ec, duplicate_head_, table_t::duplicate_head); reload(ec, duplicate_body_, table_t::duplicate_body); reload(ec, prevout_head_, table_t::prevout_head); @@ -641,6 +676,8 @@ code CLASS::close(const event_handler& handler) NOEXCEPT close(ec, confirmed, table_t::confirmed_table); close(ec, strong_tx, table_t::strong_tx_table); + close(ec, ecdsa, table_t::ecdsa_table); + close(ec, schnorr, table_t::schnorr_table); close(ec, duplicate, table_t::duplicate_table); close(ec, prevout, table_t::prevout_table); close(ec, validated_bk, table_t::validated_bk_table); @@ -706,6 +743,10 @@ code CLASS::open_load(const event_handler& handler) NOEXCEPT open(ec, strong_tx_head_, table_t::strong_tx_head); open(ec, strong_tx_body_, table_t::strong_tx_body); + open(ec, ecdsa_head_, table_t::ecdsa_head); + open(ec, ecdsa_body_, table_t::ecdsa_body); + open(ec, schnorr_head_, table_t::schnorr_head); + open(ec, schnorr_body_, table_t::schnorr_body); open(ec, duplicate_head_, table_t::duplicate_head); open(ec, duplicate_body_, table_t::duplicate_body); open(ec, prevout_head_, table_t::prevout_head); @@ -755,6 +796,10 @@ code CLASS::open_load(const event_handler& handler) NOEXCEPT load(ec, strong_tx_head_, table_t::strong_tx_head); load(ec, strong_tx_body_, table_t::strong_tx_body); + load(ec, ecdsa_head_, table_t::ecdsa_head); + load(ec, ecdsa_body_, table_t::ecdsa_body); + load(ec, schnorr_head_, table_t::schnorr_head); + load(ec, schnorr_body_, table_t::schnorr_body); load(ec, duplicate_head_, table_t::duplicate_head); load(ec, duplicate_body_, table_t::duplicate_body); load(ec, prevout_head_, table_t::prevout_head); @@ -814,6 +859,10 @@ code CLASS::unload_close(const event_handler& handler) NOEXCEPT unload(ec, strong_tx_head_, table_t::strong_tx_head); unload(ec, strong_tx_body_, table_t::strong_tx_body); + unload(ec, ecdsa_head_, table_t::ecdsa_head); + unload(ec, ecdsa_body_, table_t::ecdsa_body); + unload(ec, schnorr_head_, table_t::schnorr_head); + unload(ec, schnorr_body_, table_t::schnorr_body); unload(ec, duplicate_head_, table_t::duplicate_head); unload(ec, duplicate_body_, table_t::duplicate_body); unload(ec, prevout_head_, table_t::prevout_head); @@ -863,6 +912,10 @@ code CLASS::unload_close(const event_handler& handler) NOEXCEPT close(ec, strong_tx_head_, table_t::strong_tx_head); close(ec, strong_tx_body_, table_t::strong_tx_body); + close(ec, ecdsa_head_, table_t::ecdsa_head); + close(ec, ecdsa_body_, table_t::ecdsa_body); + close(ec, schnorr_head_, table_t::schnorr_head); + close(ec, schnorr_body_, table_t::schnorr_body); close(ec, duplicate_head_, table_t::duplicate_head); close(ec, duplicate_body_, table_t::duplicate_body); close(ec, prevout_head_, table_t::prevout_head); @@ -910,6 +963,8 @@ code CLASS::backup(const event_handler& handler, bool prune) NOEXCEPT backup(ec, confirmed, table_t::confirmed_table); backup(ec, strong_tx, table_t::strong_tx_table); + backup(ec, ecdsa, table_t::ecdsa_table); + backup(ec, schnorr, table_t::schnorr_table); backup(ec, duplicate, table_t::duplicate_table); backup(ec, prevout, table_t::prevout_table, prune); backup(ec, validated_bk, table_t::validated_bk_table); @@ -975,6 +1030,8 @@ code CLASS::dump(const path& folder, auto confirmed_buffer = confirmed_head_.get(); auto strong_tx_buffer = strong_tx_head_.get(); + auto ecdsa_buffer = ecdsa_head_.get(); + auto schnorr_buffer = schnorr_head_.get(); auto duplicate_buffer = duplicate_head_.get(); auto prevout_buffer = prevout_head_.get(); auto validated_bk_buffer = validated_bk_head_.get(); @@ -997,6 +1054,8 @@ code CLASS::dump(const path& folder, if (!confirmed_buffer) return error::unloaded_file; if (!strong_tx_buffer) return error::unloaded_file; + if (!ecdsa_buffer) return error::unloaded_file; + if (!schnorr_buffer) return error::unloaded_file; if (!duplicate_buffer) return error::unloaded_file; if (!prevout_buffer) return error::unloaded_file; if (!validated_bk_buffer) return error::unloaded_file; @@ -1031,6 +1090,8 @@ code CLASS::dump(const path& folder, dump(ec, confirmed_buffer, schema::indexes::confirmed, table_t::confirmed_head); dump(ec, strong_tx_buffer, schema::indexes::strong_tx, table_t::strong_tx_head); + dump(ec, ecdsa_buffer, schema::caches::ecdsa, table_t::ecdsa_head); + dump(ec, schnorr_buffer, schema::caches::schnorr, table_t::schnorr_head); dump(ec, duplicate_buffer, schema::caches::duplicate, table_t::duplicate_head); dump(ec, prevout_buffer, schema::caches::prevout, table_t::prevout_head); dump(ec, validated_bk_buffer, schema::caches::validated_bk, table_t::validated_bk_head); @@ -1124,6 +1185,8 @@ code CLASS::restore(const event_handler& handler) NOEXCEPT restore(ec, confirmed, table_t::confirmed_table); restore(ec, strong_tx, table_t::strong_tx_table); + restore(ec, ecdsa, table_t::ecdsa_table); + restore(ec, schnorr, table_t::schnorr_table); restore(ec, duplicate, table_t::duplicate_table); restore(ec, prevout, table_t::prevout_table); restore(ec, validated_bk, table_t::validated_bk_table); @@ -1187,6 +1250,8 @@ code CLASS::get_fault() const NOEXCEPT if ((ec = candidate_body_.get_fault())) return ec; if ((ec = confirmed_body_.get_fault())) return ec; if ((ec = strong_tx_body_.get_fault())) return ec; + if ((ec = ecdsa_body_.get_fault())) return ec; + if ((ec = schnorr_body_.get_fault())) return ec; if ((ec = duplicate_body_.get_fault())) return ec; if ((ec = prevout_body_.get_fault())) return ec; if ((ec = validated_bk_body_.get_fault())) return ec; @@ -1217,6 +1282,8 @@ size_t CLASS::get_space() const NOEXCEPT space(candidate_body_); space(confirmed_body_); space(strong_tx_body_); + space(ecdsa_body_); + space(schnorr_body_); space(duplicate_body_); space(prevout_body_); space(validated_bk_body_); @@ -1251,6 +1318,8 @@ void CLASS::report(const error_handler& handler) const NOEXCEPT report(candidate_body_, table_t::candidate_body); report(confirmed_body_, table_t::confirmed_body); report(strong_tx_body_, table_t::strong_tx_body); + report(ecdsa_body_, table_t::ecdsa_body); + report(schnorr_body_, table_t::schnorr_body); report(duplicate_body_, table_t::duplicate_body); report(prevout_body_, table_t::prevout_body); report(validated_bk_body_, table_t::validated_bk_body); diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index a936ce35a..1bddcf0d8 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -53,6 +53,9 @@ class query using chain_state = system::chain::chain_state; using chain_state_cptr = system::chain::chain_state::cptr; using chain_context = system::chain::context; + using ec_compressed = system::ec_compressed; + using ec_signature = system::ec_signature; + using ec_xonly = system::ec_xonly; query(Store& store) NOEXCEPT; @@ -118,6 +121,8 @@ class query size_t candidate_head_size() const NOEXCEPT; size_t confirmed_head_size() const NOEXCEPT; size_t strong_tx_head_size() const NOEXCEPT; + size_t ecdsa_head_size() const NOEXCEPT; + size_t schnorr_head_size() const NOEXCEPT; size_t duplicate_head_size() const NOEXCEPT; size_t prevout_head_size() const NOEXCEPT; size_t validated_bk_head_size() const NOEXCEPT; @@ -139,6 +144,8 @@ class query size_t candidate_body_size() const NOEXCEPT; size_t confirmed_body_size() const NOEXCEPT; size_t strong_tx_body_size() const NOEXCEPT; + size_t ecdsa_body_size() const NOEXCEPT; + size_t schnorr_body_size() const NOEXCEPT; size_t duplicate_body_size() const NOEXCEPT; size_t prevout_body_size() const NOEXCEPT; size_t validated_bk_body_size() const NOEXCEPT; @@ -160,6 +167,8 @@ class query size_t candidate_size() const NOEXCEPT; size_t confirmed_size() const NOEXCEPT; size_t strong_tx_size() const NOEXCEPT; + size_t ecdsa_size() const NOEXCEPT; + size_t schnorr_size() const NOEXCEPT; size_t duplicate_size() const NOEXCEPT; size_t prevout_size() const NOEXCEPT; size_t validated_bk_size() const NOEXCEPT; @@ -193,6 +202,8 @@ class query size_t candidate_records() const NOEXCEPT; size_t confirmed_records() const NOEXCEPT; size_t strong_tx_records() const NOEXCEPT; + size_t ecdsa_records() const NOEXCEPT; + size_t schnorr_records() const NOEXCEPT; size_t duplicate_records() const NOEXCEPT; size_t filter_bk_records() const NOEXCEPT; size_t address_records() const NOEXCEPT; @@ -559,6 +570,12 @@ class query bool set_tx_connected(const tx_link& link, const context& ctx, uint64_t fee, size_t sigops) NOEXCEPT; + /// Set signature (ecdsa/schnorr) table entry. + bool set_signature(const hash_digest& digest, const ec_compressed& point, + const ec_signature& signature, const header_link& link) NOEXCEPT; + bool set_signature(const hash_digest& digest, const ec_xonly& point, + const ec_signature& signature, const header_link& link) NOEXCEPT; + /// Confirmation. /// ----------------------------------------------------------------------- /// These are not used in consensus confirmation. @@ -941,6 +958,7 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) #include #include #include +#include #include BC_POP_WARNING() diff --git a/include/bitcoin/database/settings.hpp b/include/bitcoin/database/settings.hpp index 749c90368..5a7371db1 100644 --- a/include/bitcoin/database/settings.hpp +++ b/include/bitcoin/database/settings.hpp @@ -95,6 +95,12 @@ struct BCD_API settings /// Caches. /// ----------------------------------------------------------------------- + uint64_t ecdsa_size; + uint16_t ecdsa_rate; + + uint64_t schnorr_size; + uint16_t schnorr_rate; + // This one is 16 bit (could use table link::integer) for these. uint16_t duplicate_buckets; uint64_t duplicate_size; diff --git a/include/bitcoin/database/store.hpp b/include/bitcoin/database/store.hpp index 762ec95b9..c0c2ec2ff 100644 --- a/include/bitcoin/database/store.hpp +++ b/include/bitcoin/database/store.hpp @@ -103,35 +103,6 @@ class store /// Dump all error/full conditions to handler. void report(const error_handler& handler) const NOEXCEPT; - /// Tables. - /// ----------------------------------------------------------------------- - - /// Archives. - table::header header; - table::input input; - table::output output; - table::point point; - table::ins ins; - table::outs outs; - table::transaction tx; - table::txs txs; - - /// Indexes. - table::height candidate; - table::height confirmed; - table::strong_tx strong_tx; - - /// Caches. - table::duplicate duplicate; - table::prevout prevout; - table::validated_bk validated_bk; - table::validated_tx validated_tx; - - /// Optionals. - table::address address; - table::filter_bk filter_bk; - table::filter_tx filter_tx; - protected: using path = std::filesystem::path; @@ -196,11 +167,19 @@ class store /// Caches. /// ----------------------------------------------------------------------- - // bloc arraymap + // array + Storage ecdsa_head_; + Storage ecdsa_body_; + + // array + Storage schnorr_head_; + Storage schnorr_body_; + + // blob arraymap Storage duplicate_head_; Storage duplicate_body_; - // bloc arraymap + // blob arraymap Storage prevout_head_; Storage prevout_body_; @@ -253,6 +232,38 @@ class store { return folder / (name + schema::ext::lock); } + +public: + /// Tables. + /// ----------------------------------------------------------------------- + + /// Archives. + table::header header; + table::input input; + table::output output; + table::point point; + table::ins ins; + table::outs outs; + table::transaction tx; + table::txs txs; + + /// Indexes. + table::height candidate; + table::height confirmed; + table::strong_tx strong_tx; + + /// Caches. + table::ecdsa ecdsa; + table::schnorr schnorr; + table::duplicate duplicate; + table::prevout prevout; + table::validated_bk validated_bk; + table::validated_tx validated_tx; + + /// Optionals. + table::address address; + table::filter_bk filter_bk; + table::filter_tx filter_tx; }; } // namespace database diff --git a/include/bitcoin/database/tables/caches/ecdsa.hpp b/include/bitcoin/database/tables/caches/ecdsa.hpp new file mode 100644 index 000000000..734a55849 --- /dev/null +++ b/include/bitcoin/database/tables/caches/ecdsa.hpp @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#ifndef LIBBITCOIN_DATABASE_TABLES_CACHES_ECDSA_HPP +#define LIBBITCOIN_DATABASE_TABLES_CACHES_ECDSA_HPP + +#include +#include +#include + +namespace libbitcoin { +namespace database { +namespace table { + +/// ecdsa is an array of ecdsa signature validation records. +struct ecdsa + : public no_map +{ + using header = schema::header::link; + using no_map::nomap; + + struct record + : public schema::ecdsa + { + inline bool from_data(reader& source) NOEXCEPT + { + digest = source.read_hash(); + point = source.read_forward(); + signature = source.read_forward(); + header_fk = source.read_little_endian(); + BC_ASSERT(!source || source.get_read_position() == minrow); + return source; + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + sink.write_bytes(digest); + sink.write_bytes(point); + sink.write_bytes(signature); + sink.write_little_endian(header_fk); + BC_ASSERT(!sink || sink.get_write_position() == minrow); + return sink; + } + + inline bool operator==(const record& other) const NOEXCEPT + { + return digest == other.digest + && point == other.point + && signature == other.signature + && header_fk == other.header_fk; + } + + system::hash_digest digest{}; + system::ec_compressed point{}; + system::ec_signature signature{}; + header::integer header_fk{}; + }; +}; + +static_assert(offsetof(system::ecdsa::triple, digest) == 0); +static_assert(offsetof(system::ecdsa::triple, point) == 32); +static_assert(offsetof(system::ecdsa::triple, signature) == 65); +static_assert(offsetof(system::ecdsa::triple, identifier) == 129); +static_assert(sizeof(system::ecdsa::triple) == 32 + 33 + 64 + 3); + +} // namespace table +} // namespace database +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/database/tables/caches/schnorr.hpp b/include/bitcoin/database/tables/caches/schnorr.hpp new file mode 100644 index 000000000..02d8d0ebd --- /dev/null +++ b/include/bitcoin/database/tables/caches/schnorr.hpp @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#ifndef LIBBITCOIN_DATABASE_TABLES_CACHES_SCHNORR_HPP +#define LIBBITCOIN_DATABASE_TABLES_CACHES_SCHNORR_HPP + +#include +#include +#include + +namespace libbitcoin { +namespace database { +namespace table { + +/// schnorr is an array of schnorr signature validation records. +struct schnorr + : public no_map +{ + using header = schema::header::link; + using no_map::nomap; + + struct record + : public schema::schnorr + { + inline bool from_data(reader& source) NOEXCEPT + { + digest = source.read_hash(); + point = source.read_forward(); + signature = source.read_forward(); + header_fk = source.read_little_endian(); + BC_ASSERT(!source || source.get_read_position() == minrow); + return source; + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + sink.write_bytes(digest); + sink.write_bytes(point); + sink.write_bytes(signature); + sink.write_little_endian(header_fk); + BC_ASSERT(!sink || sink.get_write_position() == minrow); + return sink; + } + + inline bool operator==(const record& other) const NOEXCEPT + { + return digest == other.digest + && point == other.point + && signature == other.signature + && header_fk == other.header_fk; + } + + system::hash_digest digest{}; + system::ec_xonly point{}; + system::ec_signature signature{}; + header::integer header_fk{}; + }; +}; + +static_assert(offsetof(system::schnorr::triple, digest) == 0); +static_assert(offsetof(system::schnorr::triple, point) == 32); +static_assert(offsetof(system::schnorr::triple, signature) == 64); +static_assert(offsetof(system::schnorr::triple, identifier) == 128); +static_assert(sizeof(system::schnorr::triple) == 32 + 32 + 64 + 3); + +} // namespace table +} // namespace database +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/database/tables/names.hpp b/include/bitcoin/database/tables/names.hpp index b5a1c018b..6d22e8f57 100644 --- a/include/bitcoin/database/tables/names.hpp +++ b/include/bitcoin/database/tables/names.hpp @@ -57,6 +57,8 @@ namespace indexes namespace caches { + constexpr auto ecdsa = "ecdsa"; + constexpr auto schnorr = "schnorr"; constexpr auto duplicate = "duplicate"; constexpr auto prevout = "prevout"; constexpr auto validated_bk = "validated_bk"; diff --git a/include/bitcoin/database/tables/schema.hpp b/include/bitcoin/database/tables/schema.hpp index 9775871c9..707eae2b4 100644 --- a/include/bitcoin/database/tables/schema.hpp +++ b/include/bitcoin/database/tables/schema.hpp @@ -221,7 +221,7 @@ struct txs /// Index tables. /// --------------------------------------------------------------------------- -// candidate and confirmed arrays +// array (candidate and confirmed) struct height { static constexpr size_t pk = schema::header::pk; @@ -259,6 +259,44 @@ struct strong_tx /// Cache tables. /// --------------------------------------------------------------------------- +// array +struct ecdsa +{ + static constexpr size_t pk = schema::header::pk; + using link = schema::header::link; + static constexpr size_t minsize = + system::hash_size + + system::ec_compressed_size + + system::ec_signature_size + + schema::header::pk; + static constexpr size_t minrow = minsize; + static constexpr size_t size = minsize; + static constexpr link count() NOEXCEPT { return 1; } + static_assert(minsize == 132u); + static_assert(minrow == 132u); + static_assert(link::size == 3u); + static_assert(minrow - link::size == 129u); +}; + +// array +struct schnorr +{ + static constexpr size_t pk = schema::header::pk; + using link = schema::header::link; + static constexpr size_t minsize = + system::hash_size + + system::ec_xonly_size + + system::ec_signature_size + + schema::header::pk; + static constexpr size_t minrow = minsize; + static constexpr size_t size = minsize; + static constexpr link count() NOEXCEPT { return 1; } + static_assert(minsize == 131u); + static_assert(minrow == 131u); + static_assert(link::size == 3u); + static_assert(minrow - link::size == 128u); +}; + // record hashmap struct duplicate { diff --git a/include/bitcoin/database/tables/table.hpp b/include/bitcoin/database/tables/table.hpp index b35b37806..eed537ac2 100644 --- a/include/bitcoin/database/tables/table.hpp +++ b/include/bitcoin/database/tables/table.hpp @@ -69,6 +69,12 @@ enum class table_t strong_tx_body, /// Caches. + ecdsa_table, + ecdsa_head, + ecdsa_body, + schnorr_table, + schnorr_head, + schnorr_body, duplicate_table, duplicate_head, duplicate_body, diff --git a/include/bitcoin/database/tables/tables.hpp b/include/bitcoin/database/tables/tables.hpp index ab005a75f..2c7bd04ae 100644 --- a/include/bitcoin/database/tables/tables.hpp +++ b/include/bitcoin/database/tables/tables.hpp @@ -28,8 +28,10 @@ #include #include +#include #include #include +#include #include #include diff --git a/src/settings.cpp b/src/settings.cpp index b87279e1e..0d00ca64f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -71,6 +71,12 @@ settings::settings() NOEXCEPT // Caches. + ecdsa_size{ 1 }, + ecdsa_rate{ 50 }, + + schnorr_size{ 1 }, + schnorr_rate{ 50 }, + duplicate_buckets{ 128 }, duplicate_size{ 1 }, duplicate_rate{ 50 }, diff --git a/test/mocks/chunk_store.hpp b/test/mocks/chunk_store.hpp index 750e6b7b6..c68b97ec9 100644 --- a/test/mocks/chunk_store.hpp +++ b/test/mocks/chunk_store.hpp @@ -148,6 +148,26 @@ class chunk_store // Caches. + system::data_chunk& ecdsa_head() NOEXCEPT + { + return ecdsa_head_.buffer(); + } + + system::data_chunk& ecdsa_body() NOEXCEPT + { + return ecdsa_body_.buffer(); + } + + system::data_chunk& schnorr_head() NOEXCEPT + { + return schnorr_head_.buffer(); + } + + system::data_chunk& schnorr_body() NOEXCEPT + { + return schnorr_body_.buffer(); + } + system::data_chunk& duplicate_head() NOEXCEPT { return duplicate_head_.buffer(); @@ -225,4 +245,4 @@ using query_accessor = query>; } // namespace test -#endif +#endif \ No newline at end of file diff --git a/test/mocks/map_store.hpp b/test/mocks/map_store.hpp index 7701b50d3..099cb6cd9 100644 --- a/test/mocks/map_store.hpp +++ b/test/mocks/map_store.hpp @@ -169,6 +169,26 @@ class map_store // Caches. + inline const path& ecdsa_head_file() const NOEXCEPT + { + return ecdsa_head_.file(); + } + + inline const path& ecdsa_body_file() const NOEXCEPT + { + return ecdsa_body_.file(); + } + + inline const path& schnorr_head_file() const NOEXCEPT + { + return schnorr_head_.file(); + } + + inline const path& schnorr_body_file() const NOEXCEPT + { + return schnorr_body_.file(); + } + inline const path& duplicate_head_file() const NOEXCEPT { return duplicate_head_.file(); @@ -261,4 +281,4 @@ class map_store } // namespace test -#endif +#endif \ No newline at end of file diff --git a/test/query/extent.cpp b/test/query/extent.cpp index b2f81f1ea..5be68517c 100644 --- a/test/query/extent.cpp +++ b/test/query/extent.cpp @@ -51,6 +51,8 @@ BOOST_AUTO_TEST_CASE(query_extent__body_sizes__genesis__expected) BOOST_REQUIRE_EQUAL(query.candidate_body_size(), schema::height::minrow); BOOST_REQUIRE_EQUAL(query.confirmed_body_size(), schema::height::minrow); BOOST_REQUIRE_EQUAL(query.strong_tx_body_size(), schema::strong_tx::minrow); + BOOST_REQUIRE_EQUAL(query.ecdsa_body_size(), zero); + BOOST_REQUIRE_EQUAL(query.schnorr_body_size(), zero); BOOST_REQUIRE_EQUAL(query.duplicate_body_size(), zero); BOOST_REQUIRE_EQUAL(query.prevout_body_size(), zero); BOOST_REQUIRE_EQUAL(query.validated_bk_body_size(), zero); @@ -101,6 +103,8 @@ BOOST_AUTO_TEST_CASE(query_extent__records__genesis__expected) BOOST_REQUIRE_EQUAL(query.candidate_records(), one); BOOST_REQUIRE_EQUAL(query.confirmed_records(), one); BOOST_REQUIRE_EQUAL(query.strong_tx_records(), one); + BOOST_REQUIRE_EQUAL(query.ecdsa_records(), zero); + BOOST_REQUIRE_EQUAL(query.schnorr_records(), zero); BOOST_REQUIRE_EQUAL(query.duplicate_records(), zero); BOOST_REQUIRE_EQUAL(query.filter_bk_records(), one); BOOST_REQUIRE_EQUAL(query.address_records(), one); diff --git a/test/query/signatures.cpp b/test/query/signatures.cpp new file mode 100644 index 000000000..d4097cb66 --- /dev/null +++ b/test/query/signatures.cpp @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include "../test.hpp" +#include "../mocks/blocks.hpp" +#include "../mocks/chunk_store.hpp" + +BOOST_FIXTURE_TEST_SUITE(query_signatures_tests, test::directory_setup_fixture) + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/settings.cpp b/test/settings.cpp index 1d35a7dde..aa0cffc79 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -59,6 +59,10 @@ BOOST_AUTO_TEST_CASE(settings__construct__default__expected) BOOST_REQUIRE_EQUAL(configuration.strong_tx_rate, 50u); // Caches. + BOOST_REQUIRE_EQUAL(configuration.ecdsa_size, 1u); + BOOST_REQUIRE_EQUAL(configuration.ecdsa_rate, 50u); + BOOST_REQUIRE_EQUAL(configuration.schnorr_size, 1u); + BOOST_REQUIRE_EQUAL(configuration.schnorr_rate, 50u); BOOST_REQUIRE_EQUAL(configuration.duplicate_buckets, 128u); BOOST_REQUIRE_EQUAL(configuration.duplicate_size, 1u); BOOST_REQUIRE_EQUAL(configuration.duplicate_rate, 50u); diff --git a/test/tables/caches/ecdsa.cpp b/test/tables/caches/ecdsa.cpp new file mode 100644 index 000000000..6bfb4d417 --- /dev/null +++ b/test/tables/caches/ecdsa.cpp @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include "../../test.hpp" +#include "../../mocks/chunk_storage.hpp" + +BOOST_AUTO_TEST_SUITE(ecdsa_tests) + +using namespace system; + +const table::ecdsa::record record1 +{ + {}, + base16_hash("1111111111111111111111111111111111111111111111111111111111111111"), + base16_array("222222222222222222222222222222222222222222222222222222222222222222"), + base16_array("33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"), + 0x00345678_u32 +}; + +const table::ecdsa::record record2 +{ + {}, + base16_hash("4444444444444444444444444444444444444444444444444444444444444444"), + base16_array("555555555555555555555555555555555555555555555555555555555555555555"), + base16_array("66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"), + 0x00cdef12_u32 +}; + +const auto expected_head = base16_chunk("000000"); +const auto closed_head = base16_chunk("020000"); +const auto expected_body = base16_chunk +( + // record 1 + "1111111111111111111111111111111111111111111111111111111111111111" + "222222222222222222222222222222222222222222222222222222222222222222" + "33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" + "785634" + + // record 2 + "4444444444444444444444444444444444444444444444444444444444444444" + "555555555555555555555555555555555555555555555555555555555555555555" + "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666" + "12efcd" +); + +BOOST_AUTO_TEST_CASE(ecdsa__put__two__expected) +{ + test::chunk_storage head_store{}; + test::chunk_storage body_store{}; + table::ecdsa instance{ head_store, body_store }; + BOOST_REQUIRE(instance.create()); + + table::ecdsa::link link1{}; + BOOST_REQUIRE(instance.put_link(link1, record1)); + BOOST_REQUIRE_EQUAL(link1, 0u); + + table::ecdsa::link link2{}; + BOOST_REQUIRE(instance.put_link(link2, record2)); + BOOST_REQUIRE_EQUAL(link2, 1u); + + BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); + BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); + BOOST_REQUIRE(instance.close()); + BOOST_REQUIRE_EQUAL(head_store.buffer(), closed_head); +} + +BOOST_AUTO_TEST_CASE(ecdsa__get__two__expected) +{ + auto head = expected_head; + auto body = expected_body; + test::chunk_storage head_store{ head }; + test::chunk_storage body_store{ body }; + table::ecdsa instance{ head_store, body_store }; + BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); + BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); + + table::ecdsa::record out{}; + BOOST_REQUIRE(instance.get(0u, out)); + BOOST_REQUIRE(out == record1); + BOOST_REQUIRE(instance.get(1u, out)); + BOOST_REQUIRE(out == record2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tables/caches/schnorr.cpp b/test/tables/caches/schnorr.cpp new file mode 100644 index 000000000..76b309b8e --- /dev/null +++ b/test/tables/caches/schnorr.cpp @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include "../../test.hpp" +#include "../../mocks/chunk_storage.hpp" + +BOOST_AUTO_TEST_SUITE(schnorr_tests) + +using namespace system; + +const table::schnorr::record record1 +{ + {}, + base16_hash("1111111111111111111111111111111111111111111111111111111111111111"), + base16_array("2222222222222222222222222222222222222222222222222222222222222222"), + base16_array("33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"), + 0x00345678_u32 +}; + +const table::schnorr::record record2 +{ + {}, + base16_hash("4444444444444444444444444444444444444444444444444444444444444444"), + base16_array("5555555555555555555555555555555555555555555555555555555555555555"), + base16_array("66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"), + 0x00cdef12_u32 +}; + +const auto expected_head = base16_chunk("000000"); +const auto closed_head = base16_chunk("020000"); +const auto expected_body = base16_chunk +( + // record 1 + "1111111111111111111111111111111111111111111111111111111111111111" + "2222222222222222222222222222222222222222222222222222222222222222" + "33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" + "785634" + + // record 2 + "4444444444444444444444444444444444444444444444444444444444444444" + "5555555555555555555555555555555555555555555555555555555555555555" + "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666" + "12efcd" +); + +BOOST_AUTO_TEST_CASE(schnorr__put__two__expected) +{ + test::chunk_storage head_store{}; + test::chunk_storage body_store{}; + table::schnorr instance{ head_store, body_store }; + BOOST_REQUIRE(instance.create()); + + table::schnorr::link link1{}; + BOOST_REQUIRE(instance.put_link(link1, record1)); + BOOST_REQUIRE_EQUAL(link1, 0u); + + table::schnorr::link link2{}; + BOOST_REQUIRE(instance.put_link(link2, record2)); + BOOST_REQUIRE_EQUAL(link2, 1u); + + BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); + BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); + BOOST_REQUIRE(instance.close()); + BOOST_REQUIRE_EQUAL(head_store.buffer(), closed_head); +} + +BOOST_AUTO_TEST_CASE(schnorr__get__two__expected) +{ + auto head = expected_head; + auto body = expected_body; + test::chunk_storage head_store{ head }; + test::chunk_storage body_store{ body }; + table::schnorr instance{ head_store, body_store }; + BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); + BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); + + table::schnorr::record out{}; + BOOST_REQUIRE(instance.get(0u, out)); + BOOST_REQUIRE(out == record1); + BOOST_REQUIRE(instance.get(1u, out)); + BOOST_REQUIRE(out == record2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tables/caches/validated_bk.cpp b/test/tables/caches/validated_bk.cpp index 64e753815..c3fb1302e 100644 --- a/test/tables/caches/validated_bk.cpp +++ b/test/tables/caches/validated_bk.cpp @@ -24,7 +24,7 @@ BOOST_AUTO_TEST_SUITE(validated_bk_tests) using namespace system; const table::validated_bk::record record1{ {}, 0x42 }; const table::validated_bk::record record2{ {}, 0xab }; -const data_chunk expected_head = base16_chunk +const auto expected_head = base16_chunk ( "000000" "000000" @@ -36,7 +36,7 @@ const data_chunk expected_head = base16_chunk "ffffff" "ffffff" ); -const data_chunk closed_head = base16_chunk +const auto closed_head = base16_chunk ( "020000" "000000" @@ -48,7 +48,7 @@ const data_chunk closed_head = base16_chunk "ffffff" "ffffff" ); -const data_chunk expected_body = base16_chunk +const auto expected_body = base16_chunk ( "42" // code1 "ab" // code2 diff --git a/test/tables/caches/validated_tx.cpp b/test/tables/caches/validated_tx.cpp index df3abf7fc..184417f90 100644 --- a/test/tables/caches/validated_tx.cpp +++ b/test/tables/caches/validated_tx.cpp @@ -72,7 +72,7 @@ const table::validated_tx::slab out2 0x0000000000000042, // fee 0x00000055 // sigops }; -const data_chunk expected_head = base16_chunk +const auto expected_head = base16_chunk ( "0000000000" "ffffffffff" @@ -84,7 +84,7 @@ const data_chunk expected_head = base16_chunk "ffffffffff" "ffffffffff" ); -const data_chunk closed_head = base16_chunk +const auto closed_head = base16_chunk ( "3a00000000" "ffffffffff" @@ -96,7 +96,7 @@ const data_chunk closed_head = base16_chunk "ffffffffff" "ffffffffff" ); -const data_chunk expected_body = base16_chunk +const auto expected_body = base16_chunk ( "ffffffffff" // next->end "01020304" // key1 diff --git a/test/tables/indexes/height.cpp b/test/tables/indexes/height.cpp index ff83d69d4..7fdb5b588 100644 --- a/test/tables/indexes/height.cpp +++ b/test/tables/indexes/height.cpp @@ -26,15 +26,15 @@ const table::height::record in1{ {}, 0x12345678 }; const table::height::record in2{ {}, 0xabcdef12 }; const table::height::record out1{ {}, 0x00345678 }; const table::height::record out2{ {}, 0x00cdef12 }; -const data_chunk expected_head = base16_chunk +const auto expected_head = base16_chunk ( "000000" ); -const data_chunk closed_head = base16_chunk +const auto closed_head = base16_chunk ( "020000" ); -const data_chunk expected_body = base16_chunk +const auto expected_body = base16_chunk ( "785634" // header_fk1 "12efcd" // header_fk2 diff --git a/test/tables/indexes/strong_tx.cpp b/test/tables/indexes/strong_tx.cpp index 29ed8ce14..d13fa6950 100644 --- a/test/tables/indexes/strong_tx.cpp +++ b/test/tables/indexes/strong_tx.cpp @@ -27,7 +27,7 @@ const table::strong_tx::key key2{ 0xa1, 0xa2, 0xa3, 0xa4 }; const table::strong_tx::record strong1{ {}, table::strong_tx::merge(true, 0x0078f87f) }; const table::strong_tx::record strong2{ {}, table::strong_tx::merge(false, 0x0078f87f) }; -const data_chunk expected_head = base16_chunk +const auto expected_head = base16_chunk ( "00000000" "ffffffff" @@ -39,7 +39,7 @@ const data_chunk expected_head = base16_chunk "ffffffff" "ffffffff" ); -const data_chunk closed_head = base16_chunk +const auto closed_head = base16_chunk ( "02000000" "ffffffff" @@ -51,7 +51,7 @@ const data_chunk closed_head = base16_chunk "ffffffff" "ffffffff" ); -const data_chunk expected_body = base16_chunk +const auto expected_body = base16_chunk ( "ffffffff" // next->end "01020304" // key1 diff --git a/test/tables/optional/address.cpp b/test/tables/optional/address.cpp index a838b9608..5d331b3a5 100644 --- a/test/tables/optional/address.cpp +++ b/test/tables/optional/address.cpp @@ -28,7 +28,7 @@ const table::address::record in1{ {}, 0x1234567890abcdef }; const table::address::record in2{ {}, 0xabcdef1234567890 }; const table::address::record out1{ {}, 0x0000007890abcdef }; const table::address::record out2{ {}, 0x0000001234567890 }; -const data_chunk expected_head = base16_chunk +const auto expected_head = base16_chunk ( "00000000" "01000000" @@ -40,7 +40,7 @@ const data_chunk expected_head = base16_chunk "ffffffff" "ffffffff" ); -const data_chunk closed_head = base16_chunk +const auto closed_head = base16_chunk ( "02000000" "01000000" @@ -52,7 +52,7 @@ const data_chunk closed_head = base16_chunk "ffffffff" "ffffffff" ); -const data_chunk expected_body = base16_chunk +const auto expected_body = base16_chunk ( "ffffffff" // next->end "100000000000000000000000000000000000000000000000000000000000000a" // key1 diff --git a/test/tables/optional/filter_bk.cpp b/test/tables/optional/filter_bk.cpp index 7492c5887..01b2a4649 100644 --- a/test/tables/optional/filter_bk.cpp +++ b/test/tables/optional/filter_bk.cpp @@ -25,7 +25,7 @@ using namespace system; BOOST_AUTO_TEST_CASE(filter_bk__put__ordered__expected) { - const data_chunk expected_head = base16_chunk + const auto expected_head = base16_chunk ( "000000" "000000" @@ -37,7 +37,7 @@ BOOST_AUTO_TEST_CASE(filter_bk__put__ordered__expected) "ffffff" "ffffff" ); - const data_chunk closed_head = base16_chunk + const auto closed_head = base16_chunk ( "050000" "000000" @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(filter_bk__put__ordered__expected) "ffffff" "ffffff" ); - const data_chunk expected_body = base16_chunk + const auto expected_body = base16_chunk ( // hash, head "0000000000000000000000000000000000000000000000000000000000000000""0000000000000000000000000000000000000000000000000000000000000000" diff --git a/test/tables/optional/filter_tx.cpp b/test/tables/optional/filter_tx.cpp index 06a31dc1c..71d033d1a 100644 --- a/test/tables/optional/filter_tx.cpp +++ b/test/tables/optional/filter_tx.cpp @@ -25,7 +25,7 @@ using namespace system; BOOST_AUTO_TEST_CASE(filter_tx__put__ordered__expected) { - const data_chunk expected_head = base16_chunk + const auto expected_head = base16_chunk ( "0000000000" "0000000000" @@ -37,7 +37,7 @@ BOOST_AUTO_TEST_CASE(filter_tx__put__ordered__expected) "ffffffffff" "ffffffffff" ); - const data_chunk closed_head = base16_chunk + const auto closed_head = base16_chunk ( "a500000000" "0000000000" @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(filter_tx__put__ordered__expected) "ffffffffff" "ffffffffff" ); - const data_chunk expected_body = base16_chunk + const auto expected_body = base16_chunk ( "20""0000000000000000000000000000000000000000000000000000000000000000" "20""0100000000000000000000000000000000000000000000000000000000000000"