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
5 changes: 4 additions & 1 deletion include/bitcoin/database/impl/query/height.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,17 @@ header_states CLASS::get_validated_fork(size_t& fork_point,
out.reserve(one);
code ec{};

// Disable filter constraint if filtering is disabled.
filter &= filter_enabled();

///////////////////////////////////////////////////////////////////////////
std::shared_lock interlock{ candidate_reorganization_mutex_ };

fork_point = get_fork_();
auto height = add1(fork_point);
auto link = to_candidate(height);
while (is_block_validated(ec, link, height, top_checkpoint) &&
(!filter || is_filtered(link)))
(!filter || is_filtered_body(link)))
{
out.emplace_back(link, ec);
link = to_candidate(++height);
Expand Down
22 changes: 22 additions & 0 deletions include/bitcoin/database/impl/query/network.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,28 @@ size_t CLASS::get_fork(const hashes& locator) const NOEXCEPT
return zero;
}

TEMPLATE
bool CLASS::get_ancestry(header_links& ancestry, const header_link& descendant,
size_t count) const NOEXCEPT
{
size_t height{};
if (!get_height(height, descendant))
return false;

// Limit to genesis.
count = std::min(add1(height), count);
ancestry.resize(count);
auto link = descendant;

// Ancestry navigation ensures continuity without locks.
// If count is zero then not even descendant is pushed.
// link terminal if previous was genesis (avoided by count <= height).
for (auto& ancestor: ancestry)
link = to_parent((ancestor = link));

return true;
}

} // namespace database
} // namespace libbitcoin

Expand Down
90 changes: 76 additions & 14 deletions include/bitcoin/database/impl/query/optional.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#ifndef LIBBITCOIN_DATABASE_QUERY_OPTIONAL_IPP
#define LIBBITCOIN_DATABASE_QUERY_OPTIONAL_IPP

#include <algorithm>
#include <ranges>
#include <utility>
#include <bitcoin/system.hpp>
#include <bitcoin/database/define.hpp>
Expand Down Expand Up @@ -152,6 +154,12 @@ bool CLASS::get_confirmed_balance(uint64_t& out,
// filter_tx (surrogate-keyed).
// ----------------------------------------------------------------------------

TEMPLATE
bool CLASS::is_filtered_body(const header_link& link) const NOEXCEPT
{
return store_.filter_tx.exists(to_filter_tx(link));
}

TEMPLATE
bool CLASS::get_filter_body(filter& out, const header_link& link) const NOEXCEPT
{
Expand All @@ -163,18 +171,78 @@ bool CLASS::get_filter_body(filter& out, const header_link& link) const NOEXCEPT
return true;
}

// filter_bk (surrogate-keyed).
// ----------------------------------------------------------------------------

TEMPLATE
bool CLASS::is_filtered_head(const header_link& link) const NOEXCEPT
{
return store_.filter_bk.exists(to_filter_bk(link));
}

TEMPLATE
bool CLASS::get_filter_head(hash_digest& out,
const header_link& link) const NOEXCEPT
{
table::filter_bk::get_head filter_bk{};
table::filter_bk::get_head_only filter_bk{};
if (!store_.filter_bk.at(to_filter_bk(link), filter_bk))
return false;

out = std::move(filter_bk.head);
return true;
}

TEMPLATE
bool CLASS::get_filter_hash(hash_digest& out,
const header_link& link) const NOEXCEPT
{
table::filter_bk::get_hash_only filter_bk{};
if (!store_.filter_bk.at(to_filter_bk(link), filter_bk))
return false;

out = std::move(filter_bk.hash);
return true;
}

TEMPLATE
bool CLASS::get_filter_hashes(hashes& filter_hashes,
hash_digest& previous_header, const header_link& stop_link,
size_t count) const NOEXCEPT
{
size_t height{};
if (!get_height(height, stop_link))
return false;

count = std::min(add1(height), count);
filter_hashes.resize(count);
auto link = stop_link;

// Reversal allows ancenstry population into forward vector.
for (auto& hash: std::views::reverse(filter_hashes))
{
// Implies that stop_link is not a filtered block.
if (!get_filter_hash(hash, link))
return false;

// Ancestry from stop link (included) ensures continuity without locks.
link = to_parent(link);
}

// There's no trailing increment without at least one loop iteration.
if (is_zero(count))
link = to_parent(link);

// link is genesis, previous is null.
if (link.is_terminal())
{
previous_header = system::null_hash;
return true;
}

// Obtaining previous from ancestry eansures its continuity as well.
return get_filter_head(previous_header, link);
}

// set_filter_body
// ----------------------------------------------------------------------------

Expand Down Expand Up @@ -213,14 +281,6 @@ bool CLASS::set_filter_body(const header_link& link,
// set_filter_head
// ----------------------------------------------------------------------------

TEMPLATE
bool CLASS::is_filtered(const header_link& link) const NOEXCEPT
{
// The current block has been filtered. So when order is imposed in confirm
// this can be checked in the case of bump events (maybe not validated).
return !filter_enabled() || store_.filter_tx.exists(to_filter_tx(link));
}

TEMPLATE
bool CLASS::set_filter_head(const header_link& link) NOEXCEPT
{
Expand All @@ -240,13 +300,14 @@ bool CLASS::set_filter_head(const header_link& link) NOEXCEPT
if (!get_filter_head(previous, parent))
return false;

// Use the previous head and current body to compute the current head.
return set_filter_head(link, compute_filter_header(previous, body));
// Use previous head and current body to compute current hash and head.
hash_digest hash{};
return set_filter_head(link, compute_header(hash, previous, body), hash);
}

TEMPLATE
bool CLASS::set_filter_head(const header_link& link,
const hash_digest& head) NOEXCEPT
bool CLASS::set_filter_head(const header_link& link, const hash_digest& head,
const hash_digest& hash) NOEXCEPT
{
if (!filter_enabled())
return true;
Expand All @@ -258,6 +319,7 @@ bool CLASS::set_filter_head(const header_link& link,
return store_.filter_bk.put(to_filter_bk(link), table::filter_bk::put_ref
{
{},
hash,
head
});
// ========================================================================
Expand Down
17 changes: 13 additions & 4 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ class query
hashes get_blocks(const hashes& locator, const hash_digest& stop,
size_t limit) const NOEXCEPT;

/// Get descending list of ancestry starting with descendant (inclusive).
bool get_ancestry(header_links& ancestry, const header_link& descendant,
size_t count) const NOEXCEPT;

/// Optional Tables.
/// -----------------------------------------------------------------------

Expand All @@ -563,14 +567,19 @@ class query
bool get_confirmed_balance(uint64_t& out,
const hash_digest& key) const NOEXCEPT;

bool is_filtered(const header_link& link) const NOEXCEPT;
bool is_filtered_body(const header_link& link) const NOEXCEPT;
bool get_filter_body(filter& out, const header_link& link) const NOEXCEPT;
bool get_filter_head(hash_digest& out, const header_link& link) const NOEXCEPT;
bool set_filter_body(const header_link& link, const block& block) NOEXCEPT;
bool set_filter_body(const header_link& link, const filter& body) NOEXCEPT;

bool is_filtered_head(const header_link& link) const NOEXCEPT;
bool get_filter_head(hash_digest& out, const header_link& link) const NOEXCEPT;
bool get_filter_hash(hash_digest& out, const header_link& link) const NOEXCEPT;
bool get_filter_hashes(hashes& filter_hashes, hash_digest& previous_header,
const header_link& stop_link, size_t count) const NOEXCEPT;
bool set_filter_head(const header_link& link) NOEXCEPT;
bool set_filter_head(const header_link& link,
const hash_digest& head) NOEXCEPT;
bool set_filter_head(const header_link& link, const hash_digest& head,
const hash_digest& hash) NOEXCEPT;

protected:
struct span
Expand Down
29 changes: 29 additions & 0 deletions include/bitcoin/database/tables/optionals/filter_bk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,52 @@ struct filter_bk
{
inline bool from_data(reader& source) NOEXCEPT
{
hash = source.read_hash();
head = source.read_hash();
return source;
}

hash_digest hash{};
hash_digest head{};
};

struct get_head_only
: public schema::filter_bk
{
inline bool from_data(reader& source) NOEXCEPT
{
source.skip_bytes(system::hash_size);
head = source.read_hash();
return source;
}

hash_digest head{};
};

struct get_hash_only
: public schema::filter_bk
{
inline bool from_data(reader& source) NOEXCEPT
{
hash = source.read_hash();
return source;
}

hash_digest hash{};
};

struct put_ref
: public schema::filter_bk
{
inline bool to_data(finalizer& sink) const NOEXCEPT
{
sink.write_bytes(hash);
sink.write_bytes(head);
BC_ASSERT(!sink || sink.get_write_position() == count() * minrow);
return sink;
}

const hash_digest& hash{};
const hash_digest& head{};
};
};
Expand Down
5 changes: 3 additions & 2 deletions include/bitcoin/database/tables/schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,12 +363,13 @@ struct filter_bk
static constexpr size_t pk = schema::header::pk;
using link = linkage<pk, to_bits(pk)>;
static constexpr size_t minsize =
schema::hash +
schema::hash;
static constexpr size_t minrow = minsize;
static constexpr size_t size = minsize;
static constexpr link count() NOEXCEPT { return 1; }
static_assert(minsize == 32u);
static_assert(minrow == 32u);
static_assert(minsize == 64u);
static_assert(minrow == 64u);
static_assert(link::size == 3u);
};

Expand Down
Loading
Loading