diff --git a/include/bitcoin/database/impl/query/batch/ecdsa.ipp b/include/bitcoin/database/impl/query/batch/ecdsa.ipp index be2f522fb..79bfad512 100644 --- a/include/bitcoin/database/impl/query/batch/ecdsa.ipp +++ b/include/bitcoin/database/impl/query/batch/ecdsa.ipp @@ -74,62 +74,25 @@ bool CLASS::purge_ecdsa_signatures() NOEXCEPT } TEMPLATE -bool CLASS::set_signature(const hash_digest& digest, - const ec_compressed& point, const ec_signature& signature, uint16_t id, +bool CLASS::set_signatures(const system::chain::ecdsa_signatures& sigs, const header_link& link) NOEXCEPT { - using correlate_t = table::ecdsa_correlate::put_ref; - using digest_t = table::ecdsa_digest::put_ref; - using compressed_t = table::ecdsa_compressed::put_ref; - using signature_t = table::ecdsa_signature::put_ref; + using correlate_t = table::ecdsa_correlate::put_signatures; + using digest_t = table::ecdsa_digest::put_signatures; + using compressed_t = table::ecdsa_compressed::put_signatures; + using signature_t = table::ecdsa_signature::put_signatures; - // Caller must guard reads, this is writing into hot storage. - // ======================================================================== - const auto scope = get_transactor(); - - using namespace system; - const auto row = possible_narrow_cast(one); - - // Allocate 1 row across all columns. - const auto fk = store_.ecdsa.allocate(row); - if (fk.is_terminal()) - return false; - - // Guard against remap (required for nomaps::put(fk)). - const auto guard = store_.ecdsa.guard(); - - // Write one value to each column in corresponding positions. - return - store_.ecdsa.correlate.put(fk, correlate_t{ {}, link, id }) && - store_.ecdsa.digest.put(fk, digest_t{ {}, digest }) && - store_.ecdsa.compressed.put(fk, compressed_t{ {}, point }) && - store_.ecdsa.signature.put(fk, signature_t{ {}, signature }); - // ======================================================================== -} - -TEMPLATE -bool CLASS::set_signatures(const hash_digest& digest, - const std::span& keys, - const std::span& sigs, uint16_t id, - const header_link& link) NOEXCEPT -{ - using correlate_t = table::ecdsa_correlate::put_refs; - using digest_t = table::ecdsa_digest::put_refs; - using compressed_t = table::ecdsa_compressed::put_refs; - using signature_t = table::ecdsa_signature::put_refs; + if (sigs.empty()) + return true; using namespace system; - const auto csigs = sigs.size(); - const auto ckeys = keys.size(); - const auto count = chain::multisig::rows(csigs, ckeys); + const auto rows = possible_narrow_cast(sigs.rows()); // Caller must guard reads, this is writing into hot storage. // ======================================================================== const auto scope = get_transactor(); - const auto rows = possible_narrow_cast(count); - - // Allocate rows across all columns. + // Allocate all of the block's rows across all columns. const auto fk = store_.ecdsa.allocate(rows); if (fk.is_terminal()) return false; @@ -137,12 +100,12 @@ bool CLASS::set_signatures(const hash_digest& digest, // Guard against remap (required for nomaps::put(fk)). const auto guard = store_.ecdsa.guard(); - // Write values to each column in corresponding positions. + // Deinterleave the accumulator into the columns, expanding group bands. return - 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 }); + store_.ecdsa.correlate.put(fk, correlate_t{ {}, link, sigs }) && + store_.ecdsa.digest.put(fk, digest_t{ {}, sigs }) && + store_.ecdsa.compressed.put(fk, compressed_t{ {}, sigs }) && + store_.ecdsa.signature.put(fk, signature_t{ {}, sigs }); // ======================================================================== } diff --git a/include/bitcoin/database/impl/query/batch/schnorr.ipp b/include/bitcoin/database/impl/query/batch/schnorr.ipp index d8189585a..2cd890dc6 100644 --- a/include/bitcoin/database/impl/query/batch/schnorr.ipp +++ b/include/bitcoin/database/impl/query/batch/schnorr.ipp @@ -73,74 +73,39 @@ bool CLASS::purge_schnorr_signatures() NOEXCEPT } TEMPLATE -bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point, - const ec_signature& signature, const header_link& link) NOEXCEPT +bool CLASS::set_signatures(const system::chain::schnorr_signatures& sigs, + const header_link& link) NOEXCEPT { - using correlate_t = 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; + using correlate_t = table::schnorr_correlate::put_signatures; + using digest_t = table::schnorr_digest::put_signatures; + using xonly_t = table::schnorr_xonly::put_signatures; + using signature_t = table::schnorr_signature::put_signatures; - // Caller must guard reads, this is writing into hot storage. - // ======================================================================== - const auto scope = get_transactor(); + if (sigs.empty()) + return true; using namespace system; - const auto row = possible_narrow_cast(one); - - // Allocate 1 row across all columns. - const auto fk = store_.schnorr.allocate(row); - if (fk.is_terminal()) - return false; - - // Guard against remap (required for nomaps::put(fk)). - const auto guard = store_.schnorr.guard(); - - // Write one value to each column in corresponding positions. - return - store_.schnorr.correlate.put(fk, correlate_t{ {}, link }) && - store_.schnorr.digest.put(fk, digest_t{ {}, digest }) && - store_.schnorr.xonly.put(fk, xonly_t{ {}, point }) && - store_.schnorr.signature.put(fk, signature_t{ {}, signature }); - // ======================================================================== -} - -TEMPLATE -schnorr_link CLASS::allocate_signatures(size_t count) NOEXCEPT -{ - // Allocate count rows across all columns (hot storage). - // ======================================================================== - const auto scope = get_transactor(); - - using namespace system; - const auto rows = possible_narrow_cast(count); - return store_.schnorr.allocate(rows); - // ======================================================================== -} - -TEMPLATE -bool CLASS::set_signature(const schnorr_link& schnorr_fk, - const hash_digest& digest, const ec_xonly& point, - const ec_signature& signature, const header_link& link) NOEXCEPT -{ - using namespace system; - using correlate_t = 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; + const auto rows = possible_narrow_cast( + sigs.rows().size()); // Caller must guard reads, this is writing into hot storage. // ======================================================================== const auto scope = get_transactor(); + // Allocate all of the block's rows across all columns. + const auto fk = store_.schnorr.allocate(rows); + if (fk.is_terminal()) + return false; + // Guard against remap (required for nomaps::put(fk)). const auto guard = store_.schnorr.guard(); + // Deinterleave the accumulator into the columns. return - store_.schnorr.correlate.put(schnorr_fk, correlate_t{ {}, link }) && - store_.schnorr.digest.put(schnorr_fk, digest_t{ {}, digest }) && - store_.schnorr.xonly.put(schnorr_fk, xonly_t{ {}, point }) && - store_.schnorr.signature.put(schnorr_fk, signature_t{ {}, signature }); + store_.schnorr.correlate.put(fk, correlate_t{ {}, link, sigs }) && + store_.schnorr.digest.put(fk, digest_t{ {}, sigs }) && + store_.schnorr.xonly.put(fk, xonly_t{ {}, sigs }) && + store_.schnorr.signature.put(fk, signature_t{ {}, sigs }); // ======================================================================== } diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index d6401ee8f..b1d505f59 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -592,25 +592,12 @@ class query bool set_silent(const tx_link& link, const transaction& tx) NOEXCEPT; bool set_silent(const header_link& link, const block& block) NOEXCEPT; - /// Set single ecdsa signature row. - bool set_signature(const hash_digest& digest, const ec_compressed& point, - const ec_signature& signature, uint16_t id, + /// Commit a block's captured ecdsa signature groups (band-expanded). + bool set_signatures(const system::chain::ecdsa_signatures& sigs, const header_link& link) NOEXCEPT; - /// Set ecdsa multisig rows. - bool set_signatures(const hash_digest& digest, - const std::span& keys, - const std::span& sigs, uint16_t id, - const header_link& link) NOEXCEPT; - - /// Set single schnorr signature row. - bool set_signature(const hash_digest& digest, const ec_xonly& point, - const ec_signature& signature, const header_link& link) NOEXCEPT; - - /// Set schnorr threshold signature rows. - schnorr_link allocate_signatures(size_t count) NOEXCEPT; - bool set_signature(const schnorr_link& first, const hash_digest& digest, - const ec_xonly& point, const ec_signature& signature, + /// Commit a block's captured schnorr signature rows. + bool set_signatures(const system::chain::schnorr_signatures& sigs, const header_link& link) NOEXCEPT; /// Invoke callback for each candidate match, false implies cancel. diff --git a/include/bitcoin/database/tables/caches/ecdsa.hpp b/include/bitcoin/database/tables/caches/ecdsa.hpp index a3ff12ea6..16aebe52a 100644 --- a/include/bitcoin/database/tables/caches/ecdsa.hpp +++ b/include/bitcoin/database/tables/caches/ecdsa.hpp @@ -73,6 +73,36 @@ struct ecdsa_digest const size_t rows{}; const hash_digest& digest; }; + + struct put_signatures + : public schema::ecdsa_digest + { + inline link count() const NOEXCEPT + { + return system::possible_narrow_cast(sigs.rows()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + using namespace system; + sigs.for_each([&](const hash_digest& digest, + std::span keys, + std::span sigs) NOEXCEPT + { + // Group capture is limited to common signature hash. + const auto rows = chain::multisig::rows(sigs.size(), + keys.size()); + + for (size_t row{}; row < rows; ++row) + sink.write_bytes(digest); + }); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const system::chain::ecdsa_signatures& sigs; + }; }; /// ecdsa_compressed is an array of ecdsa verification compressed public keys. @@ -127,6 +157,36 @@ struct ecdsa_compressed const std::span keys; const size_t sigs{}; }; + + struct put_signatures + : public schema::ecdsa_compressed + { + inline link count() const NOEXCEPT + { + return system::possible_narrow_cast(sigs.rows()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + using namespace system; + sigs.for_each([&](const hash_digest&, + std::span keys, + std::span sigs) NOEXCEPT + { + const auto m = sigs.size(); + const auto gap = keys.size() - m; + + for (size_t sig{}; sig < m; ++sig) + for (auto key = sig; key <= gap + sig; ++key) + sink.write_bytes(keys[key]); + }); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const system::chain::ecdsa_signatures& sigs; + }; }; /// ecdsa_signature is an array of ecdsa verification signatures. @@ -181,6 +241,36 @@ struct ecdsa_signature const size_t keys{}; const std::span sigs; }; + + struct put_signatures + : public schema::ecdsa_signature + { + inline link count() const NOEXCEPT + { + return system::possible_narrow_cast(sigs.rows()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + using namespace system; + sigs.for_each([&](const hash_digest&, + std::span keys, + std::span sigs) NOEXCEPT + { + const auto m = sigs.size(); + const auto gap = keys.size() - m; + + for (size_t sig{}; sig < m; ++sig) + for (auto key = sig; key <= gap + sig; ++key) + sink.write_bytes(sigs[sig]); + }); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const system::chain::ecdsa_signatures& sigs; + }; }; /// ecdsa_correlate is an array of ecdsa correlation records. @@ -271,6 +361,48 @@ struct ecdsa_correlate const size_t sigs{}; const uint16_t group{}; }; + + struct put_signatures + : public schema::ecdsa_correlate + { + inline link count() const NOEXCEPT + { + return system::possible_narrow_cast(sigs.rows()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + using namespace system; + uint16_t group{}; + sigs.for_each([&](const hash_digest&, + std::span keys, + std::span sigs) NOEXCEPT + { + const auto m = sigs.size(); + const auto gap = keys.size() - m; + + // Group id is the group capture ordinal (ecdsa_signatures). + for (size_t sig{}; sig < m; ++sig) + { + for (auto key = sig; key <= gap + sig; ++key) + { + sink.write_little_endian( + header_fk); + sink.write_byte(pack_word(sig, key)); + sink.write_little_endian(group); + } + } + + ++group; + }); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const hd::integer header_fk{}; + const system::chain::ecdsa_signatures& sigs; + }; }; /// Aggregate (files) diff --git a/include/bitcoin/database/tables/caches/schnorr.hpp b/include/bitcoin/database/tables/caches/schnorr.hpp index 1cd32925f..aab247c33 100644 --- a/include/bitcoin/database/tables/caches/schnorr.hpp +++ b/include/bitcoin/database/tables/caches/schnorr.hpp @@ -50,6 +50,27 @@ struct schnorr_digest const system::hash_digest& digest; }; + + struct put_signatures + : public schema::schnorr_digest + { + inline link count() const NOEXCEPT + { + return system::possible_narrow_cast( + sigs.rows().size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + for (const auto& row: sigs.rows()) + sink.write_bytes(row.digest); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const system::chain::schnorr_signatures& sigs; + }; }; /// schnorr_xonly is an array of schnorr verification xonly public keys. @@ -75,6 +96,27 @@ struct schnorr_xonly const system::ec_xonly& point; }; + + struct put_signatures + : public schema::schnorr_xonly + { + inline link count() const NOEXCEPT + { + return system::possible_narrow_cast( + sigs.rows().size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + for (const auto& row: sigs.rows()) + sink.write_bytes(row.point); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const system::chain::schnorr_signatures& sigs; + }; }; /// schnorr_signature is an array of schnorr verification signatures. @@ -100,6 +142,27 @@ struct schnorr_signature const system::ec_signature& signature; }; + + struct put_signatures + : public schema::schnorr_signature + { + inline link count() const NOEXCEPT + { + return system::possible_narrow_cast( + sigs.rows().size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + for (const auto& row: sigs.rows()) + sink.write_bytes(row.signature); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const system::chain::schnorr_signatures& sigs; + }; }; /// schnorr_correlate is an array of schnorr correlation records. @@ -144,6 +207,29 @@ struct schnorr_correlate const hd::integer header_fk{}; }; + + struct put_signatures + : public schema::schnorr_correlate + { + inline link count() const NOEXCEPT + { + return system::possible_narrow_cast( + sigs.rows().size()); + } + + inline bool to_data(flipper& sink) const NOEXCEPT + { + const auto rows = sigs.rows().size(); + for (size_t row{}; row < rows; ++row) + sink.write_little_endian(header_fk); + + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); + return sink; + } + + const hd::integer header_fk{}; + const system::chain::schnorr_signatures& sigs; + }; }; /// Aggregate (files) diff --git a/test/query/batch/ecdsa.cpp b/test/query/batch/ecdsa.cpp index 4e7df0df4..bd176d43a 100644 --- a/test/query/batch/ecdsa.cpp +++ b/test/query/batch/ecdsa.cpp @@ -42,6 +42,16 @@ const ec_signature ecdsa_signature = base16_array "01f4e1dbc36f32b4683faeecc8e4b2c6810da69e98fd783f1aad105636c3da08" ); +// Commit one single-sig (1 of 1) group as one block's accumulator. +static bool set_one(test::query_accessor& query, const hash_digest& digest, + const ec_compressed& key, const ec_signature& sig, + const header_link& link) NOEXCEPT +{ + chain::ecdsa_signatures sigs{}; + return sigs.append(digest, { &key, one }, { &sig, one }) && + query.set_signatures(sigs, link); +} + BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__empty__empty) { const database::settings configuration{}; @@ -59,7 +69,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_valid__empt const database::settings configuration{}; test::chunk_store store{ configuration }; test::query_accessor query{ store }; - BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 0, 42)); + BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42)); header_links links{}; BOOST_REQUIRE_EQUAL(query.ecdsa_records(), 1u); @@ -73,7 +83,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__one_invalid__ex test::chunk_store store{ configuration }; test::query_accessor query{ store }; constexpr auto expected = 42u; - BOOST_REQUIRE(query.set_signature(sighash_bad, ecdsa_compressed, ecdsa_signature, 0, expected)); + BOOST_REQUIRE(set_one(query, sighash_bad, ecdsa_compressed, ecdsa_signature, expected)); header_links links{}; BOOST_REQUIRE_EQUAL(query.ecdsa_records(), 1u); @@ -90,14 +100,14 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_ecdsa_signatures__various__expect constexpr auto expected1 = 42u; constexpr auto expected2 = 24u; - BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 0, 1)); - BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 0, 2)); - BOOST_REQUIRE(query.set_signature(sighash_bad, ecdsa_compressed, ecdsa_signature, 0, expected1)); - BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 0, 3)); - BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 0, 4)); - BOOST_REQUIRE(query.set_signature(sighash_bad, ecdsa_compressed, ecdsa_signature, 0, expected2)); - BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 0, 5)); - BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 0, 6)); + BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 1)); + BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 2)); + BOOST_REQUIRE(set_one(query, sighash_bad, ecdsa_compressed, ecdsa_signature, expected1)); + BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 3)); + BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 4)); + BOOST_REQUIRE(set_one(query, sighash_bad, ecdsa_compressed, ecdsa_signature, expected2)); + BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 5)); + BOOST_REQUIRE(set_one(query, ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 6)); header_links links{}; BOOST_REQUIRE_EQUAL(query.ecdsa_records(), 8u); diff --git a/test/query/batch/schnorr.cpp b/test/query/batch/schnorr.cpp index d18e711bc..16b78f2b8 100644 --- a/test/query/batch/schnorr.cpp +++ b/test/query/batch/schnorr.cpp @@ -42,6 +42,16 @@ const ec_signature schnorr_signature = base16_array "25f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0" ); +// Commit one row as one block's accumulator. +static bool set_one(test::query_accessor& query, const hash_digest& digest, + const ec_xonly& point, const ec_signature& sig, + const header_link& link) NOEXCEPT +{ + chain::schnorr_signatures sigs{}; + sigs.append(digest, point, sig); + return query.set_signatures(sigs, link); +} + BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__empty__empty) { const database::settings configuration{}; @@ -59,7 +69,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_valid__em const database::settings configuration{}; test::chunk_store store{ configuration }; test::query_accessor query{ store }; - BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 42)); + BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 42)); header_links links{}; BOOST_REQUIRE_EQUAL(query.schnorr_records(), 1u); @@ -73,7 +83,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_invalid__ test::chunk_store store{ configuration }; test::query_accessor query{ store }; constexpr auto expected = 42u; - BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, expected)); + BOOST_REQUIRE(set_one(query, sighash_bad, schnorr_xonly, schnorr_signature, expected)); header_links links{}; BOOST_REQUIRE_EQUAL(query.schnorr_records(), 1u); @@ -90,14 +100,14 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__various__expe constexpr auto expected1 = 42u; constexpr auto expected2 = 24u; - BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 1)); - BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 2)); - BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, expected1)); - BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 3)); - BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 4)); - BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, expected2)); - BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 5)); - BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 6)); + BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 1)); + BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 2)); + BOOST_REQUIRE(set_one(query, sighash_bad, schnorr_xonly, schnorr_signature, expected1)); + BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 3)); + BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 4)); + BOOST_REQUIRE(set_one(query, sighash_bad, schnorr_xonly, schnorr_signature, expected2)); + BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 5)); + BOOST_REQUIRE(set_one(query, schnorr_sighash, schnorr_xonly, schnorr_signature, 6)); header_links links{}; BOOST_REQUIRE_EQUAL(query.schnorr_records(), 8u);