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
93 changes: 93 additions & 0 deletions include/bitcoin/database/impl/query/height.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifndef LIBBITCOIN_DATABASE_QUERY_HEIGHT_IPP
#define LIBBITCOIN_DATABASE_QUERY_HEIGHT_IPP

#include <algorithm>
#include <bitcoin/system.hpp>
#include <bitcoin/database/define.hpp>

Expand Down Expand Up @@ -59,6 +60,98 @@ size_t CLASS::get_confirmed_size(size_t top) const NOEXCEPT
return wire;
}

// locator readers
// ----------------------------------------------------------------------------
// These do not require strict consistency.

TEMPLATE
CLASS::headers CLASS::get_headers(const hashes& locator,
const hash_digest& stop, size_t limit) const NOEXCEPT
{
headers out{};
const auto span = get_locator_span(locator, stop, limit);
out.reserve(span.size());

for (auto height = span.begin; height < span.end; ++height)
{
// Terminal implies intervening reorganization.
const auto link = to_confirmed(height);
if (link.is_terminal())
return {};

out.push_back(get_header(link));
BC_ASSERT(!is_null(out.back()));
}

return out;
}

TEMPLATE
hashes CLASS::get_blocks(const hashes& locator,
const hash_digest& stop, size_t limit) const NOEXCEPT
{
hashes out{};
const auto span = get_locator_span(locator, stop, limit);
out.reserve(span.size());

for (auto height = span.begin; height < span.end; ++height)
{
// Terminal implies intervening reorganization.
const auto link = to_confirmed(height);
if (link.is_terminal())
return {};

out.push_back(get_header_key(link));
BC_ASSERT(out.back() != system::null_hash);
}

return out;
}

TEMPLATE
CLASS::span CLASS::get_locator_span(const hashes& locator,
const hash_digest& stop, size_t limit) const NOEXCEPT
{
using namespace system;
span out{};

// Start at fork point, stop at given header (both excluded).
const auto start = add1(get_fork(locator));
const auto last1 = (stop == null_hash) ? max_uint32 :
get_height(to_header(stop)).value;

// Determine number of headers requested, limited by max allowed.
const auto request = floored_subtract<size_t>(last1, start);
const auto allowed = std::min(request, limit);

// Set end to (start + allowed), limited by (top + 1).
const auto top1 = ceilinged_add(get_top_confirmed(), one);
const auto end = std::min(ceilinged_add(start, allowed), top1);

// Convert negative range to empty.
out.end = std::max(start, end);
return out;
}

// protected
TEMPLATE
size_t CLASS::get_fork(const hashes& locator) const NOEXCEPT
{
// Locator is presumed (by convention) to be in order by height.
for (const auto& hash: locator)
{
const auto link = to_header(hash);
const auto height = get_height(link);

table::height::record confirmed{};
if (store_.confirmed.get(height, confirmed) &&
confirmed.header_fk == link)
return height;
}

return zero;
}

// shared_lock readers
// ----------------------------------------------------------------------------
// Protected against index pop (low contention) to ensure branch consistency.
Expand Down
24 changes: 24 additions & 0 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class query
using script = system::chain::script;
using output = system::chain::output;
using header = system::chain::header;
using headers = system::chain::header_cptrs;
using transaction = system::chain::transaction;
using transactions = system::chain::transaction_cptrs;
using inputs_ptr = system::chain::inputs_ptr;
Expand Down Expand Up @@ -534,6 +535,12 @@ class query
bool pop_candidate() NOEXCEPT;
bool pop_confirmed() NOEXCEPT;

/// Populate message payloads from locator.
headers get_headers(const hashes& locator, const hash_digest& stop,
size_t limit) const NOEXCEPT;
hashes get_blocks(const hashes& locator, const hash_digest& stop,
size_t limit) const NOEXCEPT;

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

Expand All @@ -557,6 +564,23 @@ class query
const hash_digest& head) NOEXCEPT;

protected:
struct span
{
size_t size() const NOEXCEPT { return end - begin; }
size_t begin;
size_t end;
};

/// Network
/// -----------------------------------------------------------------------

/// Height of highest confirmed block (assumes locator descending).
size_t get_fork(const hashes& locator) const NOEXCEPT;

/// Height of highest confirmed block (assumes locator descending).
span get_locator_span(const hashes& locator, const hash_digest& stop,
size_t limit) const NOEXCEPT;

/// Translate.
/// -----------------------------------------------------------------------
uint32_t to_input_index(const tx_link& parent_fk,
Expand Down
4 changes: 2 additions & 2 deletions test/query/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(query_context__get_candidate_chain_state__genesis__expected
test::genesis.header().timestamp(),
0u,
0u,
1u,
0u,
0u
};

Expand Down Expand Up @@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(query_context__get_candidate_chain_state__block1__expected)
test::block1.header().timestamp(), // timestamp
test::genesis.header().timestamp(), // mtp
1u, // height
1u, // minimum_block_version
0u, // minimum_block_version
486604799u // work_required
};

Expand Down
Loading