diff --git a/include/bitcoin/database/impl/query/batch/silent.ipp b/include/bitcoin/database/impl/query/batch/silent.ipp index 11a11efb1..6a099a562 100644 --- a/include/bitcoin/database/impl/query/batch/silent.ipp +++ b/include/bitcoin/database/impl/query/batch/silent.ipp @@ -76,9 +76,10 @@ bool CLASS::scan_silent(const stopper& cancel, return !cancel; } -// Rows are in validation order, so the rows of confirmed blocks are selected -// by tx link from the range and only the selected rows are scanned. A block's -// txs are a few runs of consecutive links, so membership is a search of runs. +// Rows are in validation order, so the rows of confirmed blocks in the cut are +// selected by tx link from the range, along with all unconfirmed rows, and only +// the selected rows are scanned. A block's txs are a few runs of consecutive +// links, so membership is a search of runs. TEMPLATE bool CLASS::scan_silent(const stopper& cancel, const system::scan::batch::receiver& keys, size_t first, size_t last, @@ -114,19 +115,18 @@ bool CLASS::scan_silent(const stopper& cancel, merged.emplace_back(low, high); } - const auto latch = is_pooling() ? get_latch_tx() : max_size_t; const auto selected = [&](link_t link) NOEXCEPT { - if (link >= latch) - return true; - const auto it = std::upper_bound(merged.cbegin(), merged.cend(), link, [](link_t value, const run_t& run) NOEXCEPT { return value < run.first; }); - return it != merged.cbegin() && link <= std::prev(it)->second; + if (it != merged.cbegin() && link <= std::prev(it)->second) + return true; + + return to_block(link).is_terminal(); }; const auto correlate_ptr = store_.scan.correlate.get_memory(); @@ -265,7 +265,7 @@ size_t CLASS::get_silent_floor(size_t start, bool time) const NOEXCEPT if (time && !get_mtp_height(height, start)) height = max_size_t; - return get_scan_floor(height).value; + return get_scan_floor(height); } // Rows are allocated zero-filled and a nonzero correlate publishes the row. diff --git a/include/bitcoin/database/impl/query/consensus/consensus_strong.ipp b/include/bitcoin/database/impl/query/consensus/consensus_strong.ipp index d0a92f57b..733cd79d6 100644 --- a/include/bitcoin/database/impl/query/consensus/consensus_strong.ipp +++ b/include/bitcoin/database/impl/query/consensus/consensus_strong.ipp @@ -109,21 +109,10 @@ TEMPLATE bool CLASS::set_strong(const header_link& link, const tx_links& fks, bool positive) NOEXCEPT { - using namespace system; - using link_t = table::strong::link; - using element_t = table::strong::record; - - // Preallocate all strong records for the block and reuse memory ptr. - const auto records = possible_narrow_cast(fks.size()); - auto record = store_.strong.allocate(records); - const auto ptr = store_.strong.get_memory(); - + const table::strong::replace element{ {}, table::strong::merge(positive, link) }; for (const auto& fk: fks) - if (!store_.strong.put(ptr, record++, tx_link{ fk }, element_t - { - {}, - table::strong::merge(positive, link) - })) return false; + if (!store_.strong.set(fk, element)) + return false; return true; } diff --git a/include/bitcoin/database/impl/query/extent.ipp b/include/bitcoin/database/impl/query/extent.ipp index 61146bc7e..d626487fb 100644 --- a/include/bitcoin/database/impl/query/extent.ipp +++ b/include/bitcoin/database/impl/query/extent.ipp @@ -212,7 +212,7 @@ DEFINE_BUCKETS(tx) DEFINE_HEADMAP_BUCKETS(candidate) DEFINE_HEADMAP_BUCKETS(confirmed) -DEFINE_BUCKETS(strong) +DEFINE_HEADMAP_BUCKETS(strong) DEFINE_BUCKETS(scan) DEFINE_HEADMAP_BUCKETS(state) DEFINE_BUCKETS(duplicate) @@ -230,7 +230,6 @@ DEFINE_RECORDS(ins) DEFINE_RECORDS(outs) DEFINE_RECORDS(tx) -DEFINE_RECORDS(strong) DEFINE_RECORDS(scan) DEFINE_RECORDS(scan_prefix) DEFINE_RECORDS(ecdsa0) diff --git a/include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp b/include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp index 620ced0e2..0cdcb6dfc 100644 --- a/include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp +++ b/include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp @@ -343,11 +343,11 @@ tx_links CLASS::to_duplicates(const hash_digest& tx_hash) const NOEXCEPT TEMPLATE header_link CLASS::to_block(const tx_link& link) const NOEXCEPT { - table::strong::record strong{}; - if (!store_.strong.find(link, strong) || !strong.positive()) + const auto strong = store_.strong.at(link); + if (!table::strong::positive(strong)) return {}; - return strong.header_fk(); + return table::strong::header_fk(strong); } // utilities diff --git a/include/bitcoin/database/impl/store/store.ipp b/include/bitcoin/database/impl/store/store.ipp index 288841c7e..9fddf8aee 100644 --- a/include/bitcoin/database/impl/store/store.ipp +++ b/include/bitcoin/database/impl/store/store.ipp @@ -73,8 +73,7 @@ CLASS::store(const settings& config) NOEXCEPT candidate_head_(head(config.path / schema::dir::heads, schema::indexes::candidate), head_settings(config.candidate), sequential), confirmed_head_(head(config.path / schema::dir::heads, schema::indexes::confirmed), head_settings(config.confirmed), sequential), - strong_head_(head(config.path / schema::dir::heads, schema::indexes::strong), head_settings(config.strong), random), - strong_body_(body(config.path, schema::indexes::strong), config.strong, sequential, staged), + strong_head_(head(config.path / schema::dir::heads, schema::indexes::strong), head_settings(config.strong), random), scan_head_(head(config.path / schema::dir::heads, schema::indexes::scan), head_settings(config.scan), random), scan_body_(body(config.path, schema::indexes::scan), config.scan, sequential, staged), scan_prefix_head_(head(config.path / schema::dir::heads, schema::indexes::scan_prefix), head_settings(config.scan), sequential), @@ -157,7 +156,7 @@ CLASS::store(const settings& config) NOEXCEPT candidate(candidate_head_), confirmed(confirmed_head_), - strong(strong_head_, strong_body_, config.strong.buckets, config.strong.expected), + strong(strong_head_), scan(scan_head_, scan_body_, config.scan.buckets), scan_prefix(scan_prefix_head_, scan_prefix_body_), @@ -193,7 +192,6 @@ CLASS::store(const settings& config) NOEXCEPT envelope_.ins_k = possible_narrow_cast(ins.filter_k()); envelope_.outs_k = possible_narrow_cast(outs.filter_k()); envelope_.tx_k = possible_narrow_cast(tx.filter_k()); - envelope_.strong_k = possible_narrow_cast(strong.filter_k()); envelope_.duplicate_k = possible_narrow_cast(duplicate.filter_k()); envelope_.pool_k = possible_narrow_cast(pool.filter_k()); envelope_.wtxid_k = possible_narrow_cast(wtxid.filter_k()); diff --git a/include/bitcoin/database/impl/store/store_create.ipp b/include/bitcoin/database/impl/store/store_create.ipp index d0a8c2b93..97435d510 100644 --- a/include/bitcoin/database/impl/store/store_create.ipp +++ b/include/bitcoin/database/impl/store/store_create.ipp @@ -97,7 +97,6 @@ code CLASS::create_load(const event_handler& handler) NOEXCEPT create(ec, candidate_head_, table_t::candidate_head); create(ec, confirmed_head_, table_t::confirmed_head); create(ec, strong_head_, table_t::strong_head); - create(ec, strong_body_, table_t::strong_body); create(ec, scan_head_, table_t::scan_head); create(ec, scan_body_, table_t::scan_body); create(ec, scan_prefix_head_, table_t::scan_prefix_head); diff --git a/include/bitcoin/database/impl/store/store_open.ipp b/include/bitcoin/database/impl/store/store_open.ipp index c43f0d346..7fd331004 100644 --- a/include/bitcoin/database/impl/store/store_open.ipp +++ b/include/bitcoin/database/impl/store/store_open.ipp @@ -210,7 +210,6 @@ code CLASS::load_envelope() NOEXCEPT !ins.set_buckets(envelope_.ins_buckets) || !outs.set_buckets(envelope_.outs_buckets) || !tx.set_buckets(envelope_.tx_buckets) || - !strong.set_buckets(envelope_.strong_buckets) || !duplicate.set_buckets(envelope_.duplicate_buckets) || !pool.set_buckets(envelope_.pool_buckets) || !wtxid.set_buckets(envelope_.wtxid_buckets)) @@ -223,7 +222,6 @@ code CLASS::load_envelope() NOEXCEPT !ins.set_filter_k(envelope_.ins_k) || !outs.set_filter_k(envelope_.outs_k) || !tx.set_filter_k(envelope_.tx_k) || - !strong.set_filter_k(envelope_.strong_k) || !duplicate.set_filter_k(envelope_.duplicate_k) || !pool.set_filter_k(envelope_.pool_k) || !wtxid.set_filter_k(envelope_.wtxid_k)) diff --git a/include/bitcoin/database/impl/store/store_open_load.ipp b/include/bitcoin/database/impl/store/store_open_load.ipp index 16900737f..ec3831c71 100644 --- a/include/bitcoin/database/impl/store/store_open_load.ipp +++ b/include/bitcoin/database/impl/store/store_open_load.ipp @@ -81,7 +81,6 @@ code CLASS::open_load(const event_handler& handler) NOEXCEPT open(ec, candidate_head_, table_t::candidate_head); open(ec, confirmed_head_, table_t::confirmed_head); open(ec, strong_head_, table_t::strong_head); - open(ec, strong_body_, table_t::strong_body); open(ec, scan_head_, table_t::scan_head); open(ec, scan_body_, table_t::scan_body); open(ec, scan_prefix_head_, table_t::scan_prefix_head); @@ -146,7 +145,6 @@ code CLASS::open_load(const event_handler& handler) NOEXCEPT load(ec, candidate_head_, table_t::candidate_head); load(ec, confirmed_head_, table_t::confirmed_head); load(ec, strong_head_, table_t::strong_head); - load(ec, strong_body_, table_t::strong_body); load(ec, scan_head_, table_t::scan_head); load(ec, scan_body_, table_t::scan_body); load(ec, scan_prefix_head_, table_t::scan_prefix_head); diff --git a/include/bitcoin/database/impl/store/store_reload.ipp b/include/bitcoin/database/impl/store/store_reload.ipp index 4af834134..57a9ae85f 100644 --- a/include/bitcoin/database/impl/store/store_reload.ipp +++ b/include/bitcoin/database/impl/store/store_reload.ipp @@ -71,7 +71,6 @@ code CLASS::reload(const event_handler& handler) NOEXCEPT reload(ec, candidate_head_, table_t::candidate_head); reload(ec, confirmed_head_, table_t::confirmed_head); reload(ec, strong_head_, table_t::strong_head); - reload(ec, strong_body_, table_t::strong_body); reload(ec, scan_head_, table_t::scan_head); reload(ec, scan_body_, table_t::scan_body); reload(ec, scan_prefix_head_, table_t::scan_prefix_head); diff --git a/include/bitcoin/database/impl/store/store_report.ipp b/include/bitcoin/database/impl/store/store_report.ipp index f8d8e400c..3fefaf3e2 100644 --- a/include/bitcoin/database/impl/store/store_report.ipp +++ b/include/bitcoin/database/impl/store/store_report.ipp @@ -48,7 +48,6 @@ void CLASS::report(const error_handler& handler) const NOEXCEPT report(*outs_body_, table_t::outs_body); report(tx_body_, table_t::tx_body); report(txs_body_, table_t::txs_body); - report(strong_body_, table_t::strong_body); report(scan_body_, table_t::scan_body); report(scan_prefix_body_, table_t::scan_prefix_body); report(ecdsa0_body_, table_t::ecdsa0_body); @@ -94,7 +93,6 @@ code CLASS::get_fault() const NOEXCEPT if ((ec = candidate_head_.get_fault())) return ec; if ((ec = confirmed_head_.get_fault())) return ec; if ((ec = strong_head_.get_fault())) return ec; - if ((ec = strong_body_.get_fault())) return ec; if ((ec = scan_head_.get_fault())) return ec; if ((ec = scan_body_.get_fault())) return ec; if ((ec = scan_prefix_head_.get_fault())) return ec; @@ -169,7 +167,6 @@ size_t CLASS::get_space() const NOEXCEPT space(candidate_head_); space(confirmed_head_); space(strong_head_); - space(strong_body_); space(scan_head_); space(scan_body_); space(scan_prefix_head_); diff --git a/include/bitcoin/database/impl/store/store_snapshot.ipp b/include/bitcoin/database/impl/store/store_snapshot.ipp index 0d2689a93..9dd7caeb9 100644 --- a/include/bitcoin/database/impl/store/store_snapshot.ipp +++ b/include/bitcoin/database/impl/store/store_snapshot.ipp @@ -53,7 +53,6 @@ code CLASS::snapshot(const event_handler& handler, bool prune) NOEXCEPT flush(ec, tx_body_, table_t::tx_body); flush(ec, txs_body_, table_t::txs_body); - flush(ec, strong_body_, table_t::strong_body); flush(ec, scan_body_, table_t::scan_body); flush(ec, scan_prefix_body_, table_t::scan_prefix_body); diff --git a/include/bitcoin/database/impl/store/store_tables.ipp b/include/bitcoin/database/impl/store/store_tables.ipp index 2681e8e47..ecaa5b6c8 100644 --- a/include/bitcoin/database/impl/store/store_tables.ipp +++ b/include/bitcoin/database/impl/store/store_tables.ipp @@ -59,7 +59,6 @@ const CLASS::table_map CLASS::tables { table_t::confirmed_head, "confirmed_head" }, { table_t::strong_table, "strong_table" }, { table_t::strong_head, "strong_head" }, - { table_t::strong_body, "strong_body" }, { table_t::scan_table, "scan_table" }, { table_t::scan_head, "scan_head" }, { table_t::scan_body, "scan_body" }, diff --git a/include/bitcoin/database/impl/store/store_unload_close.ipp b/include/bitcoin/database/impl/store/store_unload_close.ipp index cc88e6f18..b81489bcc 100644 --- a/include/bitcoin/database/impl/store/store_unload_close.ipp +++ b/include/bitcoin/database/impl/store/store_unload_close.ipp @@ -58,7 +58,6 @@ code CLASS::unload_close(const event_handler& handler) NOEXCEPT unload(ec, candidate_head_, table_t::candidate_head); unload(ec, confirmed_head_, table_t::confirmed_head); unload(ec, strong_head_, table_t::strong_head); - unload(ec, strong_body_, table_t::strong_body); unload(ec, scan_head_, table_t::scan_head); unload(ec, scan_body_, table_t::scan_body); unload(ec, scan_prefix_head_, table_t::scan_prefix_head); @@ -133,7 +132,6 @@ code CLASS::unload_close(const event_handler& handler) NOEXCEPT close(ec, candidate_head_, table_t::candidate_head); close(ec, confirmed_head_, table_t::confirmed_head); close(ec, strong_head_, table_t::strong_head); - close(ec, strong_body_, table_t::strong_body); close(ec, scan_head_, table_t::scan_head); close(ec, scan_body_, table_t::scan_body); close(ec, scan_prefix_head_, table_t::scan_prefix_head); diff --git a/include/bitcoin/database/impl/unspent/unspent_reader.ipp b/include/bitcoin/database/impl/unspent/unspent_reader.ipp index 821471ea6..1ffa8e2c3 100644 --- a/include/bitcoin/database/impl/unspent/unspent_reader.ipp +++ b/include/bitcoin/database/impl/unspent/unspent_reader.ipp @@ -247,13 +247,11 @@ code CLASS::read_blocks(header_links& out, if (parents.at(at) != parent) { parent = parents.at(at); - const auto fk = store_.strong.first(ptr, parent); - - table::strong::record strong{}; - if (!store_.strong.get(ptr, fk, strong) || !strong.positive()) + const auto strong = store_.strong.at(ptr, parent); + if (!table::strong::positive(strong)) return error::branch_inactive; - block = strong.header_fk(); + block = table::strong::header_fk(strong); } out.at(at) = block; diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 335c2ccf3..d35b4ad80 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -263,7 +263,6 @@ class query size_t outs_records() const NOEXCEPT; size_t tx_records() const NOEXCEPT; - size_t strong_records() const NOEXCEPT; size_t scan_records() const NOEXCEPT; size_t scan_prefix_records() const NOEXCEPT; size_t ecdsa0_records() const NOEXCEPT; diff --git a/include/bitcoin/database/settings.hpp b/include/bitcoin/database/settings.hpp index b2b04d992..dfec1ecf1 100644 --- a/include/bitcoin/database/settings.hpp +++ b/include/bitcoin/database/settings.hpp @@ -104,7 +104,7 @@ struct BCD_API settings bucket_table candidate{}; bucket_table confirmed{}; - hash_table strong{}; + bucket_table strong{}; bucket_table scan{}; hash_table wtxid{}; diff --git a/include/bitcoin/database/store.hpp b/include/bitcoin/database/store.hpp index cc9648165..14fc984d6 100644 --- a/include/bitcoin/database/store.hpp +++ b/include/bitcoin/database/store.hpp @@ -221,7 +221,6 @@ class store // record hashmap Storage strong_head_; - Storage strong_body_; Storage scan_head_; table::scan_storage scan_body_; Storage scan_prefix_head_; diff --git a/include/bitcoin/database/tables/envelope.hpp b/include/bitcoin/database/tables/envelope.hpp index 9883bd7bb..ba5ed134d 100644 --- a/include/bitcoin/database/tables/envelope.hpp +++ b/include/bitcoin/database/tables/envelope.hpp @@ -86,7 +86,6 @@ struct BCD_API envelope uint32_t ins_buckets{}; uint32_t outs_buckets{}; uint32_t tx_buckets{}; - uint32_t strong_buckets{}; uint32_t duplicate_buckets{}; uint32_t pool_buckets{}; uint32_t wtxid_buckets{}; @@ -94,7 +93,6 @@ struct BCD_API envelope uint8_t ins_k{}; uint8_t outs_k{}; uint8_t tx_k{}; - uint8_t strong_k{}; uint8_t duplicate_k{}; uint8_t pool_k{}; uint8_t wtxid_k{}; diff --git a/include/bitcoin/database/tables/indexes/strong.hpp b/include/bitcoin/database/tables/indexes/strong.hpp index 78e946427..8a2c71d64 100644 --- a/include/bitcoin/database/tables/indexes/strong.hpp +++ b/include/bitcoin/database/tables/indexes/strong.hpp @@ -27,16 +27,18 @@ namespace libbitcoin { namespace database { namespace table { -/// strong is a record hashmap of tx confirmation state. +/// strong is a head-only array of signed header fks indexed by tx.fk. +/// A zero value (the fill) is a negative association to header zero. struct strong - : public hash_map + : public value_map { using header = schema::header::link; - using hash_map::hashmap; + using value = schema::strong::value; + using value_map::headmap; static constexpr auto offset = header::bits; static_assert(offset < to_bits(header::size)); - static constexpr header::integer merge(bool positive, + static constexpr value merge(bool positive, header::integer header_fk) NOEXCEPT { using namespace system; @@ -44,40 +46,33 @@ struct strong return set_right(header_fk, offset, positive); } - struct record - : public schema::strong + static constexpr bool positive(value signed_block_fk) NOEXCEPT { - inline bool positive() const NOEXCEPT - { - return system::get_right(signed_block_fk, offset); - } + return system::get_right(signed_block_fk, offset); + } - inline header::integer header_fk() const NOEXCEPT - { - return system::set_right(signed_block_fk, offset, false); - } + static constexpr header::integer header_fk(value signed_block_fk) NOEXCEPT + { + return system::set_right(signed_block_fk, offset, false); + } + /// Replace the association. + struct replace + : public schema::strong + { inline bool from_data(reader& source) NOEXCEPT { - signed_block_fk = source.read_little_endian(); - BC_ASSERT(!source || source.get_read_position() == minrow); + source.skip_bytes(cell); return source; } - inline bool to_data(finalizer& sink) const NOEXCEPT + inline bool to_data(flipper& sink) const NOEXCEPT { - sink.write_little_endian(signed_block_fk); - BC_ASSERT(!sink || sink.get_write_position() == minrow); + sink.write_little_endian(signed_block_fk); return sink; } - inline bool operator==(const record& other) const NOEXCEPT - { - return positive() == other.positive() - && header_fk() == other.header_fk(); - } - - header::integer signed_block_fk{}; + value signed_block_fk{}; }; }; diff --git a/include/bitcoin/database/tables/schema.hpp b/include/bitcoin/database/tables/schema.hpp index 73414fb87..36d16e6b1 100644 --- a/include/bitcoin/database/tables/schema.hpp +++ b/include/bitcoin/database/tables/schema.hpp @@ -310,24 +310,23 @@ struct height bool operator==(const height&) const NOEXCEPT = default; }; -// record hashmap +// headmap (signed header fk by tx fk) struct strong { - static constexpr size_t sk = schema::transaction::pk; static constexpr size_t pk = schema::transaction::pk; - using link = linkage; - using key = system::data_array; + using link = schema::transaction::link; + using value = schema::header::link::integer; static constexpr size_t minsize = ////schema::bit + // positive (merged bit into header::pk) schema::header::pk; - static constexpr size_t minrow = pk + sk + minsize; - static constexpr size_t size = minsize; - static constexpr size_t cell = link::size; - static constexpr link count() NOEXCEPT { return 1; } + static constexpr size_t minrow = minsize; + static constexpr size_t size = sizeof(value); + static constexpr size_t cell = sizeof(value); static_assert(minsize == 3u); - static_assert(minrow == 11u); + static_assert(minrow == 3u); static_assert(link::size == 4u); static_assert(cell == 4u); + bool operator==(const strong&) const NOEXCEPT = default; }; /// Cache tables. diff --git a/include/bitcoin/database/tables/table.hpp b/include/bitcoin/database/tables/table.hpp index f902b085f..a102b687d 100644 --- a/include/bitcoin/database/tables/table.hpp +++ b/include/bitcoin/database/tables/table.hpp @@ -58,7 +58,6 @@ enum class table_t confirmed_head, strong_table, strong_head, - strong_body, scan_table, scan_head, scan_body, diff --git a/src/tables/envelope.cpp b/src/tables/envelope.cpp index e3cb04534..6bcd34c6d 100644 --- a/src/tables/envelope.cpp +++ b/src/tables/envelope.cpp @@ -47,7 +47,6 @@ void envelope::set(const settings& database) NOEXCEPT ins_buckets = database.ins.buckets; outs_buckets = database.outs.buckets; tx_buckets = database.tx.buckets; - strong_buckets = database.strong.buckets; duplicate_buckets = database.duplicate.buckets; pool_buckets = database.pool.buckets; wtxid_buckets = database.wtxid.buckets; @@ -177,7 +176,6 @@ bool envelope::from_data(reader& source) NOEXCEPT ins_buckets = source.read_little_endian(); outs_buckets = source.read_little_endian(); tx_buckets = source.read_little_endian(); - strong_buckets = source.read_little_endian(); duplicate_buckets = source.read_little_endian(); pool_buckets = source.read_little_endian(); wtxid_buckets = source.read_little_endian(); @@ -185,7 +183,6 @@ bool envelope::from_data(reader& source) NOEXCEPT ins_k = source.read_byte(); outs_k = source.read_byte(); tx_k = source.read_byte(); - strong_k = source.read_byte(); duplicate_k = source.read_byte(); pool_k = source.read_byte(); wtxid_k = source.read_byte(); @@ -273,7 +270,6 @@ bool envelope::to_data(flipper& sink) const NOEXCEPT sink.write_little_endian(ins_buckets); sink.write_little_endian(outs_buckets); sink.write_little_endian(tx_buckets); - sink.write_little_endian(strong_buckets); sink.write_little_endian(duplicate_buckets); sink.write_little_endian(pool_buckets); sink.write_little_endian(wtxid_buckets); @@ -281,7 +277,6 @@ bool envelope::to_data(flipper& sink) const NOEXCEPT sink.write_byte(ins_k); sink.write_byte(outs_k); sink.write_byte(tx_k); - sink.write_byte(strong_k); sink.write_byte(duplicate_k); sink.write_byte(pool_k); sink.write_byte(wtxid_k); @@ -301,7 +296,7 @@ size_t envelope::serialized_size() const NOEXCEPT { constexpr auto forks_size = 24_size; constexpr auto fixed = (4 * sizeof(uint32_t)) + sizeof(uint16_t) + - (8 * sizeof(uint32_t)) + (11 * sizeof(uint8_t)) + forks_size + + (7 * sizeof(uint32_t)) + (10 * sizeof(uint8_t)) + forks_size + sizeof(uint64_t) + (18 * sizeof(uint32_t)); const auto checkpoint_size = [](const chain::checkpoint& in) NOEXCEPT diff --git a/test/mocks/chunk_store.hpp b/test/mocks/chunk_store.hpp index ea6ffb87f..d741dcf1b 100644 --- a/test/mocks/chunk_store.hpp +++ b/test/mocks/chunk_store.hpp @@ -133,11 +133,6 @@ class chunk_store return strong_head_.buffer(); } - system::data_chunk& strong_body() NOEXCEPT - { - return strong_body_.buffer(); - } - // Caches. system::data_chunk& ecdsa0_head() NOEXCEPT diff --git a/test/mocks/map_store.hpp b/test/mocks/map_store.hpp index d8d4c5ff8..f83e38227 100644 --- a/test/mocks/map_store.hpp +++ b/test/mocks/map_store.hpp @@ -164,11 +164,6 @@ class map_store return strong_head_.file(); } - inline const path& strong_body_file() const NOEXCEPT - { - return strong_body_.file(); - } - inline const path& duplicate_head_file() const NOEXCEPT { return duplicate_head_.file(); diff --git a/test/query/batch/silent.cpp b/test/query/batch/silent.cpp index 1df54ccda..f0531ae93 100644 --- a/test/query/batch/silent.cpp +++ b/test/query/batch/silent.cpp @@ -713,7 +713,6 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__scan_silent__confirmed_heights__selecte test::query_accessor query{ store }; BOOST_REQUIRE(!store.create(test::events_handler)); BOOST_REQUIRE(query.initialize(test::genesis)); - BOOST_REQUIRE(query.set_silent(42, simple_send())); BOOST_REQUIRE(query.set_silent(0, simple_send())); std::vector links{}; @@ -723,7 +722,7 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__scan_silent__confirmed_heights__selecte }; const stopper cancel{}; - BOOST_REQUIRE(query.scan_silent(cancel, get_keys(), 0, 2, 0, 0, handler)); + BOOST_REQUIRE(query.scan_silent(cancel, get_keys(), 0, 1, 0, 0, handler)); BOOST_REQUIRE_EQUAL(links, std::vector{ 0 }); } @@ -748,7 +747,7 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__scan_silent__heights_above_top__none) BOOST_REQUIRE_EQUAL(calls, 0u); } -BOOST_AUTO_TEST_CASE(query_batch_silent__scan_silent__pooling__latched_selected) +BOOST_AUTO_TEST_CASE(query_batch_silent__scan_silent__unconfirmed__selected) { database::settings settings{}; settings.path = TEST_DIRECTORY; @@ -756,7 +755,6 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__scan_silent__pooling__latched_selected) test::query_accessor query{ store }; BOOST_REQUIRE(!store.create(test::events_handler)); BOOST_REQUIRE(query.initialize(test::genesis)); - query.set_pooling(); BOOST_REQUIRE(query.set_silent(0, simple_send())); BOOST_REQUIRE(query.set_silent(42, simple_send())); @@ -781,17 +779,33 @@ BOOST_AUTO_TEST_CASE(query_batch_silent__get_silent_matches__short_cut_from_floo test::query_accessor query{ store }; BOOST_REQUIRE(!store.create(test::events_handler)); BOOST_REQUIRE(query.initialize(test::genesis)); - BOOST_REQUIRE(query.set_silent(42, simple_send())); BOOST_REQUIRE(query.set_silent(0, simple_send())); silent_matches out{}; const stopper cancel{}; const auto genesis = test::genesis.transactions_ptr()->front()->hash(false); - BOOST_REQUIRE(query.get_silent_matches(out, cancel, get_keys(), 0, 2, 0, 0, false)); + BOOST_REQUIRE(query.get_silent_matches(out, cancel, get_keys(), 0, 1, 0, 0, false)); BOOST_REQUIRE_EQUAL(out.size(), 1u); BOOST_REQUIRE_EQUAL(std::get<1>(out.front()), genesis); } +BOOST_AUTO_TEST_CASE(query_batch_silent__get_silent_matches__short_cut_from_floor__unconfirmed_selected) +{ + database::settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_REQUIRE(!store.create(test::events_handler)); + BOOST_REQUIRE(query.initialize(test::genesis)); + BOOST_REQUIRE(query.set_silent(42, simple_send())); + + silent_matches out{}; + const stopper cancel{}; + BOOST_REQUIRE(query.get_silent_matches(out, cancel, get_keys(), 0, 1, 0, 0, false)); + BOOST_REQUIRE_EQUAL(out.size(), 1u); + BOOST_REQUIRE_EQUAL(std::get<0>(out.front()), 0u); +} + BOOST_AUTO_TEST_CASE(query_batch_silent__get_silent_matches__above_floor__unconfirmed) { database::settings settings{}; diff --git a/test/query/extent.cpp b/test/query/extent.cpp index a5fc0ca2a..e1285e01d 100644 --- a/test/query/extent.cpp +++ b/test/query/extent.cpp @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(query_extent__body_sizes__genesis__expected) BOOST_REQUIRE_EQUAL(query.candidate_body_size(), zero); BOOST_REQUIRE_EQUAL(query.confirmed_body_size(), zero); - BOOST_REQUIRE_EQUAL(query.strong_body_size(), schema::strong::minrow); + BOOST_REQUIRE_EQUAL(query.strong_body_size(), zero); BOOST_REQUIRE_EQUAL(query.scan_body_size(), zero); BOOST_REQUIRE_EQUAL(query.ecdsa0_body_size(), zero); BOOST_REQUIRE_EQUAL(query.schnorr0_body_size(), zero); @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(query_extent__buckets__genesis__expected) BOOST_REQUIRE_EQUAL(query.candidate_buckets(), one); BOOST_REQUIRE_EQUAL(query.confirmed_buckets(), one); - BOOST_REQUIRE_EQUAL(query.strong_buckets(), 128u); + BOOST_REQUIRE_EQUAL(query.strong_buckets(), one); BOOST_REQUIRE_EQUAL(query.state_buckets(), one); BOOST_REQUIRE_EQUAL(query.duplicate_buckets(), 128u); BOOST_REQUIRE_EQUAL(query.prevout_buckets(), 128); @@ -122,7 +122,6 @@ BOOST_AUTO_TEST_CASE(query_extent__records__genesis__expected) BOOST_REQUIRE_EQUAL(query.outs_records(), one); BOOST_REQUIRE_EQUAL(query.tx_records(), one); - BOOST_REQUIRE_EQUAL(query.strong_records(), one); BOOST_REQUIRE_EQUAL(query.scan_records(), zero); BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), zero); BOOST_REQUIRE_EQUAL(query.schnorr0_records(), zero); diff --git a/test/settings.cpp b/test/settings.cpp index 164a28215..231fbfd2f 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -32,7 +32,6 @@ BOOST_AUTO_TEST_CASE(settings__construct__default__expected) BOOST_REQUIRE_EQUAL(configuration.envelope.ins_buckets, 128u); BOOST_REQUIRE_EQUAL(configuration.envelope.outs_buckets, 128u); BOOST_REQUIRE_EQUAL(configuration.envelope.tx_buckets, 128u); - BOOST_REQUIRE_EQUAL(configuration.envelope.strong_buckets, 128u); BOOST_REQUIRE_EQUAL(configuration.envelope.duplicate_buckets, 128u); BOOST_REQUIRE_EQUAL(configuration.envelope.pool_buckets, 128u); BOOST_REQUIRE_EQUAL(configuration.envelope.wtxid_buckets, 128u); @@ -70,7 +69,6 @@ BOOST_AUTO_TEST_CASE(settings__construct__default__expected) BOOST_REQUIRE_EQUAL(configuration.confirmed.buckets, 128u); BOOST_REQUIRE_EQUAL(configuration.confirmed.rate, 5u); BOOST_REQUIRE_EQUAL(configuration.strong.buckets, 128u); - BOOST_REQUIRE_EQUAL(configuration.strong.expected, 0u); BOOST_REQUIRE_EQUAL(configuration.strong.size, 1u); BOOST_REQUIRE_EQUAL(configuration.strong.rate, 5u); BOOST_REQUIRE_EQUAL(configuration.scan.size, 1u); diff --git a/test/store/store.cpp b/test/store/store.cpp index 50ea07164..aff0f60f1 100644 --- a/test/store/store.cpp +++ b/test/store/store.cpp @@ -158,7 +158,6 @@ BOOST_AUTO_TEST_CASE(store__paths__default_configuration__expected) BOOST_REQUIRE_EQUAL(instance.candidate_head_file(), "bitcoin/heads/index_candidate.head"); BOOST_REQUIRE_EQUAL(instance.confirmed_head_file(), "bitcoin/heads/index_confirmed.head"); BOOST_REQUIRE_EQUAL(instance.strong_head_file(), "bitcoin/heads/index_strong.head"); - BOOST_REQUIRE_EQUAL(instance.strong_body_file(), "bitcoin/index_strong.data"); BOOST_REQUIRE_EQUAL(instance.duplicate_head_file(), "bitcoin/heads/index_duplicate.head"); BOOST_REQUIRE_EQUAL(instance.duplicate_body_file(), "bitcoin/index_duplicate.data"); BOOST_REQUIRE_EQUAL(instance.state_head_file(), "bitcoin/heads/index_state.head"); diff --git a/test/tables/envelope.cpp b/test/tables/envelope.cpp index ad0d0932d..7c560a999 100644 --- a/test/tables/envelope.cpp +++ b/test/tables/envelope.cpp @@ -22,7 +22,7 @@ BOOST_AUTO_TEST_SUITE(envelope_tests) using namespace system; -constexpr auto default_size = 370_size; +constexpr auto default_size = 365_size; static data_chunk to_chunk(const envelope& instance) { @@ -108,7 +108,6 @@ BOOST_AUTO_TEST_CASE(envelope__set__default_settings__expected) BOOST_REQUIRE_EQUAL(instance.ins_buckets, configuration.ins.buckets); BOOST_REQUIRE_EQUAL(instance.outs_buckets, configuration.outs.buckets); BOOST_REQUIRE_EQUAL(instance.tx_buckets, configuration.tx.buckets); - BOOST_REQUIRE_EQUAL(instance.strong_buckets, configuration.strong.buckets); BOOST_REQUIRE_EQUAL(instance.duplicate_buckets, configuration.duplicate.buckets); BOOST_REQUIRE_EQUAL(instance.pool_buckets, configuration.pool.buckets); BOOST_REQUIRE_EQUAL(instance.wtxid_buckets, configuration.wtxid.buckets); @@ -163,7 +162,6 @@ BOOST_AUTO_TEST_CASE(envelope__construct__mainnet__unset_filter_k) BOOST_REQUIRE_EQUAL(instance.ins_k, 0u); BOOST_REQUIRE_EQUAL(instance.outs_k, 0u); BOOST_REQUIRE_EQUAL(instance.tx_k, 0u); - BOOST_REQUIRE_EQUAL(instance.strong_k, 0u); BOOST_REQUIRE_EQUAL(instance.duplicate_k, 0u); BOOST_REQUIRE_EQUAL(instance.pool_k, 0u); BOOST_REQUIRE_EQUAL(instance.wtxid_k, 0u); diff --git a/test/tables/indexes/strong.cpp b/test/tables/indexes/strong.cpp index 2dd57b644..8f522965b 100644 --- a/test/tables/indexes/strong.cpp +++ b/test/tables/indexes/strong.cpp @@ -22,96 +22,58 @@ BOOST_AUTO_TEST_SUITE(strong_tests) using namespace system; -const table::strong::key key1{ 0x01, 0x02, 0x03, 0x04 }; -const table::strong::key key2{ 0xa1, 0xa2, 0xa3, 0xa4 }; -const table::strong::record strong1 -{ - {}, - table::strong::merge(true, 0x0078f87f) -}; - -const table::strong::record strong2 -{ - {}, - table::strong::merge(false, 0x0078f87f) -}; - +const table::strong::replace strong1{ {}, table::strong::merge(true, 0x0078f87f) }; +const table::strong::replace strong2{ {}, table::strong::merge(false, 0x0078f87f) }; const auto expected_head = base16_chunk ( - "00000000" - "ffffffff" - "01000000" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" -); -const auto closed_head = base16_chunk -( - "02000000" - "ffffffff" - "01000000" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" -); -const auto expected_body = base16_chunk -( - "ffffffff" // next->end - "01020304" // key1 - "7ff8f8" // 0x0078f87f | 0x00800000 - - "00000000" // next-> - "a1a2a3a4" // key2 - "7ff878" // 0x0078f87f | 0x00000000 + "00000000" // bucket[0] (fill) + "7ff8f800" // bucket[1] 0x0078f87f | 0x00800000 + "7ff87800" // bucket[2] 0x0078f87f | 0x00000000 ); -BOOST_AUTO_TEST_CASE(strong__put__two__expected) +BOOST_AUTO_TEST_CASE(strong__set__two__expected) { - test::chunk_storage head_store{}; - test::chunk_storage body_store{}; - table::strong instance{ head_store, body_store, 8 }; + data_chunk head_file{}; + test::chunk_storage head_store{ head_file }; + table::strong instance{ head_store }; BOOST_REQUIRE(instance.create()); - - table::strong::link link1{}; - BOOST_REQUIRE(instance.put_link(link1, key1, strong1)); - BOOST_REQUIRE_EQUAL(link1, 0u); - - table::strong::link link2{}; - BOOST_REQUIRE(instance.put_link(link2, key2, strong2)); - BOOST_REQUIRE_EQUAL(link2, 1u); - - BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); + BOOST_REQUIRE(instance.set(1u, strong1)); + BOOST_REQUIRE(instance.set(2u, strong2)); + BOOST_REQUIRE_EQUAL(instance.count(), 3u); + BOOST_REQUIRE_EQUAL(head_file, expected_head); BOOST_REQUIRE(instance.close()); - BOOST_REQUIRE_EQUAL(head_store.buffer(), closed_head); + BOOST_REQUIRE_EQUAL(head_file, expected_head); } -BOOST_AUTO_TEST_CASE(strong__get__two__expected) +BOOST_AUTO_TEST_CASE(strong__at__two__expected) { - auto head = expected_head; - auto body = expected_body; - test::chunk_storage head_store{ head }; - test::chunk_storage body_store{ body }; - table::strong instance{ head_store, body_store, 32 }; - BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); - - table::strong::record out{}; - BOOST_REQUIRE(instance.get(0u, out)); - BOOST_REQUIRE_EQUAL(out.header_fk(), strong1.header_fk()); - BOOST_REQUIRE_EQUAL(out.positive(), strong1.positive()); - BOOST_REQUIRE_EQUAL(out.signed_block_fk, bit_or(0x0078f87fu, 0x00800000u)); + auto head_file = expected_head; + test::chunk_storage head_store{ head_file }; + table::strong instance{ head_store }; + BOOST_REQUIRE(instance.verify()); + BOOST_REQUIRE_EQUAL(instance.count(), 3u); + BOOST_REQUIRE(!table::strong::positive(instance.at(0))); + BOOST_REQUIRE_EQUAL(table::strong::header_fk(instance.at(0)), 0u); + BOOST_REQUIRE(table::strong::positive(instance.at(1))); + BOOST_REQUIRE_EQUAL(table::strong::header_fk(instance.at(1)), 0x0078f87fu); + BOOST_REQUIRE(!table::strong::positive(instance.at(2))); + BOOST_REQUIRE_EQUAL(table::strong::header_fk(instance.at(2)), 0x0078f87fu); + BOOST_REQUIRE(!table::strong::positive(instance.at(3))); + BOOST_REQUIRE_EQUAL(table::strong::header_fk(instance.at(3)), 0u); +} - BOOST_REQUIRE(instance.get(1u, out)); - BOOST_REQUIRE_EQUAL(out.header_fk(), strong2.header_fk()); - BOOST_REQUIRE_EQUAL(out.positive(), strong2.positive()); - BOOST_REQUIRE_EQUAL(out.signed_block_fk, bit_or(0x0078f87fu, 0x00000000u)); +BOOST_AUTO_TEST_CASE(strong__set__same_index__last_wins) +{ + data_chunk head_file{}; + test::chunk_storage head_store{ head_file }; + table::strong instance{ head_store }; + BOOST_REQUIRE(instance.create()); + BOOST_REQUIRE(instance.set(1u, strong1)); + BOOST_REQUIRE(table::strong::positive(instance.at(1))); + BOOST_REQUIRE(instance.set(1u, strong2)); + BOOST_REQUIRE(!table::strong::positive(instance.at(1))); + BOOST_REQUIRE_EQUAL(table::strong::header_fk(instance.at(1)), 0x0078f87fu); + BOOST_REQUIRE_EQUAL(instance.count(), 2u); } BOOST_AUTO_TEST_SUITE_END()