diff --git a/include/bitcoin/database/impl/query/extent.ipp b/include/bitcoin/database/impl/query/extent.ipp index d30e2457..424e4124 100644 --- a/include/bitcoin/database/impl/query/extent.ipp +++ b/include/bitcoin/database/impl/query/extent.ipp @@ -93,6 +93,7 @@ size_t CLASS::store_body_size() const NOEXCEPT + strong_tx_body_size() + ecdsa_body_size() + schnorr_body_size() + + multisig_body_size() + duplicate_body_size() + prevout_body_size() + validated_bk_body_size() @@ -124,6 +125,7 @@ size_t CLASS::store_head_size() const NOEXCEPT + strong_tx_head_size() + ecdsa_head_size() + schnorr_head_size() + + multisig_head_size() + duplicate_head_size() + prevout_head_size() + validated_bk_head_size() @@ -150,6 +152,7 @@ DEFINE_SIZES(confirmed) DEFINE_SIZES(strong_tx) DEFINE_SIZES(ecdsa) DEFINE_SIZES(schnorr) +DEFINE_SIZES(multisig) DEFINE_SIZES(duplicate) DEFINE_SIZES(prevout) DEFINE_SIZES(validated_bk) @@ -189,6 +192,7 @@ DEFINE_RECORDS(confirmed) DEFINE_RECORDS(strong_tx) DEFINE_RECORDS(ecdsa) DEFINE_RECORDS(schnorr) +DEFINE_RECORDS(multisig) DEFINE_RECORDS(duplicate) DEFINE_RECORDS(filter_bk) DEFINE_RECORDS(address) diff --git a/include/bitcoin/database/impl/query/signatures.ipp b/include/bitcoin/database/impl/query/signatures.ipp index 07818226..e41f6abe 100644 --- a/include/bitcoin/database/impl/query/signatures.ipp +++ b/include/bitcoin/database/impl/query/signatures.ipp @@ -64,22 +64,22 @@ bool CLASS::set_signature(const hash_digest& digest, const ec_compressed& point, } TEMPLATE -bool CLASS::set_signatures(const hash_digest& , const ec_compresseds& , - const ec_signatures& , uint16_t , const header_link& ) NOEXCEPT +bool CLASS::set_signatures(const hash_digest& digest, const ec_compresseds& keys, + const ec_signatures& sigs, uint16_t group, const header_link& link) NOEXCEPT { // ======================================================================== const auto scope = store_.get_transactor(); // Clean single allocation failure (e.g. disk full). - ////return store_.multisig.put(table::multisig::put_ref - ////{ - //// {}, - //// digest, - //// keys, - //// sigs, - //// set, - //// link - ////}); + return store_.multisig.put(table::multisig::put_ref + { + {}, + digest, + keys, + sigs, + group, + link + }); // ======================================================================== return {}; diff --git a/include/bitcoin/database/impl/store.ipp b/include/bitcoin/database/impl/store.ipp index 29199dce..b0b0e3e5 100644 --- a/include/bitcoin/database/impl/store.ipp +++ b/include/bitcoin/database/impl/store.ipp @@ -109,6 +109,9 @@ const std::unordered_map CLASS::tables { table_t::schnorr_table, "schnorr_table" }, { table_t::schnorr_head, "schnorr_head" }, { table_t::schnorr_body, "schnorr_body" }, + { table_t::multisig_table, "multisig_table" }, + { table_t::multisig_head, "multisig_head" }, + { table_t::multisig_body, "multisig_body" }, { table_t::duplicate_table, "duplicate_table" }, { table_t::duplicate_head, "duplicate_head" }, { table_t::duplicate_body, "duplicate_body" }, @@ -186,6 +189,9 @@ CLASS::store(const settings& config) NOEXCEPT schnorr_head_(head(config.path / schema::dir::heads, schema::caches::schnorr), 1, 0, random), schnorr_body_(body(config.path, schema::caches::schnorr), config.schnorr_size, config.schnorr_rate, sequential), + multisig_head_(head(config.path / schema::dir::heads, schema::caches::multisig), 1, 0, random), + multisig_body_(body(config.path, schema::caches::multisig), config.multisig_size, config.multisig_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), @@ -234,6 +240,7 @@ CLASS::store(const settings& config) NOEXCEPT ecdsa(ecdsa_head_, ecdsa_body_), schnorr(schnorr_head_, schnorr_body_), + multisig(multisig_head_, multisig_body_), duplicate(duplicate_head_, duplicate_body_, config.duplicate_buckets), prevout(prevout_head_, prevout_body_, config.prevout_buckets), validated_bk(validated_bk_head_, validated_bk_body_, config.validated_bk_buckets), @@ -319,6 +326,8 @@ code CLASS::create(const event_handler& handler) NOEXCEPT create(ec, ecdsa_body_, table_t::ecdsa_body); create(ec, schnorr_head_, table_t::schnorr_head); create(ec, schnorr_body_, table_t::schnorr_body); + create(ec, multisig_head_, table_t::multisig_head); + create(ec, multisig_body_, table_t::multisig_body); create(ec, duplicate_head_, table_t::duplicate_head); create(ec, duplicate_body_, table_t::duplicate_body); create(ec, prevout_head_, table_t::prevout_head); @@ -364,6 +373,7 @@ code CLASS::create(const event_handler& handler) NOEXCEPT populate(ec, ecdsa, table_t::ecdsa_table); populate(ec, schnorr, table_t::schnorr_table); + populate(ec, multisig, table_t::multisig_table); populate(ec, duplicate, table_t::duplicate_table); populate(ec, prevout, table_t::prevout_table); populate(ec, validated_bk, table_t::validated_bk_table); @@ -439,6 +449,7 @@ code CLASS::open(const event_handler& handler) NOEXCEPT verify(ec, ecdsa, table_t::ecdsa_table); verify(ec, schnorr, table_t::schnorr_table); + verify(ec, multisig, table_t::multisig_table); verify(ec, duplicate, table_t::duplicate_table); verify(ec, prevout, table_t::prevout_table); verify(ec, validated_bk, table_t::validated_bk_table); @@ -557,6 +568,7 @@ code CLASS::snapshot(const event_handler& handler, bool prune) NOEXCEPT flush(ec, ecdsa_body_, table_t::ecdsa_body); flush(ec, schnorr_body_, table_t::schnorr_body); + flush(ec, multisig_body_, table_t::multisig_body); flush(ec, duplicate_body_, table_t::duplicate_body); if (!prune) flush(ec, prevout_body_, table_t::prevout_body); flush(ec, validated_bk_body_, table_t::validated_bk_body); @@ -623,6 +635,8 @@ code CLASS::reload(const event_handler& handler) NOEXCEPT reload(ec, ecdsa_body_, table_t::ecdsa_body); reload(ec, schnorr_head_, table_t::schnorr_head); reload(ec, schnorr_body_, table_t::schnorr_body); + reload(ec, multisig_head_, table_t::multisig_head); + reload(ec, multisig_body_, table_t::multisig_body); reload(ec, duplicate_head_, table_t::duplicate_head); reload(ec, duplicate_body_, table_t::duplicate_body); reload(ec, prevout_head_, table_t::prevout_head); @@ -678,6 +692,7 @@ code CLASS::close(const event_handler& handler) NOEXCEPT close(ec, ecdsa, table_t::ecdsa_table); close(ec, schnorr, table_t::schnorr_table); + close(ec, multisig, table_t::multisig_table); close(ec, duplicate, table_t::duplicate_table); close(ec, prevout, table_t::prevout_table); close(ec, validated_bk, table_t::validated_bk_table); @@ -747,6 +762,8 @@ code CLASS::open_load(const event_handler& handler) NOEXCEPT open(ec, ecdsa_body_, table_t::ecdsa_body); open(ec, schnorr_head_, table_t::schnorr_head); open(ec, schnorr_body_, table_t::schnorr_body); + open(ec, multisig_head_, table_t::multisig_head); + open(ec, multisig_body_, table_t::multisig_body); open(ec, duplicate_head_, table_t::duplicate_head); open(ec, duplicate_body_, table_t::duplicate_body); open(ec, prevout_head_, table_t::prevout_head); @@ -800,6 +817,8 @@ code CLASS::open_load(const event_handler& handler) NOEXCEPT load(ec, ecdsa_body_, table_t::ecdsa_body); load(ec, schnorr_head_, table_t::schnorr_head); load(ec, schnorr_body_, table_t::schnorr_body); + load(ec, multisig_head_, table_t::multisig_head); + load(ec, multisig_body_, table_t::multisig_body); load(ec, duplicate_head_, table_t::duplicate_head); load(ec, duplicate_body_, table_t::duplicate_body); load(ec, prevout_head_, table_t::prevout_head); @@ -863,6 +882,8 @@ code CLASS::unload_close(const event_handler& handler) NOEXCEPT unload(ec, ecdsa_body_, table_t::ecdsa_body); unload(ec, schnorr_head_, table_t::schnorr_head); unload(ec, schnorr_body_, table_t::schnorr_body); + unload(ec, multisig_head_, table_t::multisig_head); + unload(ec, multisig_body_, table_t::multisig_body); unload(ec, duplicate_head_, table_t::duplicate_head); unload(ec, duplicate_body_, table_t::duplicate_body); unload(ec, prevout_head_, table_t::prevout_head); @@ -916,6 +937,8 @@ code CLASS::unload_close(const event_handler& handler) NOEXCEPT close(ec, ecdsa_body_, table_t::ecdsa_body); close(ec, schnorr_head_, table_t::schnorr_head); close(ec, schnorr_body_, table_t::schnorr_body); + close(ec, multisig_head_, table_t::multisig_head); + close(ec, multisig_body_, table_t::multisig_body); close(ec, duplicate_head_, table_t::duplicate_head); close(ec, duplicate_body_, table_t::duplicate_body); close(ec, prevout_head_, table_t::prevout_head); @@ -965,6 +988,7 @@ code CLASS::backup(const event_handler& handler, bool prune) NOEXCEPT backup(ec, ecdsa, table_t::ecdsa_table); backup(ec, schnorr, table_t::schnorr_table); + backup(ec, multisig, table_t::multisig_table); backup(ec, duplicate, table_t::duplicate_table); backup(ec, prevout, table_t::prevout_table, prune); backup(ec, validated_bk, table_t::validated_bk_table); @@ -1032,6 +1056,7 @@ code CLASS::dump(const path& folder, auto ecdsa_buffer = ecdsa_head_.get(); auto schnorr_buffer = schnorr_head_.get(); + auto multisig_buffer = multisig_head_.get(); auto duplicate_buffer = duplicate_head_.get(); auto prevout_buffer = prevout_head_.get(); auto validated_bk_buffer = validated_bk_head_.get(); @@ -1056,6 +1081,7 @@ code CLASS::dump(const path& folder, if (!ecdsa_buffer) return error::unloaded_file; if (!schnorr_buffer) return error::unloaded_file; + if (!multisig_buffer) return error::unloaded_file; if (!duplicate_buffer) return error::unloaded_file; if (!prevout_buffer) return error::unloaded_file; if (!validated_bk_buffer) return error::unloaded_file; @@ -1092,6 +1118,7 @@ code CLASS::dump(const path& folder, dump(ec, ecdsa_buffer, schema::caches::ecdsa, table_t::ecdsa_head); dump(ec, schnorr_buffer, schema::caches::schnorr, table_t::schnorr_head); + dump(ec, multisig_buffer, schema::caches::multisig, table_t::multisig_head); dump(ec, duplicate_buffer, schema::caches::duplicate, table_t::duplicate_head); dump(ec, prevout_buffer, schema::caches::prevout, table_t::prevout_head); dump(ec, validated_bk_buffer, schema::caches::validated_bk, table_t::validated_bk_head); @@ -1187,6 +1214,7 @@ code CLASS::restore(const event_handler& handler) NOEXCEPT restore(ec, ecdsa, table_t::ecdsa_table); restore(ec, schnorr, table_t::schnorr_table); + restore(ec, multisig, table_t::multisig_table); restore(ec, duplicate, table_t::duplicate_table); restore(ec, prevout, table_t::prevout_table); restore(ec, validated_bk, table_t::validated_bk_table); @@ -1252,6 +1280,7 @@ code CLASS::get_fault() const NOEXCEPT if ((ec = strong_tx_body_.get_fault())) return ec; if ((ec = ecdsa_body_.get_fault())) return ec; if ((ec = schnorr_body_.get_fault())) return ec; + if ((ec = multisig_body_.get_fault())) return ec; if ((ec = duplicate_body_.get_fault())) return ec; if ((ec = prevout_body_.get_fault())) return ec; if ((ec = validated_bk_body_.get_fault())) return ec; @@ -1284,6 +1313,7 @@ size_t CLASS::get_space() const NOEXCEPT space(strong_tx_body_); space(ecdsa_body_); space(schnorr_body_); + space(multisig_body_); space(duplicate_body_); space(prevout_body_); space(validated_bk_body_); @@ -1320,6 +1350,7 @@ void CLASS::report(const error_handler& handler) const NOEXCEPT report(strong_tx_body_, table_t::strong_tx_body); report(ecdsa_body_, table_t::ecdsa_body); report(schnorr_body_, table_t::schnorr_body); + report(multisig_body_, table_t::multisig_body); report(duplicate_body_, table_t::duplicate_body); report(prevout_body_, table_t::prevout_body); report(validated_bk_body_, table_t::validated_bk_body); diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 2be3a92a..5bac58bf 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -125,6 +125,7 @@ class query size_t strong_tx_head_size() const NOEXCEPT; size_t ecdsa_head_size() const NOEXCEPT; size_t schnorr_head_size() const NOEXCEPT; + size_t multisig_head_size() const NOEXCEPT; size_t duplicate_head_size() const NOEXCEPT; size_t prevout_head_size() const NOEXCEPT; size_t validated_bk_head_size() const NOEXCEPT; @@ -148,6 +149,7 @@ class query size_t strong_tx_body_size() const NOEXCEPT; size_t ecdsa_body_size() const NOEXCEPT; size_t schnorr_body_size() const NOEXCEPT; + size_t multisig_body_size() const NOEXCEPT; size_t duplicate_body_size() const NOEXCEPT; size_t prevout_body_size() const NOEXCEPT; size_t validated_bk_body_size() const NOEXCEPT; @@ -171,6 +173,7 @@ class query size_t strong_tx_size() const NOEXCEPT; size_t ecdsa_size() const NOEXCEPT; size_t schnorr_size() const NOEXCEPT; + size_t multisig_size() const NOEXCEPT; size_t duplicate_size() const NOEXCEPT; size_t prevout_size() const NOEXCEPT; size_t validated_bk_size() const NOEXCEPT; @@ -206,6 +209,7 @@ class query size_t strong_tx_records() const NOEXCEPT; size_t ecdsa_records() const NOEXCEPT; size_t schnorr_records() const NOEXCEPT; + size_t multisig_records() const NOEXCEPT; size_t duplicate_records() const NOEXCEPT; size_t filter_bk_records() const NOEXCEPT; size_t address_records() const NOEXCEPT; @@ -578,7 +582,8 @@ class query 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 ec_compresseds& keys, - const ec_signatures& sigs, uint16_t set, const header_link& link) NOEXCEPT; + const ec_signatures& sigs, uint16_t group, + const header_link& link) NOEXCEPT; /// Confirmation. /// ----------------------------------------------------------------------- diff --git a/include/bitcoin/database/settings.hpp b/include/bitcoin/database/settings.hpp index 5a7371db..a6176e78 100644 --- a/include/bitcoin/database/settings.hpp +++ b/include/bitcoin/database/settings.hpp @@ -101,6 +101,9 @@ struct BCD_API settings uint64_t schnorr_size; uint16_t schnorr_rate; + uint64_t multisig_size; + uint16_t multisig_rate; + // This one is 16 bit (could use table link::integer) for these. uint16_t duplicate_buckets; uint64_t duplicate_size; diff --git a/include/bitcoin/database/store.hpp b/include/bitcoin/database/store.hpp index c0c2ec2f..94ec69c9 100644 --- a/include/bitcoin/database/store.hpp +++ b/include/bitcoin/database/store.hpp @@ -175,6 +175,10 @@ class store Storage schnorr_head_; Storage schnorr_body_; + // array + Storage multisig_head_; + Storage multisig_body_; + // blob arraymap Storage duplicate_head_; Storage duplicate_body_; @@ -255,6 +259,7 @@ class store /// Caches. table::ecdsa ecdsa; table::schnorr schnorr; + table::multisig multisig; table::duplicate duplicate; table::prevout prevout; table::validated_bk validated_bk; diff --git a/include/bitcoin/database/tables/caches/multisig.hpp b/include/bitcoin/database/tables/caches/multisig.hpp index 68775122..f48fb38d 100644 --- a/include/bitcoin/database/tables/caches/multisig.hpp +++ b/include/bitcoin/database/tables/caches/multisig.hpp @@ -43,7 +43,7 @@ struct multisig point = source.read_forward(); signature = source.read_forward(); pair = source.read_byte(); - set = source.read_2_bytes_little_endian(); + group = source.read_2_bytes_little_endian(); header_fk = source.read_little_endian(); BC_ASSERT(!source || source.get_read_position() == minrow); return source; @@ -55,7 +55,7 @@ struct multisig sink.write_bytes(point); sink.write_bytes(signature); sink.write_byte(pair); - sink.write_little_endian(set); + sink.write_little_endian(group); sink.write_little_endian(header_fk); BC_ASSERT(!sink || sink.get_write_position() == minrow); return sink; @@ -67,7 +67,7 @@ struct multisig && point == other.point && signature == other.signature && pair == other.pair - && set == other.set + && group == other.group && header_fk == other.header_fk; } @@ -75,7 +75,7 @@ struct multisig system::ec_compressed point{}; system::ec_signature signature{}; uint8_t pair{}; - uint16_t set{}; + uint16_t group{}; header::integer header_fk{}; }; @@ -87,11 +87,19 @@ struct multisig using namespace system; const auto m = sigs.size(); const auto n = keys.size(); + if (is_subtract_overflow(n, m)) + return {}; - BC_ASSERT(!is_subtract_overflow(n, m)); - BC_ASSERT(!is_add_overflow(n - m, one)); - BC_ASSERT(!is_multiply_overflow(m, add1(n - m))); - return possible_narrow_cast(m * add1(n - m)); + const auto gap = n - m; + if (is_add_overflow(gap, one)) + return {}; + + const auto sum = add1(gap); + if (is_multiply_overflow(m, sum)) + return {}; + + // Terminal count fails the write attempt, so to_data() is guarded. + return possible_narrow_cast(m * sum); } inline bool to_data(flipper& sink) const NOEXCEPT @@ -111,7 +119,7 @@ struct multisig sink.write_bytes(keys.at(key)); sink.write_bytes(sigs.at(sig)); sink.write_byte(pack_word(m, n)); - sink.write_little_endian(set); + sink.write_little_endian(group); sink.write_little_endian( header_fk); } @@ -124,7 +132,7 @@ struct multisig const hash_digest& digest; const system::ec_compresseds& keys; const system::ec_signatures& sigs; - const uint16_t set{}; + const uint16_t group{}; const header::integer header_fk{}; }; }; diff --git a/include/bitcoin/database/tables/names.hpp b/include/bitcoin/database/tables/names.hpp index 6d22e8f5..7855edbe 100644 --- a/include/bitcoin/database/tables/names.hpp +++ b/include/bitcoin/database/tables/names.hpp @@ -59,6 +59,7 @@ namespace caches { constexpr auto ecdsa = "ecdsa"; constexpr auto schnorr = "schnorr"; + constexpr auto multisig = "multisig"; constexpr auto duplicate = "duplicate"; constexpr auto prevout = "prevout"; constexpr auto validated_bk = "validated_bk"; diff --git a/include/bitcoin/database/tables/table.hpp b/include/bitcoin/database/tables/table.hpp index eed537ac..50248250 100644 --- a/include/bitcoin/database/tables/table.hpp +++ b/include/bitcoin/database/tables/table.hpp @@ -75,6 +75,9 @@ enum class table_t schnorr_table, schnorr_head, schnorr_body, + multisig_table, + multisig_head, + multisig_body, duplicate_table, duplicate_head, duplicate_body, diff --git a/include/bitcoin/database/tables/tables.hpp b/include/bitcoin/database/tables/tables.hpp index 1dd6ce13..d34ab4b0 100644 --- a/include/bitcoin/database/tables/tables.hpp +++ b/include/bitcoin/database/tables/tables.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/src/settings.cpp b/src/settings.cpp index 0d00ca64..faa8f26d 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -77,6 +77,9 @@ settings::settings() NOEXCEPT schnorr_size{ 1 }, schnorr_rate{ 50 }, + multisig_size{ 1 }, + multisig_rate{ 50 }, + duplicate_buckets{ 128 }, duplicate_size{ 1 }, duplicate_rate{ 50 }, diff --git a/test/mocks/chunk_store.hpp b/test/mocks/chunk_store.hpp index c68b97ec..062f6cf9 100644 --- a/test/mocks/chunk_store.hpp +++ b/test/mocks/chunk_store.hpp @@ -168,6 +168,16 @@ class chunk_store return schnorr_body_.buffer(); } + system::data_chunk& multisig_head() NOEXCEPT + { + return multisig_head_.buffer(); + } + + system::data_chunk& multisig_body() NOEXCEPT + { + return multisig_body_.buffer(); + } + system::data_chunk& duplicate_head() NOEXCEPT { return duplicate_head_.buffer(); diff --git a/test/mocks/map_store.hpp b/test/mocks/map_store.hpp index 099cb6cd..d13630b2 100644 --- a/test/mocks/map_store.hpp +++ b/test/mocks/map_store.hpp @@ -189,6 +189,16 @@ class map_store return schnorr_body_.file(); } + inline const path& multisig_head_file() const NOEXCEPT + { + return multisig_head_.file(); + } + + inline const path& multisig_body_file() const NOEXCEPT + { + return multisig_body_.file(); + } + inline const path& duplicate_head_file() const NOEXCEPT { return duplicate_head_.file(); diff --git a/test/query/extent.cpp b/test/query/extent.cpp index 5be68517..c10f8bba 100644 --- a/test/query/extent.cpp +++ b/test/query/extent.cpp @@ -53,6 +53,7 @@ BOOST_AUTO_TEST_CASE(query_extent__body_sizes__genesis__expected) BOOST_REQUIRE_EQUAL(query.strong_tx_body_size(), schema::strong_tx::minrow); BOOST_REQUIRE_EQUAL(query.ecdsa_body_size(), zero); BOOST_REQUIRE_EQUAL(query.schnorr_body_size(), zero); + BOOST_REQUIRE_EQUAL(query.multisig_body_size(), zero); BOOST_REQUIRE_EQUAL(query.duplicate_body_size(), zero); BOOST_REQUIRE_EQUAL(query.prevout_body_size(), zero); BOOST_REQUIRE_EQUAL(query.validated_bk_body_size(), zero); @@ -105,6 +106,7 @@ BOOST_AUTO_TEST_CASE(query_extent__records__genesis__expected) BOOST_REQUIRE_EQUAL(query.strong_tx_records(), one); BOOST_REQUIRE_EQUAL(query.ecdsa_records(), zero); BOOST_REQUIRE_EQUAL(query.schnorr_records(), zero); + BOOST_REQUIRE_EQUAL(query.multisig_records(), zero); BOOST_REQUIRE_EQUAL(query.duplicate_records(), zero); BOOST_REQUIRE_EQUAL(query.filter_bk_records(), one); BOOST_REQUIRE_EQUAL(query.address_records(), one); diff --git a/test/settings.cpp b/test/settings.cpp index aa0cffc7..1a9d417f 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -63,6 +63,8 @@ BOOST_AUTO_TEST_CASE(settings__construct__default__expected) BOOST_REQUIRE_EQUAL(configuration.ecdsa_rate, 50u); BOOST_REQUIRE_EQUAL(configuration.schnorr_size, 1u); BOOST_REQUIRE_EQUAL(configuration.schnorr_rate, 50u); + BOOST_REQUIRE_EQUAL(configuration.multisig_size, 1u); + BOOST_REQUIRE_EQUAL(configuration.multisig_rate, 50u); BOOST_REQUIRE_EQUAL(configuration.duplicate_buckets, 128u); BOOST_REQUIRE_EQUAL(configuration.duplicate_size, 1u); BOOST_REQUIRE_EQUAL(configuration.duplicate_rate, 50u);