|
19 | 19 | #ifndef LIBBITCOIN_DATABASE_QUERY_HEIGHT_IPP |
20 | 20 | #define LIBBITCOIN_DATABASE_QUERY_HEIGHT_IPP |
21 | 21 |
|
| 22 | +#include <algorithm> |
22 | 23 | #include <bitcoin/system.hpp> |
23 | 24 | #include <bitcoin/database/define.hpp> |
24 | 25 |
|
@@ -59,6 +60,98 @@ size_t CLASS::get_confirmed_size(size_t top) const NOEXCEPT |
59 | 60 | return wire; |
60 | 61 | } |
61 | 62 |
|
| 63 | +// locator readers |
| 64 | +// ---------------------------------------------------------------------------- |
| 65 | +// These do not require strict consistency. |
| 66 | + |
| 67 | +TEMPLATE |
| 68 | +CLASS::headers CLASS::get_headers(const hashes& locator, |
| 69 | + const hash_digest& stop, size_t limit) const NOEXCEPT |
| 70 | +{ |
| 71 | + headers out{}; |
| 72 | + const auto span = get_locator_span(locator, stop, limit); |
| 73 | + out.reserve(span.size()); |
| 74 | + |
| 75 | + for (auto height = span.begin; height < span.end; ++height) |
| 76 | + { |
| 77 | + // Terminal implies intervening reorganization. |
| 78 | + const auto link = to_confirmed(height); |
| 79 | + if (link.is_terminal()) |
| 80 | + return {}; |
| 81 | + |
| 82 | + out.push_back(get_header(link)); |
| 83 | + BC_ASSERT(!is_null(out.back())); |
| 84 | + } |
| 85 | + |
| 86 | + return out; |
| 87 | +} |
| 88 | + |
| 89 | +TEMPLATE |
| 90 | +hashes CLASS::get_blocks(const hashes& locator, |
| 91 | + const hash_digest& stop, size_t limit) const NOEXCEPT |
| 92 | +{ |
| 93 | + hashes out{}; |
| 94 | + const auto span = get_locator_span(locator, stop, limit); |
| 95 | + out.reserve(span.size()); |
| 96 | + |
| 97 | + for (auto height = span.begin; height < span.end; ++height) |
| 98 | + { |
| 99 | + // Terminal implies intervening reorganization. |
| 100 | + const auto link = to_confirmed(height); |
| 101 | + if (link.is_terminal()) |
| 102 | + return {}; |
| 103 | + |
| 104 | + out.push_back(get_header_key(link)); |
| 105 | + BC_ASSERT(out.back() != system::null_hash); |
| 106 | + } |
| 107 | + |
| 108 | + return out; |
| 109 | +} |
| 110 | + |
| 111 | +TEMPLATE |
| 112 | +CLASS::span CLASS::get_locator_span(const hashes& locator, |
| 113 | + const hash_digest& stop, size_t limit) const NOEXCEPT |
| 114 | +{ |
| 115 | + using namespace system; |
| 116 | + span out{}; |
| 117 | + |
| 118 | + // Start at fork point, stop at given header (both excluded). |
| 119 | + const auto start = add1(get_fork(locator)); |
| 120 | + const auto last1 = (stop == null_hash) ? max_uint32 : |
| 121 | + get_height(to_header(stop)).value; |
| 122 | + |
| 123 | + // Determine number of headers requested, limited by max allowed. |
| 124 | + const auto request = floored_subtract<size_t>(last1, start); |
| 125 | + const auto allowed = std::min(request, limit); |
| 126 | + |
| 127 | + // Set end to (start + allowed), limited by (top + 1). |
| 128 | + const auto top1 = ceilinged_add(get_top_confirmed(), one); |
| 129 | + const auto end = std::min(ceilinged_add(start, allowed), top1); |
| 130 | + |
| 131 | + // Convert negative range to empty. |
| 132 | + out.end = std::max(start, end); |
| 133 | + return out; |
| 134 | +} |
| 135 | + |
| 136 | +// protected |
| 137 | +TEMPLATE |
| 138 | +size_t CLASS::get_fork(const hashes& locator) const NOEXCEPT |
| 139 | +{ |
| 140 | + // Locator is presumed (by convention) to be in order by height. |
| 141 | + for (const auto& hash: locator) |
| 142 | + { |
| 143 | + const auto link = to_header(hash); |
| 144 | + const auto height = get_height(link); |
| 145 | + |
| 146 | + table::height::record confirmed{}; |
| 147 | + if (store_.confirmed.get(height, confirmed) && |
| 148 | + confirmed.header_fk == link) |
| 149 | + return height; |
| 150 | + } |
| 151 | + |
| 152 | + return zero; |
| 153 | +} |
| 154 | + |
62 | 155 | // shared_lock readers |
63 | 156 | // ---------------------------------------------------------------------------- |
64 | 157 | // Protected against index pop (low contention) to ensure branch consistency. |
|
0 commit comments