From a11e21cc426f1ef7457930d9f7fd5c77e65d076c Mon Sep 17 00:00:00 2001 From: evoskuil Date: Wed, 3 Jun 2026 22:35:55 -0400 Subject: [PATCH 1/5] Increase batch tables pk to 4 bytes, style. --- include/bitcoin/database/tables/schema.hpp | 14 ++++++-------- test/tables/caches/ecdsa.cpp | 4 ++-- test/tables/caches/schnorr.cpp | 4 ++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/bitcoin/database/tables/schema.hpp b/include/bitcoin/database/tables/schema.hpp index 707eae2b..eeab4713 100644 --- a/include/bitcoin/database/tables/schema.hpp +++ b/include/bitcoin/database/tables/schema.hpp @@ -262,8 +262,8 @@ struct strong_tx // array struct ecdsa { - static constexpr size_t pk = schema::header::pk; - using link = schema::header::link; + static constexpr size_t pk = schema::outs::pk; + using link = schema::outs::link; static constexpr size_t minsize = system::hash_size + system::ec_compressed_size + @@ -274,15 +274,14 @@ struct ecdsa 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); + static_assert(link::size == 4u); }; // array struct schnorr { - static constexpr size_t pk = schema::header::pk; - using link = schema::header::link; + static constexpr size_t pk = schema::outs::pk; + using link = schema::outs::link; static constexpr size_t minsize = system::hash_size + system::ec_xonly_size + @@ -293,8 +292,7 @@ struct schnorr 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); + static_assert(link::size == 4u); }; // record hashmap diff --git a/test/tables/caches/ecdsa.cpp b/test/tables/caches/ecdsa.cpp index 6bfb4d41..906ee3d8 100644 --- a/test/tables/caches/ecdsa.cpp +++ b/test/tables/caches/ecdsa.cpp @@ -41,8 +41,8 @@ const table::ecdsa::record record2 0x00cdef12_u32 }; -const auto expected_head = base16_chunk("000000"); -const auto closed_head = base16_chunk("020000"); +const auto expected_head = base16_chunk("00000000"); +const auto closed_head = base16_chunk("02000000"); const auto expected_body = base16_chunk ( // record 1 diff --git a/test/tables/caches/schnorr.cpp b/test/tables/caches/schnorr.cpp index 76b309b8..9b412ce4 100644 --- a/test/tables/caches/schnorr.cpp +++ b/test/tables/caches/schnorr.cpp @@ -41,8 +41,8 @@ const table::schnorr::record record2 0x00cdef12_u32 }; -const auto expected_head = base16_chunk("000000"); -const auto closed_head = base16_chunk("020000"); +const auto expected_head = base16_chunk("00000000"); +const auto closed_head = base16_chunk("02000000"); const auto expected_body = base16_chunk ( // record 1 From 3f98f58a31649bbe408f9d4cba34b2c69cd92cd9 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Wed, 3 Jun 2026 22:36:34 -0400 Subject: [PATCH 2/5] Stub in multisig table. --- Makefile.am | 2 + .../libbitcoin-database-test.vcxproj | 1 + .../libbitcoin-database-test.vcxproj.filters | 3 + .../libbitcoin-database-test/packages.config | 2 +- .../libbitcoin-database.vcxproj | 1 + .../libbitcoin-database.vcxproj.filters | 3 + .../libbitcoin-database-test.vcxproj | 1 + .../libbitcoin-database-test.vcxproj.filters | 3 + .../libbitcoin-database-test/packages.config | 2 +- .../libbitcoin-database.vcxproj | 1 + .../libbitcoin-database.vcxproj.filters | 3 + include/bitcoin/database.hpp | 1 + .../database/tables/caches/multisig.hpp | 95 ++++++++++++++++ include/bitcoin/database/tables/schema.hpp | 22 +++- test/tables/caches/multisig.cpp | 103 ++++++++++++++++++ 15 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 include/bitcoin/database/tables/caches/multisig.hpp create mode 100644 test/tables/caches/multisig.cpp diff --git a/Makefile.am b/Makefile.am index 09569991..0fa986ae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -136,6 +136,7 @@ test_libbitcoin_database_test_SOURCES = \ test/tables/archives/txs.cpp \ test/tables/caches/duplicate.cpp \ test/tables/caches/ecdsa.cpp \ + test/tables/caches/multisig.cpp \ test/tables/caches/prevout.cpp \ test/tables/caches/schnorr.cpp \ test/tables/caches/validated_bk.cpp \ @@ -321,6 +322,7 @@ include_bitcoin_database_tables_cachesdir = ${includedir}/bitcoin/database/table 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/multisig.hpp \ include/bitcoin/database/tables/caches/prevout.hpp \ include/bitcoin/database/tables/caches/schnorr.hpp \ include/bitcoin/database/tables/caches/validated_bk.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 e580d4c1..0df9bb43 100644 --- a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj @@ -198,6 +198,7 @@ + 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 7a3eb8dd..81b8bc14 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 @@ -270,6 +270,9 @@ src\tables\caches + + src\tables\caches + src\tables\caches diff --git a/builds/msvc/vs2022/libbitcoin-database-test/packages.config b/builds/msvc/vs2022/libbitcoin-database-test/packages.config index 3f05734c..d2115e17 100644 --- a/builds/msvc/vs2022/libbitcoin-database-test/packages.config +++ b/builds/msvc/vs2022/libbitcoin-database-test/packages.config @@ -13,7 +13,7 @@ + - diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj index 8f7f605e..8860fdf5 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj @@ -187,6 +187,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters index 9ce1ddeb..bbe878b3 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -272,6 +272,9 @@ include\bitcoin\database\tables\caches + + include\bitcoin\database\tables\caches + include\bitcoin\database\tables\caches 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 ae03f69d..c3360558 100644 --- a/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj +++ b/builds/msvc/vs2026/libbitcoin-database-test/libbitcoin-database-test.vcxproj @@ -198,6 +198,7 @@ + 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 7a3eb8dd..81b8bc14 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 @@ -270,6 +270,9 @@ src\tables\caches + + src\tables\caches + src\tables\caches diff --git a/builds/msvc/vs2026/libbitcoin-database-test/packages.config b/builds/msvc/vs2026/libbitcoin-database-test/packages.config index df1d1f3e..1c55fa06 100644 --- a/builds/msvc/vs2026/libbitcoin-database-test/packages.config +++ b/builds/msvc/vs2026/libbitcoin-database-test/packages.config @@ -13,7 +13,7 @@ + - diff --git a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj index cd33d404..1ad82100 100644 --- a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj @@ -187,6 +187,7 @@ + diff --git a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters index 9ce1ddeb..bbe878b3 100644 --- a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -272,6 +272,9 @@ include\bitcoin\database\tables\caches + + include\bitcoin\database\tables\caches + include\bitcoin\database\tables\caches diff --git a/include/bitcoin/database.hpp b/include/bitcoin/database.hpp index 2959ad98..f324b9a4 100644 --- a/include/bitcoin/database.hpp +++ b/include/bitcoin/database.hpp @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include diff --git a/include/bitcoin/database/tables/caches/multisig.hpp b/include/bitcoin/database/tables/caches/multisig.hpp new file mode 100644 index 00000000..f78ad6ea --- /dev/null +++ b/include/bitcoin/database/tables/caches/multisig.hpp @@ -0,0 +1,95 @@ +/** + * 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_MULTISIG_HPP +#define LIBBITCOIN_DATABASE_TABLES_CACHES_MULTISIG_HPP + +#include +#include +#include + +namespace libbitcoin { +namespace database { +namespace table { + +/// multisig is an array of multisig signature validation records. +struct multisig + : public no_map +{ + using header = schema::header::link; + using no_map::nomap; + + struct record + : public schema::multisig + { + 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(); + set = source.read_2_bytes_little_endian(); + pair = source.read_byte(); + 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); + sink.write_little_endian(set); + sink.write_byte(pair); + 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 + && set == other.set + && pair == other.pair; + } + + system::hash_digest digest{}; + system::ec_compressed point{}; + system::ec_signature signature{}; + header::integer header_fk{}; + uint16_t set{}; + uint8_t pair{}; + }; +}; + +static_assert(offsetof(system::multisig::triple, digest) == 0); +static_assert(offsetof(system::multisig::triple, point) == 32); +static_assert(offsetof(system::multisig::triple, signature) == 65); +static_assert(offsetof(system::multisig::triple, identifier) == 129); +static_assert(offsetof(system::multisig::triple, set) == 132); +static_assert(offsetof(system::multisig::triple, pair) == 134); +static_assert(sizeof(system::multisig::triple) == 32 + 33 + 64 + 3 + 2 + 1); + +} // namespace table +} // namespace database +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/database/tables/schema.hpp b/include/bitcoin/database/tables/schema.hpp index eeab4713..95d62da9 100644 --- a/include/bitcoin/database/tables/schema.hpp +++ b/include/bitcoin/database/tables/schema.hpp @@ -31,7 +31,7 @@ constexpr size_t bit = 1; // single bit flag. constexpr size_t code = 1; // validation state. constexpr size_t size = 3; // tx/block size/weight. constexpr size_t height_ = 3; // height record. -constexpr size_t count_ = 2; // txs count. +constexpr size_t count_ = 2; // txs/block count, inputs/block count. constexpr size_t index = 3; // input/output index. constexpr size_t sigops = 3; // signature op count. constexpr size_t flags = 4; // fork flags. @@ -295,6 +295,26 @@ struct schnorr static_assert(link::size == 4u); }; +// array +struct multisig +{ + static constexpr size_t pk = schema::outs::pk; + using link = schema::outs::link; + static constexpr size_t minsize = + system::hash_size + + system::ec_compressed_size + + system::ec_signature_size + + schema::header::pk + + count_ + // input (within block) correlation counter. + one; // [m|n] pairing merged to one byte (max 16). + static constexpr size_t minrow = minsize; + static constexpr size_t size = minsize; + static constexpr link count() NOEXCEPT { return 1; } + static_assert(minsize == 135u); + static_assert(minrow == 135u); + static_assert(link::size == 4u); +}; + // record hashmap struct duplicate { diff --git a/test/tables/caches/multisig.cpp b/test/tables/caches/multisig.cpp new file mode 100644 index 00000000..212359e0 --- /dev/null +++ b/test/tables/caches/multisig.cpp @@ -0,0 +1,103 @@ +/** + * 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(multisig_tests) + +using namespace system; + +const table::multisig::record record1 +{ + {}, + base16_hash("1111111111111111111111111111111111111111111111111111111111111111"), + base16_array("222222222222222222222222222222222222222222222222222222222222222222"), + base16_array("33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"), + 0x00345678_u32, + 0xbbaa_u16, + 0xcd_u8 +}; + +const table::multisig::record record2 +{ + {}, + base16_hash("4444444444444444444444444444444444444444444444444444444444444444"), + base16_array("555555555555555555555555555555555555555555555555555555555555555555"), + base16_array("66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"), + 0x00cdef12_u32, + 0x3412_u16, + 0x89_u8 +}; + +const auto expected_head = base16_chunk("00000000"); +const auto closed_head = base16_chunk("02000000"); +const auto expected_body = base16_chunk +( + // record 1 + "1111111111111111111111111111111111111111111111111111111111111111" + "222222222222222222222222222222222222222222222222222222222222222222" + "33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" + "785634aabbcd" + + // record 2 + "4444444444444444444444444444444444444444444444444444444444444444" + "555555555555555555555555555555555555555555555555555555555555555555" + "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666" + "12efcd123489" +); + +BOOST_AUTO_TEST_CASE(multisig__put__two__expected) +{ + test::chunk_storage head_store{}; + test::chunk_storage body_store{}; + table::multisig instance{ head_store, body_store }; + BOOST_REQUIRE(instance.create()); + + table::multisig::link link1{}; + BOOST_REQUIRE(instance.put_link(link1, record1)); + BOOST_REQUIRE_EQUAL(link1, 0u); + + table::multisig::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(multisig__get__two__expected) +{ + auto head = expected_head; + auto body = expected_body; + test::chunk_storage head_store{ head }; + test::chunk_storage body_store{ body }; + table::multisig instance{ head_store, body_store }; + BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); + BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); + + table::multisig::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() From 7576f52a36b331bd300c748eec4f996b61783e9a Mon Sep 17 00:00:00 2001 From: evoskuil Date: Wed, 3 Jun 2026 23:06:05 -0400 Subject: [PATCH 3/5] Use BCD_API. --- include/bitcoin/database/types/fee_rate.hpp | 2 +- include/bitcoin/database/types/header_state.hpp | 2 +- include/bitcoin/database/types/position.hpp | 2 +- include/bitcoin/database/types/span.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/bitcoin/database/types/fee_rate.hpp b/include/bitcoin/database/types/fee_rate.hpp index e9b81632..f34b8d70 100644 --- a/include/bitcoin/database/types/fee_rate.hpp +++ b/include/bitcoin/database/types/fee_rate.hpp @@ -24,7 +24,7 @@ namespace libbitcoin { namespace database { -struct fee_rate +struct BCD_API fee_rate { size_t bytes{}; uint64_t fee{}; diff --git a/include/bitcoin/database/types/header_state.hpp b/include/bitcoin/database/types/header_state.hpp index 9f75ca15..ecc46ce3 100644 --- a/include/bitcoin/database/types/header_state.hpp +++ b/include/bitcoin/database/types/header_state.hpp @@ -25,7 +25,7 @@ namespace libbitcoin { namespace database { -struct header_state +struct BCD_API header_state { header_link link; code ec; diff --git a/include/bitcoin/database/types/position.hpp b/include/bitcoin/database/types/position.hpp index cee7615a..29cb33d2 100644 --- a/include/bitcoin/database/types/position.hpp +++ b/include/bitcoin/database/types/position.hpp @@ -24,7 +24,7 @@ namespace libbitcoin { namespace database { -struct position +struct BCD_API position { size_t sibling; size_t width; diff --git a/include/bitcoin/database/types/span.hpp b/include/bitcoin/database/types/span.hpp index b5fb639e..f50ebee5 100644 --- a/include/bitcoin/database/types/span.hpp +++ b/include/bitcoin/database/types/span.hpp @@ -24,7 +24,7 @@ namespace libbitcoin { namespace database { -struct span +struct BCD_API span { inline size_t size() const NOEXCEPT { From 19da04674e999ca2a1cd3478db846f0657ea9d82 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 4 Jun 2026 00:34:29 -0400 Subject: [PATCH 4/5] Add multisig_view class. --- Makefile.am | 2 + .../libbitcoin-database.vcxproj | 2 + .../libbitcoin-database.vcxproj.filters | 6 +++ .../libbitcoin-database.vcxproj | 2 + .../libbitcoin-database.vcxproj.filters | 6 +++ include/bitcoin/database.hpp | 1 + .../bitcoin/database/types/multisig_view.hpp | 47 +++++++++++++++++++ include/bitcoin/database/types/types.hpp | 1 + src/types/multisig_view.cpp | 45 ++++++++++++++++++ 9 files changed, 112 insertions(+) create mode 100644 include/bitcoin/database/types/multisig_view.hpp create mode 100644 src/types/multisig_view.cpp diff --git a/Makefile.am b/Makefile.am index 0fa986ae..ef8e1ed9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,6 +48,7 @@ src_libbitcoin_database_la_SOURCES = \ src/memory/mman-win32/mman.cpp \ src/memory/mman-win32/mman.hpp \ src/types/history.cpp \ + src/types/multisig_view.cpp \ src/types/unspent.cpp # local: test/libbitcoin-database-test @@ -344,6 +345,7 @@ include_bitcoin_database_types_HEADERS = \ include/bitcoin/database/types/fee_rate.hpp \ include/bitcoin/database/types/header_state.hpp \ include/bitcoin/database/types/history.hpp \ + include/bitcoin/database/types/multisig_view.hpp \ include/bitcoin/database/types/position.hpp \ include/bitcoin/database/types/span.hpp \ include/bitcoin/database/types/type.hpp \ diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj index 8860fdf5..2d65f712 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj @@ -139,6 +139,7 @@ + @@ -208,6 +209,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters index bbe878b3..0fb49486 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -132,6 +132,9 @@ src\types + + src\types + src\types @@ -335,6 +338,9 @@ include\bitcoin\database\types + + include\bitcoin\database\types + include\bitcoin\database\types diff --git a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj index 1ad82100..fd36e8f2 100644 --- a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj @@ -139,6 +139,7 @@ + @@ -208,6 +209,7 @@ + diff --git a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters index bbe878b3..0fb49486 100644 --- a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -132,6 +132,9 @@ src\types + + src\types + src\types @@ -335,6 +338,9 @@ include\bitcoin\database\types + + include\bitcoin\database\types + include\bitcoin\database\types diff --git a/include/bitcoin/database.hpp b/include/bitcoin/database.hpp index f324b9a4..b5b14491 100644 --- a/include/bitcoin/database.hpp +++ b/include/bitcoin/database.hpp @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include diff --git a/include/bitcoin/database/types/multisig_view.hpp b/include/bitcoin/database/types/multisig_view.hpp new file mode 100644 index 00000000..f5b41be1 --- /dev/null +++ b/include/bitcoin/database/types/multisig_view.hpp @@ -0,0 +1,47 @@ +/** + * 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_TYPES_MULTISIG_VIEW_HPP +#define LIBBITCOIN_DATABASE_TYPES_MULTISIG_VIEW_HPP + +#include + +namespace libbitcoin { +namespace database { + +/// Non-owning writable view of a partial signature tuple. +/// m of n limited each to 4 bits (16) packed in upper/lower nibbles. +struct BCD_API multisig_view +{ + multisig_view(const system::ec_compressed& point, + const system::ec_signature& signature, size_t m, size_t n) NOEXCEPT; + + void to_data(system::bytewriter& sink) const NOEXCEPT; + +private: + uint8_t pair_; + const system::ec_compressed& point_; + const system::ec_signature& signature_; +}; + +using multisig_views = std::vector; + +} // namespace database +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/database/types/types.hpp b/include/bitcoin/database/types/types.hpp index 14d6fa21..bae19fdd 100644 --- a/include/bitcoin/database/types/types.hpp +++ b/include/bitcoin/database/types/types.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/src/types/multisig_view.cpp b/src/types/multisig_view.cpp new file mode 100644 index 00000000..f2ddcc58 --- /dev/null +++ b/src/types/multisig_view.cpp @@ -0,0 +1,45 @@ +/** + * 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 + +#include + +namespace libbitcoin { +namespace database { + +multisig_view::multisig_view(const system::ec_compressed& point, + const system::ec_signature& signature, size_t m, size_t n) NOEXCEPT + : point_(point), + signature_(signature), + pair_(system::pack_word(m, n)) +{ + BC_DEBUG_ONLY(constexpr auto half = system::power2(to_half(byte_bits));) + BC_ASSERT(m < half && n < half); +} + +void multisig_view::to_data(system::bytewriter& sink) const NOEXCEPT +{ + sink.write_bytes(point_); + sink.write_bytes(signature_); + sink.write_byte(pair_); + BC_ASSERT(sink); +} + +} // namespace database +} // namespace libbitcoin From 1c33c87b5c3fae5342521be2ad70515bf6961fa6 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 4 Jun 2026 01:42:53 -0400 Subject: [PATCH 5/5] Multisig table WIP. --- .../database/impl/query/signatures.ipp | 34 ++++++++++++++++--- include/bitcoin/database/query.hpp | 8 +++-- .../database/tables/caches/multisig.hpp | 24 ++++++------- test/tables/caches/multisig.cpp | 12 +++---- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/include/bitcoin/database/impl/query/signatures.ipp b/include/bitcoin/database/impl/query/signatures.ipp index 9d352430..56b6a4d1 100644 --- a/include/bitcoin/database/impl/query/signatures.ipp +++ b/include/bitcoin/database/impl/query/signatures.ipp @@ -20,19 +20,20 @@ #define LIBBITCOIN_DATABASE_QUERY_SIGNATURES_IPP #include +#include namespace libbitcoin { namespace database { TEMPLATE -bool CLASS::set_signature(const hash_digest& digest, const ec_compressed& point, +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_.ecdsa.put(table::ecdsa::record + return store_.schnorr.put(table::schnorr::record { {}, digest, @@ -44,14 +45,14 @@ bool CLASS::set_signature(const hash_digest& digest, const ec_compressed& point, } TEMPLATE -bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point, +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_.schnorr.put(table::schnorr::record + return store_.ecdsa.put(table::ecdsa::record { {}, digest, @@ -62,6 +63,31 @@ bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point, // ======================================================================== } +TEMPLATE +bool CLASS::set_signatures(const hash_digest& , + const multisig_views& , uint16_t , const header_link& ) NOEXCEPT +{ + // ======================================================================== + const auto scope = store_.get_transactor(); + + // TODO: allocate and then iterate. + + // Clean single allocation failure (e.g. disk full). + ////return store_.multisig.put(table::multisig::record + ////{ + //// {}, + //// digest, + //// point, + //// signature, + //// pair, + //// link, + //// set + ////}); + // ======================================================================== + + return {}; +} + } // namespace database } // namespace libbitcoin diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 1bddcf0d..c982d325 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -570,11 +570,13 @@ 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; + /// Set signature (schnorr/ecdsa/multisig) table entry. bool set_signature(const hash_digest& digest, const ec_xonly& point, const ec_signature& signature, const header_link& link) NOEXCEPT; + bool set_signature(const hash_digest& digest, const ec_compressed& point, + const ec_signature& signature, const header_link& link) NOEXCEPT; + bool set_signatures(const hash_digest& digest, const multisig_views& pairs, + uint16_t set, const header_link& link) NOEXCEPT; /// Confirmation. /// ----------------------------------------------------------------------- diff --git a/include/bitcoin/database/tables/caches/multisig.hpp b/include/bitcoin/database/tables/caches/multisig.hpp index f78ad6ea..0ac4c54c 100644 --- a/include/bitcoin/database/tables/caches/multisig.hpp +++ b/include/bitcoin/database/tables/caches/multisig.hpp @@ -42,9 +42,9 @@ struct multisig digest = source.read_hash(); point = source.read_forward(); signature = source.read_forward(); - header_fk = source.read_little_endian(); - set = source.read_2_bytes_little_endian(); pair = source.read_byte(); + set = source.read_2_bytes_little_endian(); + header_fk = source.read_little_endian(); BC_ASSERT(!source || source.get_read_position() == minrow); return source; } @@ -54,9 +54,9 @@ struct multisig sink.write_bytes(digest); sink.write_bytes(point); sink.write_bytes(signature); - sink.write_little_endian(header_fk); - sink.write_little_endian(set); sink.write_byte(pair); + sink.write_little_endian(set); + sink.write_little_endian(header_fk); BC_ASSERT(!sink || sink.get_write_position() == minrow); return sink; } @@ -66,27 +66,27 @@ struct multisig return digest == other.digest && point == other.point && signature == other.signature - && header_fk == other.header_fk + && pair == other.pair && set == other.set - && pair == other.pair; + && header_fk == other.header_fk; } system::hash_digest digest{}; system::ec_compressed point{}; system::ec_signature signature{}; - header::integer header_fk{}; - uint16_t set{}; uint8_t pair{}; + uint16_t set{}; + header::integer header_fk{}; }; }; static_assert(offsetof(system::multisig::triple, digest) == 0); static_assert(offsetof(system::multisig::triple, point) == 32); static_assert(offsetof(system::multisig::triple, signature) == 65); -static_assert(offsetof(system::multisig::triple, identifier) == 129); -static_assert(offsetof(system::multisig::triple, set) == 132); -static_assert(offsetof(system::multisig::triple, pair) == 134); -static_assert(sizeof(system::multisig::triple) == 32 + 33 + 64 + 3 + 2 + 1); +static_assert(offsetof(system::multisig::triple, pair) == 129); +static_assert(offsetof(system::multisig::triple, set) == 130); +static_assert(offsetof(system::multisig::triple, identifier) == 132); +static_assert(sizeof(system::multisig::triple) == 32 + 33 + 64 + 1 + 2 + 3); } // namespace table } // namespace database diff --git a/test/tables/caches/multisig.cpp b/test/tables/caches/multisig.cpp index 212359e0..6ea77262 100644 --- a/test/tables/caches/multisig.cpp +++ b/test/tables/caches/multisig.cpp @@ -29,9 +29,9 @@ const table::multisig::record record1 base16_hash("1111111111111111111111111111111111111111111111111111111111111111"), base16_array("222222222222222222222222222222222222222222222222222222222222222222"), base16_array("33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"), - 0x00345678_u32, + 0xcd_u8, 0xbbaa_u16, - 0xcd_u8 + 0x00345678_u32 }; const table::multisig::record record2 @@ -40,9 +40,9 @@ const table::multisig::record record2 base16_hash("4444444444444444444444444444444444444444444444444444444444444444"), base16_array("555555555555555555555555555555555555555555555555555555555555555555"), base16_array("66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"), - 0x00cdef12_u32, + 0x89_u8, 0x3412_u16, - 0x89_u8 + 0x00cdef12_u32 }; const auto expected_head = base16_chunk("00000000"); @@ -53,13 +53,13 @@ const auto expected_body = base16_chunk "1111111111111111111111111111111111111111111111111111111111111111" "222222222222222222222222222222222222222222222222222222222222222222" "33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" - "785634aabbcd" + "cdaabb785634" // record 2 "4444444444444444444444444444444444444444444444444444444444444444" "555555555555555555555555555555555555555555555555555555555555555555" "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666" - "12efcd123489" + "89123412efcd" ); BOOST_AUTO_TEST_CASE(multisig__put__two__expected)