diff --git a/include/bitcoin/database/impl/memory/mmap_private.ipp b/include/bitcoin/database/impl/memory/mmap_private.ipp index 4648a4d95..7d22c2bdf 100644 --- a/include/bitcoin/database/impl/memory/mmap_private.ipp +++ b/include/bitcoin/database/impl/memory/mmap_private.ipp @@ -253,7 +253,7 @@ bool CLASS::resize_(size_t size) NOEXCEPT const auto capacity = to_width(capacity_); // Disk full detection, any other failure is an abort. -#if !defined (WITHOUT_FALLOCATE) +#if !defined(WITHOUT_FALLOCATE) if (::fallocate(opened_[Column], 0, capacity, target - capacity) == fail) #else if (::ftruncate(opened_[Column], target) == fail) @@ -279,7 +279,7 @@ bool CLASS::resize_(size_t size) NOEXCEPT TEMPLATE template bool CLASS::finalize_(size_t - #if !defined (WITHOUT_MADVISE) && !defined(HAVE_MSC) + #if !defined(HAVE_MSC) && !defined(WITHOUT_MADVISE) size #endif ) NOEXCEPT @@ -294,7 +294,7 @@ bool CLASS::finalize_(size_t return false; } -#if !defined (WITHOUT_MADVISE) && !defined(HAVE_MSC) +#if !defined(HAVE_MSC) && !defined(WITHOUT_MADVISE) // Get page size (usually 4KB). const int page_size = ::sysconf(_SC_PAGESIZE); const auto page = system::possible_narrow_sign_cast(page_size); @@ -330,7 +330,7 @@ bool CLASS::finalize_(size_t return false; } } -#endif // !WITHOUT_MADVISE && !HAVE_MSC +#endif // !HAVE_MSC && !WITHOUT_MADVISE loaded_ = true; return true; diff --git a/include/bitcoin/database/impl/query/batch/ecdsa.ipp b/include/bitcoin/database/impl/query/batch/ecdsa.ipp index 622214b5a..d4d0f3087 100644 --- a/include/bitcoin/database/impl/query/batch/ecdsa.ipp +++ b/include/bitcoin/database/impl/query/batch/ecdsa.ipp @@ -135,10 +135,10 @@ bool CLASS::set_signatures(const hash_digest& digest, // Write values to each column in corresponding positions. return - store_.ecdsa.correlate.put(fk, correlate_t{ {}, link, ckeys, csigs, id }) && - store_.ecdsa.digest.put(fk, digest_t{ {}, ckeys, csigs, digest }) && - store_.ecdsa.compressed.put(fk, compressed_t{ {}, keys, csigs }) && - store_.ecdsa.signature.put(fk, signature_t{ {}, ckeys, sigs }); + store_.ecdsa.correlate.put(fk, correlate_t{ {}, count, link, ckeys, csigs, id }) && + store_.ecdsa.digest.put(fk, digest_t{ {}, count, digest }) && + store_.ecdsa.compressed.put(fk, compressed_t{ {}, count, keys, csigs }) && + store_.ecdsa.signature.put(fk, signature_t{ {}, count, ckeys, sigs }); // ======================================================================== } diff --git a/include/bitcoin/database/impl/store/store.ipp b/include/bitcoin/database/impl/store/store.ipp index 1440af26d..a0313b25c 100644 --- a/include/bitcoin/database/impl/store/store.ipp +++ b/include/bitcoin/database/impl/store/store.ipp @@ -34,19 +34,19 @@ 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), - input_head_(head(config.path / schema::dir::heads, schema::archive::input), 1, 0, random), + input_head_(head(config.path / schema::dir::heads, schema::archive::input), 1, 0, sequential), input_body_(body(config.path, schema::archive::input), config.input_size, config.input_rate, sequential), - output_head_(head(config.path / schema::dir::heads, schema::archive::output), 1, 0, random), + output_head_(head(config.path / schema::dir::heads, schema::archive::output), 1, 0, sequential), output_body_(body(config.path, schema::archive::output), config.output_size, config.output_rate, sequential), 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), - ins_head_(head(config.path / schema::dir::heads, schema::archive::ins), 1, 0, random), + ins_head_(head(config.path / schema::dir::heads, schema::archive::ins), 1, 0, sequential), ins_body_(body(config.path, schema::archive::ins), config.ins_size, config.ins_rate, sequential), - outs_head_(head(config.path / schema::dir::heads, schema::archive::outs), 1, 0, random), + outs_head_(head(config.path / schema::dir::heads, schema::archive::outs), 1, 0, sequential), outs_body_(body(config.path, schema::archive::outs), config.outs_size, config.outs_rate, sequential), tx_head_(head(config.path / schema::dir::heads, schema::archive::tx), 1, 0, random), @@ -58,10 +58,10 @@ CLASS::store(const settings& config) NOEXCEPT // Indexes. // ------------------------------------------------------------------------ - candidate_head_(head(config.path / schema::dir::heads, schema::indexes::candidate), 1, 0, random), + candidate_head_(head(config.path / schema::dir::heads, schema::indexes::candidate), 1, 0, sequential), candidate_body_(body(config.path, schema::indexes::candidate), config.candidate_size, config.candidate_rate, sequential), - confirmed_head_(head(config.path / schema::dir::heads, schema::indexes::confirmed), 1, 0, random), + confirmed_head_(head(config.path / schema::dir::heads, schema::indexes::confirmed), 1, 0, sequential), confirmed_body_(body(config.path, schema::indexes::confirmed), config.confirmed_size, config.confirmed_rate, sequential), strong_tx_head_(head(config.path / schema::dir::heads, schema::indexes::strong_tx), 1, 0, random), @@ -70,19 +70,21 @@ CLASS::store(const settings& config) NOEXCEPT // Caches. // ------------------------------------------------------------------------ - ecdsa_head_(head(config.path / schema::dir::heads, schema::caches::ecdsa), 1, 0, random), + // TODO: body not random, but keep in memory. + ecdsa_head_(head(config.path / schema::dir::heads, schema::caches::ecdsa), 1, 0, sequential), 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), + // TODO: body not random, but keep in memory. + schnorr_head_(head(config.path / schema::dir::heads, schema::caches::schnorr), 1, 0, sequential), schnorr_body_(body(config.path, schema::caches::schnorr), config.schnorr_size, config.schnorr_rate, sequential), - silent_head_(head(config.path / schema::dir::heads, schema::caches::silent), 1, 0, random), + silent_head_(head(config.path / schema::dir::heads, schema::caches::silent), 1, 0, sequential), silent_body_(body(config.path, schema::caches::silent), config.silent_size, config.silent_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), - prevalid_head_(head(config.path / schema::dir::heads, schema::caches::prevalid), 1, 0, random), + prevalid_head_(head(config.path / schema::dir::heads, schema::caches::prevalid), 1, 0, sequential), prevalid_body_(body(config.path, schema::caches::prevalid), config.prevalid_size, config.prevalid_rate, sequential), prevout_head_(head(config.path / schema::dir::heads, schema::caches::prevout), 1, 0, random), diff --git a/include/bitcoin/database/tables/caches/ecdsa.hpp b/include/bitcoin/database/tables/caches/ecdsa.hpp index 99a62e939..a3ff12ea6 100644 --- a/include/bitcoin/database/tables/caches/ecdsa.hpp +++ b/include/bitcoin/database/tables/caches/ecdsa.hpp @@ -57,23 +57,20 @@ struct ecdsa_digest { inline link count() const NOEXCEPT { - using namespace system; - return possible_narrow_cast( - chain::multisig::rows(sigs, keys)); + return system::possible_narrow_cast(rows); } inline bool to_data(flipper& sink) const NOEXCEPT { // ecdsa multisig capture is limited to common signature hash. - for (size_t row{}; row < count(); ++row) + for (size_t row{}; row < rows; ++row) sink.write_bytes(digest); BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); return sink; } - const size_t keys{}; - const size_t sigs{}; + const size_t rows{}; const hash_digest& digest; }; }; @@ -107,9 +104,7 @@ struct ecdsa_compressed { inline link count() const NOEXCEPT { - using namespace system; - return possible_narrow_cast( - chain::multisig::rows(sigs, keys.size())); + return system::possible_narrow_cast(rows); } inline bool to_data(flipper& sink) const NOEXCEPT @@ -117,8 +112,7 @@ struct ecdsa_compressed using namespace system::chain; const auto m = sigs; const auto n = keys.size(); - if (!multisig::check(m, n)) - return false; + BC_ASSERT(multisig::rows(m, n) == rows); const auto gap = (n - m); for (size_t sig{}; sig < m; ++sig) @@ -129,6 +123,7 @@ struct ecdsa_compressed return sink; } + const size_t rows{}; const std::span keys; const size_t sigs{}; }; @@ -163,9 +158,7 @@ struct ecdsa_signature { inline link count() const NOEXCEPT { - using namespace system; - return possible_narrow_cast( - chain::multisig::rows(sigs.size(), keys)); + return system::possible_narrow_cast(rows); } inline bool to_data(flipper& sink) const NOEXCEPT @@ -173,8 +166,7 @@ struct ecdsa_signature using namespace system::chain; const auto m = sigs.size(); const auto n = keys; - if (!multisig::check(m, n)) - return false; + BC_ASSERT(multisig::rows(m, n) == rows); const auto gap = (n - m); for (size_t sig{}; sig < m; ++sig) @@ -185,6 +177,7 @@ struct ecdsa_signature return sink; } + const size_t rows{}; const size_t keys{}; const std::span sigs; }; @@ -247,9 +240,7 @@ struct ecdsa_correlate { inline link count() const NOEXCEPT { - using namespace system; - return possible_narrow_cast( - chain::multisig::rows(sigs, keys)); + return system::possible_narrow_cast(rows); } inline bool to_data(flipper& sink) const NOEXCEPT @@ -257,8 +248,7 @@ struct ecdsa_correlate using namespace system::chain; const auto m = sigs; const auto n = keys; - if (!multisig::check(m, n)) - return false; + BC_ASSERT(multisig::rows(m, n) == rows); const auto gap = (n - m); for (size_t sig{}; sig < m; ++sig) @@ -275,6 +265,7 @@ struct ecdsa_correlate return sink; } + const size_t rows{}; const hd::integer header_fk{}; const size_t keys{}; const size_t sigs{}; diff --git a/test/tables/caches/ecdsa.cpp b/test/tables/caches/ecdsa.cpp index 1e279018f..cae23a617 100644 --- a/test/tables/caches/ecdsa.cpp +++ b/test/tables/caches/ecdsa.cpp @@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(ecdsa_correlate__put_refs__one_of_three__expected) ); // put_refs{ {}, header_fk, keys, sigs, group }. - BOOST_REQUIRE(instance.put(putter{ {}, header_fk, 3_size, 1_size, group })); + BOOST_REQUIRE(instance.put(putter{ {}, 3_size, header_fk, 3_size, 1_size, group })); BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); } @@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE(ecdsa_digest__put_refs__repeated__expected) ); // put_refs{ {}, keys, sigs, digest }. - BOOST_REQUIRE(instance.put(putter{ {}, 3_size, 1_size, digest_a })); + BOOST_REQUIRE(instance.put(putter{ {}, 3_size, digest_a })); BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); } @@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(ecdsa_compressed__put_refs__matrix__expected) ); // put_refs{ {}, keys, sigs }. - BOOST_REQUIRE(instance.put(putter{ {}, keys, 1_size })); + BOOST_REQUIRE(instance.put(putter{ {}, 3_size, keys, 1_size })); BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); } @@ -322,7 +322,7 @@ BOOST_AUTO_TEST_CASE(ecdsa_signature__put_refs__repeated__expected) ); // put_refs{ {}, keys, sigs }. - BOOST_REQUIRE(instance.put(putter{ {}, 3_size, signatures })); + BOOST_REQUIRE(instance.put(putter{ {}, 3_size, 3_size, signatures })); BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); } diff --git a/test/tables/caches/schnorr.cpp b/test/tables/caches/schnorr.cpp index 7bf39ab8b..f16062315 100644 --- a/test/tables/caches/schnorr.cpp +++ b/test/tables/caches/schnorr.cpp @@ -1,326 +1,136 @@ -/////** -//// * 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; -////using namespace test; -//// -////// Shared test vectors. -////constexpr auto header_fk = 0x00abcdef_u32; -////constexpr ec_xonly xonly_a = base16_array -////( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -////); -////constexpr ec_xonly xonly_b = base16_array -////( -//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -////); -////constexpr hash_digest digest_a = base16_hash -////( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -////); -////constexpr hash_digest digest_b = base16_hash -////( -//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -////); -////constexpr ec_signature sig_a = base16_array -////( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -////); -////constexpr ec_signature sig_b = base16_array -////( -//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -////); -//// -////// schnorr (aggregate) -////// ---------------------------------------------------------------------------- -//// -////using schnorr_table = table::schnorr; -////using schnorr_storage = default_storage>; -//// -////BOOST_AUTO_TEST_CASE(schnorr__create_verify_close__aggregate__expected) -////{ -//// schnorr_storage head{ "head" }; -//// schnorr_storage body{ "body" }; -//// schnorr_table instance{ head, body }; -//// -//// BOOST_REQUIRE(instance.create()); -//// BOOST_REQUIRE(instance.verify()); -//// BOOST_REQUIRE(instance.close()); -////} -//// -////// Round-trip a single signature through the aggregate, mirroring the -////// set_signature write sequence: allocate one terminal correlate row, expand -////// subordinates, then commit real values. Correlate is header_fk only. -////BOOST_AUTO_TEST_CASE(schnorr__set_signature__single__expected) -////{ -//// using correlate = table::schnorr_correlate::put_ref; -//// using digest_t = table::schnorr_digest::put_ref; -//// using xonly_t = table::schnorr_xonly::put_ref; -//// using signature_t = table::schnorr_signature::put_ref; -//// -//// schnorr_storage head{ "head" }; -//// schnorr_storage body{ "body" }; -//// schnorr_table instance{ head, body }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const auto fk = instance.allocate(one); -//// BOOST_REQUIRE_EQUAL(fk, 0u); -//// -//// BOOST_REQUIRE(instance.digest.put(fk, digest_t{ {}, digest_a })); -//// BOOST_REQUIRE(instance.xonly.put(fk, xonly_t{ {}, xonly_a })); -//// BOOST_REQUIRE(instance.signature.put(fk, signature_t{ {}, sig_a })); -//// BOOST_REQUIRE(instance.correlate.put(fk, correlate{ {}, header_fk })); -//// -//// // Correlate: header_fk(3). -//// const auto expected_correlate = base16_chunk("efcdab"); -//// const auto expected_digest = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// ); -//// const auto expected_xonly = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// ); -//// const auto expected_signature = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// ); -//// -//// BOOST_REQUIRE_EQUAL(body.buffers_.at(0), expected_correlate); -//// BOOST_REQUIRE_EQUAL(body.buffers_.at(1), expected_digest); -//// BOOST_REQUIRE_EQUAL(body.buffers_.at(2), expected_xonly); -//// BOOST_REQUIRE_EQUAL(body.buffers_.at(3), expected_signature); -//// BOOST_REQUIRE(instance.close()); -////} -//// -////// schnorr_correlate (single writer + reader) -////// ---------------------------------------------------------------------------- -//// -////BOOST_AUTO_TEST_CASE(schnorr_correlate__put_ref__single__expected) -////{ -//// using putter = table::schnorr_correlate::put_ref; -//// -//// chunk_storage head_store{}; -//// chunk_storage body_store{}; -//// table::schnorr_correlate instance{ head_store, body_store }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const auto expected = base16_chunk("efcdab"); -//// BOOST_REQUIRE(instance.put(putter{ {}, header_fk })); -//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -////} -//// -////// schnorr_correlate (multiple writer: threshold) + reader -////// ---------------------------------------------------------------------------- -//// -////BOOST_AUTO_TEST_CASE(schnorr_correlate__put_refs__between__expected) -////{ -//// using putter = table::schnorr_correlate::put_refs; -//// -//// chunk_storage head_store{}; -//// chunk_storage body_store{}; -//// table::schnorr_correlate instance{ head_store, body_store }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const auto expected = base16_chunk -//// ( -//// "efcdab" -//// "efcdab" -//// "efcdab" -//// ); -//// -//// // put_refs{ {}, size, header_fk }. -//// BOOST_REQUIRE(instance.put(putter{ {}, 3, header_fk })); -//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -////} -//// -////BOOST_AUTO_TEST_CASE(schnorr_correlate__get__using_record__expected) -////{ -//// auto head = base16_chunk("02000000"); -//// auto body = base16_chunk -//// ( -//// "efcdab" -//// "785634" -//// ); -//// -//// chunk_storage head_store{ head }; -//// chunk_storage body_store{ body }; -//// table::schnorr_correlate instance{ head_store, body_store }; -//// -//// table::schnorr_correlate::record out{}; -//// BOOST_REQUIRE(instance.get(0u, out)); -//// BOOST_REQUIRE(out.header_fk == header_fk); -//// -//// BOOST_REQUIRE(instance.get(1u, out)); -//// BOOST_REQUIRE(out.header_fk == 0x00345678_u32); -////} -//// -////// schnorr_digest (single + multiple writers) -////// ---------------------------------------------------------------------------- -//// -////BOOST_AUTO_TEST_CASE(schnorr_digest__put_ref__single__expected) -////{ -//// using putter = table::schnorr_digest::put_ref; -//// -//// chunk_storage head_store{}; -//// chunk_storage body_store{}; -//// table::schnorr_digest instance{ head_store, body_store }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const auto expected = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// ); -//// -//// BOOST_REQUIRE(instance.put(putter{ {}, digest_a })); -//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -////} -//// -////BOOST_AUTO_TEST_CASE(schnorr_digest__put_refs__tuples__expected) -////{ -//// using putter = table::schnorr_digest::put_refs; -//// -//// chunk_storage head_store{}; -//// chunk_storage body_store{}; -//// table::schnorr_digest instance{ head_store, body_store }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const ec_xonly point{}; -//// const ec_signature sig{}; -//// const chain::threshold::tuples_t tuples -//// { -//// { digest_a, point, sig }, -//// { digest_b, point, sig } -//// }; -//// -//// const auto expected = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -//// ); -//// -//// BOOST_REQUIRE(instance.put(putter{ {}, tuples })); -//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -////} -//// -////// schnorr_xonly (single + multiple writers) -////// ---------------------------------------------------------------------------- -//// -////BOOST_AUTO_TEST_CASE(schnorr_xonly__put_ref__single__expected) -////{ -//// using putter = table::schnorr_xonly::put_ref; -//// -//// chunk_storage head_store{}; -//// chunk_storage body_store{}; -//// table::schnorr_xonly instance{ head_store, body_store }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const auto expected = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// ); -//// -//// BOOST_REQUIRE(instance.put(putter{ {}, xonly_a })); -//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -////} -//// -////BOOST_AUTO_TEST_CASE(schnorr_xonly__put_refs__tuples__expected) -////{ -//// using putter = table::schnorr_xonly::put_refs; -//// -//// chunk_storage head_store{}; -//// chunk_storage body_store{}; -//// table::schnorr_xonly instance{ head_store, body_store }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const ec_signature sig{}; -//// const chain::threshold::tuples_t tuples -//// { -//// { null_hash, xonly_a, sig }, -//// { null_hash, xonly_b, sig } -//// }; -//// -//// const auto expected = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -//// ); -//// -//// BOOST_REQUIRE(instance.put(putter{ {}, tuples })); -//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -////} -//// -////// schnorr_signature (single + multiple writers) -////// ---------------------------------------------------------------------------- -//// -////BOOST_AUTO_TEST_CASE(schnorr_signature__put_ref__single__expected) -////{ -//// using putter = table::schnorr_signature::put_ref; -//// -//// chunk_storage head_store{}; -//// chunk_storage body_store{}; -//// table::schnorr_signature instance{ head_store, body_store }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const auto expected = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// ); -//// -//// BOOST_REQUIRE(instance.put(putter{ {}, sig_a })); -//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -////} -//// -////BOOST_AUTO_TEST_CASE(schnorr_signature__put_refs__tuples__expected) -////{ -//// using putter = table::schnorr_signature::put_refs; -//// -//// chunk_storage head_store{}; -//// chunk_storage body_store{}; -//// table::schnorr_signature instance{ head_store, body_store }; -//// BOOST_REQUIRE(instance.create()); -//// -//// const ec_xonly point{}; -//// const chain::threshold::tuples_t tuples -//// { -//// { null_hash, point, sig_a }, -//// { null_hash, point, sig_b } -//// }; -//// -//// const auto expected = base16_chunk -//// ( -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -//// ); -//// -//// BOOST_REQUIRE(instance.put(putter{ {}, tuples })); -//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -////} -//// -////BOOST_AUTO_TEST_SUITE_END() +/** + * 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; +using namespace test; + +// Shared test vectors. +constexpr auto header_fk = 0x00abcdef_u32; +constexpr auto header_fk2 = 0x00345678_u32; +constexpr ec_xonly xonly_a = base16_array +( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +); +constexpr ec_xonly xonly_b = base16_array +( + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +); +constexpr hash_digest digest_a = base16_hash +( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +); +constexpr hash_digest digest_b = base16_hash +( + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +); +constexpr ec_signature sig_a = base16_array +( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +); +constexpr ec_signature sig_b = base16_array +( + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +); + +// schnorr (aggregate) +// ---------------------------------------------------------------------------- + +using schnorr_table = table::schnorr; +using schnorr_storage = default_storage>; + +BOOST_AUTO_TEST_CASE(schnorr__create_verify_close__aggregate__expected) +{ + schnorr_storage head{ "head" }; + schnorr_storage body{ "body" }; + schnorr_table instance{ head, body }; + + BOOST_REQUIRE(instance.create()); + BOOST_REQUIRE(instance.verify()); + BOOST_REQUIRE(instance.close()); +} + +// Round-trip signatures through the aggregate, mirroring the keyed +// set_signature sequence: allocate rows, then commit values per row. +// Correlate is header_fk only. Two rows pin column alignment (position i +// in every column belongs to row i), on which batch evaluation depends. +BOOST_AUTO_TEST_CASE(schnorr__set_signature__allocated_rows__expected) +{ + using correlate = table::schnorr_correlate::put_ref; + using digest_t = table::schnorr_digest::put_ref; + using xonly_t = table::schnorr_xonly::put_ref; + using signature_t = table::schnorr_signature::put_ref; + + schnorr_storage head{ "head" }; + schnorr_storage body{ "body" }; + schnorr_table instance{ head, body }; + BOOST_REQUIRE(instance.create()); + + // Allocate two rows (cursor model), write each independently. + auto fk = instance.allocate(two); + BOOST_REQUIRE_EQUAL(fk, 0u); + + BOOST_REQUIRE(instance.digest.put(fk, digest_t{ {}, digest_a })); + BOOST_REQUIRE(instance.xonly.put(fk, xonly_t{ {}, xonly_a })); + BOOST_REQUIRE(instance.signature.put(fk, signature_t{ {}, sig_a })); + BOOST_REQUIRE(instance.correlate.put(fk, correlate{ {}, header_fk })); + + ++fk; + BOOST_REQUIRE(instance.digest.put(fk, digest_t{ {}, digest_b })); + BOOST_REQUIRE(instance.xonly.put(fk, xonly_t{ {}, xonly_b })); + BOOST_REQUIRE(instance.signature.put(fk, signature_t{ {}, sig_b })); + BOOST_REQUIRE(instance.correlate.put(fk, correlate{ {}, header_fk2 })); + + // Correlate: header_fk(3) per row. + const auto expected_correlate = base16_chunk + ( + "efcdab" + "785634" + ); + const auto expected_digest = base16_chunk + ( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ); + const auto expected_xonly = base16_chunk + ( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ); + const auto expected_signature = base16_chunk + ( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ); + + BOOST_REQUIRE_EQUAL(body.buffers_.at(0), expected_correlate); + BOOST_REQUIRE_EQUAL(body.buffers_.at(1), expected_digest); + BOOST_REQUIRE_EQUAL(body.buffers_.at(2), expected_xonly); + BOOST_REQUIRE_EQUAL(body.buffers_.at(3), expected_signature); + BOOST_REQUIRE(instance.close()); +} + +BOOST_AUTO_TEST_SUITE_END()