Skip to content

Commit d603c29

Browse files
authored
Merge pull request #713 from evoskuil/master
Test all new merkle proof methods.
2 parents bcfc180 + ac1dced commit d603c29

File tree

7 files changed

+486
-38
lines changed

7 files changed

+486
-38
lines changed

include/bitcoin/database/impl/query/height.ipp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,12 @@ hashes CLASS::get_confirmed_hashes(size_t first, size_t count) const NOEXCEPT
215215
{
216216
using namespace system;
217217
const auto size = is_odd(count) && count > one ? add1(count) : count;
218-
if (is_add_overflow(count, one) || is_add_overflow(first, size))
218+
if (is_zero(count) ||
219+
is_add_overflow(count, one) ||
220+
is_add_overflow(first, size))
219221
return {};
220222

221-
auto link = to_confirmed(first + count);
223+
auto link = to_confirmed(first + sub1(count));
222224
if (link.is_terminal())
223225
return {};
224226

@@ -238,10 +240,10 @@ hashes CLASS::get_confirmed_hashes(size_t first, size_t count) const NOEXCEPT
238240

239241
TEMPLATE
240242
header_links CLASS::get_confirmed_headers(size_t first,
241-
size_t maximum) const NOEXCEPT
243+
size_t limit) const NOEXCEPT
242244
{
243245
// Empty is always a successful/valid result for this method.
244-
if (is_zero(maximum))
246+
if (is_zero(limit))
245247
return {};
246248

247249
// First requested height is currently above top.
@@ -250,8 +252,8 @@ header_links CLASS::get_confirmed_headers(size_t first,
250252
return {};
251253

252254
// add1(top) cannot overflow, as indexed block maximum cannot exceed size_t.
253-
maximum = system::limit(maximum, add1(top) - first);
254-
auto last = first + sub1(maximum);
255+
limit = std::min(limit, add1(top) - first);
256+
auto last = first + sub1(limit);
255257

256258
// Due to reorganization it is possible for this height to now be terminal.
257259
auto link = to_confirmed(last);

include/bitcoin/database/impl/query/optional.ipp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,9 @@ CLASS::hash_option CLASS::get_confirmed_interval(size_t height) const NOEXCEPT
316316
return txs.interval;
317317
}
318318

319-
// protected
319+
// static/protected
320320
TEMPLATE
321-
void CLASS::push_merkle(hashes& to, hashes&& from, size_t first) const NOEXCEPT
321+
void CLASS::merge_merkle(hashes& to, hashes&& from, size_t first) NOEXCEPT
322322
{
323323
using namespace system;
324324
for (const auto& row: block::merkle_branch(first, from.size()))
@@ -346,8 +346,8 @@ code CLASS::get_merkle_proof(hashes& proof, hashes roots, size_t target,
346346

347347
using namespace system;
348348
proof.reserve(ceilinged_log2(other.size()) + ceilinged_log2(roots.size()));
349-
push_merkle(proof, std::move(other), target % span);
350-
push_merkle(proof, std::move(roots), target / span);
349+
merge_merkle(proof, std::move(other), target % span);
350+
merge_merkle(proof, std::move(roots), target / span);
351351
return error::success;
352352
}
353353

@@ -367,7 +367,7 @@ code CLASS::get_merkle_tree(hashes& tree, size_t waypoint) const NOEXCEPT
367367

368368
if (size == span)
369369
{
370-
auto interval = get_confirmed_interval(first);
370+
auto interval = get_confirmed_interval(last);
371371
if (!interval.has_value()) return error::merkle_interval;
372372
tree.push_back(std::move(interval.value()));
373373
}

include/bitcoin/database/query.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ class query
539539
hashes get_confirmed_hashes(const heights& heights) const NOEXCEPT;
540540
hashes get_confirmed_hashes(size_t first, size_t count) const NOEXCEPT;
541541
header_links get_confirmed_headers(size_t first,
542-
size_t maximum) const NOEXCEPT;
542+
size_t limit) const NOEXCEPT;
543543

544544
header_links get_confirmed_fork(const header_link& fork) const NOEXCEPT;
545545
header_links get_candidate_fork(size_t& fork_point) const NOEXCEPT;
@@ -720,10 +720,12 @@ class query
720720

721721
/// merkle
722722
/// -----------------------------------------------------------------------
723+
static void merge_merkle(hashes& branch, hashes&& hashes,
724+
size_t first) NOEXCEPT;
725+
723726
size_t interval_span() const NOEXCEPT;
724727
hash_option get_confirmed_interval(size_t height) const NOEXCEPT;
725728
hash_option create_interval(header_link link, size_t height) const NOEXCEPT;
726-
void push_merkle(hashes& branch, hashes&& hashes, size_t first) const NOEXCEPT;
727729
code get_merkle_tree(hashes& roots, size_t waypoint) const NOEXCEPT;
728730
code get_merkle_proof(hashes& proof, hashes roots, size_t target,
729731
size_t waypoint) const NOEXCEPT;

include/bitcoin/database/settings.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ struct BCD_API settings
4040
/// -----------------------------------------------------------------------
4141

4242
/// Enable concurrency in individual client-server queries.
43-
bool turbo;
43+
bool turbo{ false };
4444

4545
/// Depth of electrum merkle tree interval caching.
46-
uint8_t interval_depth;
46+
uint8_t interval_depth{ max_uint8 };
4747

4848
/// Path to the database directory.
49-
std::filesystem::path path;
49+
std::filesystem::path path{ "bitcoin" };
5050

5151
/// Archives.
5252
/// -----------------------------------------------------------------------

src/settings.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ namespace database {
2727
using namespace bc::system;
2828

2929
settings::settings() NOEXCEPT
30-
: turbo{ false },
31-
interval_depth{ max_uint8 },
32-
path{ "bitcoin" },
33-
30+
:
3431
// Archives.
3532

3633
header_buckets{ 128 },

test/query/height.cpp

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,20 @@ BOOST_AUTO_TEST_CASE(query_height__get_confirmed_hashes2__various__expected_size
112112
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(0, 1).size(), 1u);
113113
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(0, 2).size(), 2u);
114114
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(0, 3).size(), 3u);
115-
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(0, 4).size(), 0u);
115+
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(0, 4).size(), 4u);
116+
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(0, 5).size(), 0u);
116117
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(1, 0).size(), 0u);
117118
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(1, 1).size(), 1u);
118119
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(1, 2).size(), 2u);
119-
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(1, 3).size(), 0u);
120+
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(1, 3).size(), 3u);
121+
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(1, 4).size(), 0u);
120122
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(2, 0).size(), 0u);
121123
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(2, 1).size(), 1u);
122-
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(2, 2).size(), 0u);
124+
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(2, 2).size(), 2u);
125+
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(2, 3).size(), 0u);
123126
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(3, 0).size(), 0u);
124-
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(3, 1).size(), 0u);
127+
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(3, 1).size(), 1u);
128+
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(3, 2).size(), 0u);
125129
BOOST_REQUIRE_EQUAL(query.get_confirmed_hashes(4, 0).size(), 0u);
126130
}
127131

@@ -142,9 +146,97 @@ BOOST_AUTO_TEST_CASE(query_height__get_confirmed_hashes2__three__ascending_order
142146

143147
const auto hashes = query.get_confirmed_hashes(0, 3);
144148
BOOST_REQUIRE_EQUAL(hashes.size(), 3);
145-
BOOST_REQUIRE_EQUAL(hashes[0], test::block1.hash());
146-
BOOST_REQUIRE_EQUAL(hashes[1], test::block2.hash());
147-
BOOST_REQUIRE_EQUAL(hashes[2], test::block3.hash());
149+
BOOST_REQUIRE_EQUAL(hashes[0], test::genesis.hash());
150+
BOOST_REQUIRE_EQUAL(hashes[1], test::block1.hash());
151+
BOOST_REQUIRE_EQUAL(hashes[2], test::block2.hash());
152+
}
153+
154+
// get_confirmed_headers
155+
156+
BOOST_AUTO_TEST_CASE(query_height__get_confirmed_headers__empty__empty)
157+
{
158+
settings settings{};
159+
settings.path = TEST_DIRECTORY;
160+
test::chunk_store store{ settings };
161+
test::query_accessor query{ store };
162+
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
163+
BOOST_REQUIRE(query.initialize(test::genesis));
164+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(0, 0).size(), 0u);
165+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(0, 42).size(), 1u);
166+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(42, 0).size(), 0u);
167+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(42, 42).size(), 0u);
168+
}
169+
170+
BOOST_AUTO_TEST_CASE(query_height__get_confirmed_headers__unconfirmeds__empty)
171+
{
172+
settings settings{};
173+
settings.path = TEST_DIRECTORY;
174+
test::chunk_store store{ settings };
175+
test::query_accessor query{ store };
176+
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
177+
BOOST_REQUIRE(query.initialize(test::genesis));
178+
BOOST_REQUIRE(query.set(test::block1, test::context, false, false));
179+
BOOST_REQUIRE(query.set(test::block2, test::context, false, false));
180+
BOOST_REQUIRE(query.set(test::block3, test::context, false, false));
181+
BOOST_REQUIRE(query.push_candidate(query.to_header(test::block1.hash())));
182+
BOOST_REQUIRE(query.push_candidate(query.to_header(test::block2.hash())));
183+
BOOST_REQUIRE(query.push_candidate(query.to_header(test::block3.hash())));
184+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(0, 0).size(), 0u);
185+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(0, 42).size(), 1u);
186+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(42, 0).size(), 0u);
187+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(42, 42).size(), 0u);
188+
}
189+
190+
BOOST_AUTO_TEST_CASE(query_height__get_confirmed_headers__confirmeds__expected_size)
191+
{
192+
settings settings{};
193+
settings.path = TEST_DIRECTORY;
194+
test::chunk_store store{ settings };
195+
test::query_accessor query{ store };
196+
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
197+
BOOST_REQUIRE(query.initialize(test::genesis));
198+
BOOST_REQUIRE(query.set(test::block1, test::context, false, false));
199+
BOOST_REQUIRE(query.set(test::block2, test::context, false, false));
200+
BOOST_REQUIRE(query.set(test::block3, test::context, false, false));
201+
BOOST_REQUIRE(query.push_confirmed(query.to_header(test::block1.hash()), false));
202+
BOOST_REQUIRE(query.push_confirmed(query.to_header(test::block2.hash()), false));
203+
BOOST_REQUIRE(query.push_candidate(query.to_header(test::block3.hash())));
204+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(0, 0).size(), 0u);
205+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(0, 1).size(), 1u);
206+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(0, 2).size(), 2u);
207+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(0, 3).size(), 3u);
208+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(1, 0).size(), 0u);
209+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(1, 1).size(), 1u);
210+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(1, 2).size(), 2u);
211+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(1, 3).size(), 2u);
212+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(2, 0).size(), 0u);
213+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(2, 1).size(), 1u);
214+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(2, 2).size(), 1u);
215+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(3, 0).size(), 0u);
216+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(3, 1).size(), 0u);
217+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(4, 0).size(), 0u);
218+
BOOST_REQUIRE_EQUAL(query.get_confirmed_headers(4, 1).size(), 0u);
219+
}
220+
221+
BOOST_AUTO_TEST_CASE(query_height__get_confirmed_headers__confirmeds__expected_headers)
222+
{
223+
settings settings{};
224+
settings.path = TEST_DIRECTORY;
225+
test::chunk_store store{ settings };
226+
test::query_accessor query{ store };
227+
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
228+
BOOST_REQUIRE(query.initialize(test::genesis));
229+
BOOST_REQUIRE(query.set(test::block1, test::context, false, false));
230+
BOOST_REQUIRE(query.set(test::block2, test::context, false, false));
231+
BOOST_REQUIRE(query.set(test::block3, test::context, false, false));
232+
BOOST_REQUIRE(query.push_confirmed(query.to_header(test::block1.hash()), false));
233+
BOOST_REQUIRE(query.push_confirmed(query.to_header(test::block2.hash()), false));
234+
BOOST_REQUIRE(query.push_candidate(query.to_header(test::block3.hash())));
235+
236+
const auto headers = query.get_confirmed_headers(1, 3);
237+
BOOST_REQUIRE_EQUAL(headers.size(), 2u);
238+
BOOST_REQUIRE_EQUAL(query.get_header_key(headers[0]), test::block1.hash());
239+
BOOST_REQUIRE_EQUAL(query.get_header_key(headers[1]), test::block2.hash());
148240
}
149241

150242
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)