Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 69 additions & 26 deletions include/bitcoin/database/impl/query/signatures.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -26,46 +26,87 @@ namespace libbitcoin {
namespace database {

TEMPLATE
bool CLASS::set_signature(const hash_digest& , const ec_compressed& ,
const ec_signature& , const header_link& ) NOEXCEPT
bool CLASS::verify_ecdsa_signatures(header_links& links) NOEXCEPT
{
using batch = system::ecdsa::batch;
const auto count = store_.ecdsa.count().value;
const auto ptr = store_.ecdsa.get_memory();
const auto rows = system::pointer_cast<const batch>(ptr->data());
links = batch::verify({ rows, count }, store_.turbo());
return true;
}

TEMPLATE
bool CLASS::verify_schnorr_signatures(header_links& links) NOEXCEPT
{
using batch = system::schnorr::batch;
const auto count = store_.schnorr.count().value;
const auto ptr = store_.schnorr.get_memory();
const auto rows = system::pointer_cast<const batch>(ptr->data());
links = batch::verify({ rows, count }, store_.turbo());
return true;
}

// setters
// ----------------------------------------------------------------------------

TEMPLATE
bool CLASS::purge_ecdsa_signatures() NOEXCEPT
{
// ========================================================================
const auto scope = store_.get_transactor();
return store_.ecdsa.truncate(0);
// ========================================================================
}

////// Clean single allocation failure (e.g. disk full).
////return store_.ecdsa.put(table::ecdsa::record
////{
//// {},
//// digest,
//// point,
//// signature,
//// link
////});
TEMPLATE
bool CLASS::purge_schnorr_signatures() NOEXCEPT
{
// ========================================================================
const auto scope = store_.get_transactor();
return store_.schnorr.truncate(0);
// ========================================================================
}

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
});
// ========================================================================

// false will result in local signature validation (performance).
return true;
}

TEMPLATE
bool CLASS::set_signature(const hash_digest& , const ec_xonly& ,
const ec_signature& , const header_link& ) NOEXCEPT
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
////});
// Clean single allocation failure (e.g. disk full).
return store_.schnorr.put(table::schnorr::record
{
{},
digest,
point,
signature,
link
});
// ========================================================================

// false will result in local signature validation (performance).
return true;
}

Expand All @@ -76,6 +117,8 @@ bool CLASS::set_signatures(const hash_digest&, const ec_compresseds&,
// ========================================================================
const auto scope = store_.get_transactor();

// TODO: flatten via store_.ecdsa.put();

////// Clean single allocation failure (e.g. disk full).
////return store_.multisig.put(table::multisig::put_ref
////{
Expand All @@ -88,7 +131,6 @@ bool CLASS::set_signatures(const hash_digest&, const ec_compresseds&,
////});
// ========================================================================

// false will result in local signature validation (performance).
return true;
}

Expand All @@ -99,6 +141,8 @@ bool CLASS::set_signatures(const threshold& , size_t ,
// ========================================================================
const auto scope = store_.get_transactor();

// TODO: flatten via store_.schnorr.put();

////// Clean single allocation failure (e.g. disk full).
////return store_.multisig.put(table::multisig::put_ref
////{
Expand All @@ -111,7 +155,6 @@ bool CLASS::set_signatures(const threshold& , size_t ,
////});
// ========================================================================

// false will result in script validation failure (consensus).
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/database/impl/store/store_prune.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ code CLASS::prune(const event_handler& handler) NOEXCEPT
{
// zeroize table body, set logical body count to zero.
handler(event_t::prune_table, table_t::prevout_body);
if (!prevout_body_.truncate(zero))
if (!prevout_body_.truncate(0))
{
ec = error::prune_table;
}
Expand Down
12 changes: 5 additions & 7 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,13 +582,11 @@ class query
bool set_signatures(const threshold& group, size_t set,
const header_link& link) NOEXCEPT;

// TODO:
bool purge_signatures() NOEXCEPT { return {}; };
bool purge_ecdsa_signatures() NOEXCEPT { return {}; };
bool purge_schnorr_signatures() NOEXCEPT { return {}; };
////bool verify_signatures(header_links& ) NOEXCEPT { return {}; };
bool verify_ecdsa_signatures(header_links&) NOEXCEPT { return {}; };
bool verify_schnorr_signatures(header_links&) NOEXCEPT { return {}; };
/// Signature verification.
bool purge_ecdsa_signatures() NOEXCEPT;
bool purge_schnorr_signatures() NOEXCEPT;
bool verify_ecdsa_signatures(header_links&) NOEXCEPT;
bool verify_schnorr_signatures(header_links&) NOEXCEPT;

/// Confirmation.
/// -----------------------------------------------------------------------
Expand Down
154 changes: 154 additions & 0 deletions test/query/signatures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,158 @@

BOOST_FIXTURE_TEST_SUITE(query_signatures_tests, test::directory_setup_fixture)

using namespace system;

const hash_digest sighash_bad = base16_array(
"4242424242424242424242424242424242424242424242424242424242424242");

// ecdsa

const hash_digest ecdsa_sighash = base16_array(
"504d68beac187dd0b259ddd6ed6d5d6348150b9b23ee6dfdb43e87f74dd3c547");
const ec_compressed ecdsa_compressed = base16_array(
"039cfcfe4a5d0efad27382e5d2b478eb398a8b691a66e01c878b600b5042b33166");
const ec_signature ecdsa_signature = base16_array(
"b434c7c720d63d71e1136d740df7ff636770ce59cb0389ae8cd24c0d4441f143"
"01f4e1dbc36f32b4683faeecc8e4b2c6810da69e98fd783f1aad105636c3da08");

BOOST_AUTO_TEST_CASE(query__verify_ecdsa_signatures__empty__empty)
{
const database::settings configuration{};
test::chunk_store store{ configuration };
test::query_accessor query{ store };

header_links links{};
BOOST_REQUIRE_EQUAL(query.ecdsa_records(), 0u);
BOOST_REQUIRE(query.verify_ecdsa_signatures(links));
BOOST_REQUIRE(links.empty());
}

BOOST_AUTO_TEST_CASE(query__verify_ecdsa_signatures__one_valid__empty)
{
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, 42));

header_links links{};
BOOST_REQUIRE_EQUAL(query.ecdsa_records(), 1u);
BOOST_REQUIRE(query.verify_ecdsa_signatures(links));
BOOST_REQUIRE(links.empty());
}

BOOST_AUTO_TEST_CASE(query__verify_ecdsa_signatures__one_invalid__expected_link)
{
const database::settings configuration{};
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, expected));

header_links links{};
BOOST_REQUIRE_EQUAL(query.ecdsa_records(), 1u);
BOOST_REQUIRE(query.verify_ecdsa_signatures(links));
BOOST_REQUIRE_EQUAL(links.size(), 1u);
BOOST_REQUIRE_EQUAL(links.front(), expected);
}

BOOST_AUTO_TEST_CASE(query__verify_ecdsa_signatures__various__expected_links)
{
const database::settings configuration{};
test::chunk_store store{ configuration };
test::query_accessor query{ store };
constexpr auto expected1 = 42u;
constexpr auto expected2 = 24u;
BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42));
BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42));
BOOST_REQUIRE(query.set_signature(sighash_bad, ecdsa_compressed, ecdsa_signature, expected1));
BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42));
BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42));
BOOST_REQUIRE(query.set_signature(sighash_bad, ecdsa_compressed, ecdsa_signature, expected2));
BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42));
BOOST_REQUIRE(query.set_signature(ecdsa_sighash, ecdsa_compressed, ecdsa_signature, 42));

header_links links{};
BOOST_REQUIRE_EQUAL(query.ecdsa_records(), 8u);
BOOST_REQUIRE(query.verify_ecdsa_signatures(links));
BOOST_REQUIRE_EQUAL(links.size(), 2u);
BOOST_REQUIRE_EQUAL(links.front(), expected1);
BOOST_REQUIRE_EQUAL(links.back(), expected2);
}

// schnorr

// schnorr (valid BIP-340 test vector #0)
const hash_digest schnorr_sighash = base16_array(
"0000000000000000000000000000000000000000000000000000000000000000");
const ec_xonly schnorr_xonly = base16_array(
"f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9");
const ec_signature schnorr_signature = base16_array(
"e907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca8215"
"25f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0");

BOOST_AUTO_TEST_CASE(query__verify_schnorr_signatures__empty__empty)
{
const database::settings configuration{};
test::chunk_store store{ configuration };
test::query_accessor query{ store };

header_links links{};
BOOST_REQUIRE_EQUAL(query.schnorr_records(), 0u);
BOOST_REQUIRE(query.verify_schnorr_signatures(links));
BOOST_REQUIRE(links.empty());
}

BOOST_AUTO_TEST_CASE(query__verify_schnorr_signatures__one_valid__empty)
{
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));

header_links links{};
BOOST_REQUIRE_EQUAL(query.schnorr_records(), 1u);
BOOST_REQUIRE(query.verify_schnorr_signatures(links));
BOOST_REQUIRE(links.empty());
}

BOOST_AUTO_TEST_CASE(query__verify_schnorr_signatures__one_invalid__expected_link)
{
const database::settings configuration{};
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));

header_links links{};
BOOST_REQUIRE_EQUAL(query.schnorr_records(), 1u);
BOOST_REQUIRE(query.verify_schnorr_signatures(links));
BOOST_REQUIRE_EQUAL(links.size(), 1u);
BOOST_REQUIRE_EQUAL(links.front(), expected);
}

BOOST_AUTO_TEST_CASE(query__verify_schnorr_signatures__various__expected_links)
{
const database::settings configuration{};
test::chunk_store store{ configuration };
test::query_accessor query{ store };
constexpr auto expected1 = 42u;
constexpr auto expected2 = 24u;
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 42));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 42));
BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, expected1));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 42));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 42));
BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, expected2));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 42));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 42));

header_links links{};
BOOST_REQUIRE_EQUAL(query.schnorr_records(), 8u);
BOOST_REQUIRE(query.verify_schnorr_signatures(links));
BOOST_REQUIRE_EQUAL(links.size(), 2u);
BOOST_REQUIRE_EQUAL(links.front(), expected1);
BOOST_REQUIRE_EQUAL(links.back(), expected2);
}

BOOST_AUTO_TEST_SUITE_END()
24 changes: 24 additions & 0 deletions test/tables/caches/ecdsa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,28 @@ BOOST_AUTO_TEST_CASE(ecdsa__get__two__expected)
BOOST_REQUIRE(out == record2);
}

BOOST_AUTO_TEST_CASE(ecdsa__truncate__from_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);

BOOST_REQUIRE_EQUAL(instance.count(), 2u);
BOOST_REQUIRE(instance.truncate(1));
BOOST_REQUIRE_EQUAL(instance.count(), 1u);

table::ecdsa::record out{};
BOOST_REQUIRE(!instance.get(1u, out));
BOOST_REQUIRE(instance.get(0u, out));
BOOST_REQUIRE(out == record1);

BOOST_REQUIRE(instance.truncate(0));
BOOST_REQUIRE_EQUAL(instance.count(), 0u);
BOOST_REQUIRE(!instance.get(0u, out));
}

BOOST_AUTO_TEST_SUITE_END()
24 changes: 24 additions & 0 deletions test/tables/caches/schnorr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,28 @@ BOOST_AUTO_TEST_CASE(schnorr__get__two__expected)
BOOST_REQUIRE(out == record2);
}

BOOST_AUTO_TEST_CASE(schnorr__truncate__from_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);

BOOST_REQUIRE_EQUAL(instance.count(), 2u);
BOOST_REQUIRE(instance.truncate(1));
BOOST_REQUIRE_EQUAL(instance.count(), 1u);

table::schnorr::record out{};
BOOST_REQUIRE(!instance.get(1u, out));
BOOST_REQUIRE(instance.get(0u, out));
BOOST_REQUIRE(out == record1);

BOOST_REQUIRE(instance.truncate(0));
BOOST_REQUIRE_EQUAL(instance.count(), 0u);
BOOST_REQUIRE(!instance.get(0u, out));
}

BOOST_AUTO_TEST_SUITE_END()
Loading