Skip to content

Commit 7d9dade

Browse files
committed
Replace static merkle_branch() with block computation.
1 parent f390620 commit 7d9dade

3 files changed

Lines changed: 180 additions & 1 deletion

File tree

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,37 @@ namespace database {
3131
// merkle
3232
// ----------------------------------------------------------------------------
3333

34+
// static/protected
35+
TEMPLATE
36+
CLASS::positions CLASS::merkle_branch(size_t leaf, size_t leaves,
37+
bool compress) NOEXCEPT
38+
{
39+
using namespace system;
40+
BC_ASSERT(leaves <= power2(sub1(bits<size_t>)));
41+
BC_ASSERT(is_even(leaves) || is_one(leaves));
42+
43+
positions branch{};
44+
if (is_zero(leaves) || leaf >= leaves)
45+
return branch;
46+
47+
// Upper bound, actual count may be less given compression.
48+
branch.reserve(ceilinged_log2(leaves));
49+
50+
for (auto width = one, current = leaves; current > one;)
51+
{
52+
const auto sibling = bit_xor(leaf, one);
53+
if (!compress || sibling < current)
54+
branch.emplace_back(sibling, width);
55+
56+
++current;
57+
shift_left_into(width);
58+
shift_right_into(leaf);
59+
shift_right_into(current);
60+
}
61+
62+
return branch;
63+
}
64+
3465
// protected
3566
TEMPLATE
3667
CLASS::hash_option CLASS::create_interval(header_link link,
@@ -87,7 +118,7 @@ void CLASS::merge_merkle(hashes& path, hashes&& leaves, size_t first,
87118
++size;
88119
}
89120

90-
for (const auto& row: block::merkle_branch(first, size + lift))
121+
for (const auto& row: merkle_branch(first, size + lift))
91122
{
92123
hashes subroot{};
93124
if (const auto leaf = row.sibling * row.width; leaf < size)

include/bitcoin/database/query.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,11 +768,15 @@ class query
768768

769769
/// merkle
770770
/// -----------------------------------------------------------------------
771+
struct position { size_t sibling; size_t width; };
772+
using positions = std::vector<position>;
771773

772774
// merkle related utilities
773775
static hash_digest partial_subroot(hashes&& tree, size_t span) NOEXCEPT;
774776
static void merge_merkle(hashes& path, hashes&& leaves, size_t first,
775777
size_t lift) NOEXCEPT;
778+
static positions merkle_branch(size_t leaf, size_t leaves,
779+
bool compress=false) NOEXCEPT;
776780

777781
// merkle related configuration
778782
size_t interval_depth() const NOEXCEPT;

test/query/merkle.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ class merkle_accessor
5959
{
6060
public:
6161
using base = test::query_accessor;
62+
using positions = base::positions;
6263
using base::base;
64+
using base::merkle_branch;
6365
using base::interval_span;
6466
using base::create_interval;
6567
using base::get_confirmed_interval;
@@ -69,6 +71,148 @@ class merkle_accessor
6971
using base::get_merkle_root_and_proof;
7072
};
7173

74+
// merkle_branch
75+
76+
BOOST_AUTO_TEST_CASE(query_merkle___merkle_branch__leaf_zero__empty)
77+
{
78+
BOOST_REQUIRE(merkle_accessor::merkle_branch(0, 0, true).empty());
79+
BOOST_REQUIRE(merkle_accessor::merkle_branch(0, 0, false).empty());
80+
}
81+
82+
BOOST_AUTO_TEST_CASE(query_merkle___merkle_branch__one__zero)
83+
{
84+
auto branch = merkle_accessor::merkle_branch(1, 2, true);
85+
BOOST_REQUIRE_EQUAL(branch.size(), 1u);
86+
BOOST_REQUIRE_EQUAL(branch[0].sibling, 0u);
87+
BOOST_REQUIRE_EQUAL(branch[0].width, 1u);
88+
89+
branch = merkle_accessor::merkle_branch(1, 2, false);
90+
BOOST_REQUIRE_EQUAL(branch.size(), 1u);
91+
BOOST_REQUIRE_EQUAL(branch[0].sibling, 0u);
92+
BOOST_REQUIRE_EQUAL(branch[0].width, 1u);
93+
}
94+
95+
BOOST_AUTO_TEST_CASE(query_merkle___merkle_branch__three__two_and_zero)
96+
{
97+
auto branch = merkle_accessor::merkle_branch(3, 4, true);
98+
BOOST_REQUIRE_EQUAL(branch.size(), 2u);
99+
BOOST_REQUIRE_EQUAL(branch[0].sibling, 2u);
100+
BOOST_REQUIRE_EQUAL(branch[0].width, 1u);
101+
BOOST_REQUIRE_EQUAL(branch[1].sibling, 0u);
102+
BOOST_REQUIRE_EQUAL(branch[1].width, 2u);
103+
104+
branch = merkle_accessor::merkle_branch(3, 4, false);
105+
BOOST_REQUIRE_EQUAL(branch.size(), 2u);
106+
BOOST_REQUIRE_EQUAL(branch[0].sibling, 2u);
107+
BOOST_REQUIRE_EQUAL(branch[0].width, 1u);
108+
BOOST_REQUIRE_EQUAL(branch[1].sibling, 0u);
109+
BOOST_REQUIRE_EQUAL(branch[1].width, 2u);
110+
}
111+
112+
BOOST_AUTO_TEST_CASE(query_merkle___merkle_branch__seven__six_four_and_zero)
113+
{
114+
auto branch = merkle_accessor::merkle_branch(7, 8, true);
115+
BOOST_REQUIRE_EQUAL(branch.size(), 3u);
116+
BOOST_REQUIRE_EQUAL(branch[0].sibling, 6u);
117+
BOOST_REQUIRE_EQUAL(branch[0].width, 1u);
118+
BOOST_REQUIRE_EQUAL(branch[1].sibling, 2u);
119+
BOOST_REQUIRE_EQUAL(branch[1].width, 2u);
120+
BOOST_REQUIRE_EQUAL(branch[2].sibling, 0u);
121+
BOOST_REQUIRE_EQUAL(branch[2].width, 4u);
122+
123+
branch = merkle_accessor::merkle_branch(7, 8, false);
124+
BOOST_REQUIRE_EQUAL(branch.size(), 3u);
125+
BOOST_REQUIRE_EQUAL(branch[0].sibling, 6u);
126+
BOOST_REQUIRE_EQUAL(branch[0].width, 1u);
127+
BOOST_REQUIRE_EQUAL(branch[1].sibling, 2u);
128+
BOOST_REQUIRE_EQUAL(branch[1].width, 2u);
129+
BOOST_REQUIRE_EQUAL(branch[2].sibling, 0u);
130+
BOOST_REQUIRE_EQUAL(branch[2].width, 4u);
131+
}
132+
133+
BOOST_AUTO_TEST_CASE(block__merkle_branch__medium_power_of_two__expected)
134+
{
135+
const merkle_accessor::positions expected{ { 14, 1 }, { 6, 2 }, { 2, 4 }, { 0, 8 } };
136+
137+
auto branch = merkle_accessor::merkle_branch(15, 16, true);
138+
BOOST_REQUIRE_EQUAL(branch.size(), 4u);
139+
BOOST_REQUIRE_EQUAL(branch[0].sibling, 14u);
140+
BOOST_REQUIRE_EQUAL(branch[0].width, 1u);
141+
BOOST_REQUIRE_EQUAL(branch[1].sibling, 6u);
142+
BOOST_REQUIRE_EQUAL(branch[1].width, 2u);
143+
BOOST_REQUIRE_EQUAL(branch[2].sibling, 2u);
144+
BOOST_REQUIRE_EQUAL(branch[2].width, 4u);
145+
BOOST_REQUIRE_EQUAL(branch[3].sibling, 0u);
146+
BOOST_REQUIRE_EQUAL(branch[3].width, 8u);
147+
148+
branch = merkle_accessor::merkle_branch(15, 16, false);
149+
BOOST_REQUIRE_EQUAL(branch.size(), 4u);
150+
BOOST_REQUIRE_EQUAL(branch[0].sibling, 14u);
151+
BOOST_REQUIRE_EQUAL(branch[0].width, 1u);
152+
BOOST_REQUIRE_EQUAL(branch[1].sibling, 6u);
153+
BOOST_REQUIRE_EQUAL(branch[1].width, 2u);
154+
BOOST_REQUIRE_EQUAL(branch[2].sibling, 2u);
155+
BOOST_REQUIRE_EQUAL(branch[2].width, 4u);
156+
BOOST_REQUIRE_EQUAL(branch[3].sibling, 0u);
157+
BOOST_REQUIRE_EQUAL(branch[3].width, 8u);
158+
}
159+
160+
BOOST_AUTO_TEST_CASE(block__merkle_branch__power_of_two_minus_one__expected)
161+
{
162+
constexpr auto leaf = 1023u;
163+
constexpr auto size = system::ceilinged_log2(add1(leaf));
164+
auto branch = merkle_accessor::merkle_branch(leaf, add1(leaf), true);
165+
BOOST_REQUIRE_EQUAL(branch.size(), size);
166+
BOOST_REQUIRE_EQUAL(branch.front().sibling, 1022u);
167+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
168+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
169+
BOOST_REQUIRE_EQUAL(branch.back().width, system::power2(sub1(size)));
170+
171+
branch = merkle_accessor::merkle_branch(leaf, add1(leaf), false);
172+
BOOST_REQUIRE_EQUAL(branch.size(), size);
173+
BOOST_REQUIRE_EQUAL(branch.front().sibling, 1022u);
174+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
175+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
176+
BOOST_REQUIRE_EQUAL(branch.back().width, system::power2(sub1(size)));
177+
}
178+
179+
BOOST_AUTO_TEST_CASE(block__merkle_branch__odd_large_leaf_with_duplication__expected)
180+
{
181+
constexpr auto leaf = 2047u;
182+
constexpr auto size = system::ceilinged_log2(add1(leaf));
183+
auto branch = merkle_accessor::merkle_branch(leaf, add1(leaf), true);
184+
BOOST_REQUIRE_EQUAL(branch.size(), size);
185+
BOOST_REQUIRE_EQUAL(branch.front().sibling, 2046u);
186+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
187+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
188+
BOOST_REQUIRE_EQUAL(branch.back().width, system::power2(sub1(size)));
189+
190+
branch = merkle_accessor::merkle_branch(leaf, add1(leaf), false);
191+
BOOST_REQUIRE_EQUAL(branch.size(), size);
192+
BOOST_REQUIRE_EQUAL(branch.front().sibling, 2046u);
193+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
194+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
195+
BOOST_REQUIRE_EQUAL(branch.back().width, system::power2(sub1(size)));
196+
}
197+
198+
BOOST_AUTO_TEST_CASE(block__merkle_branch__maximum_non_overflow__expected)
199+
{
200+
constexpr auto maximum = sub1(system::power2(sub1(bits<size_t>)));
201+
auto branch = merkle_accessor::merkle_branch(maximum, add1(maximum), true);
202+
BOOST_REQUIRE_EQUAL(branch.size(), sub1(bits<size_t>));
203+
BOOST_REQUIRE_EQUAL(branch.front().sibling, sub1(maximum));
204+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
205+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
206+
BOOST_REQUIRE_EQUAL(branch.back().width, system::power2(sub1(sub1(bits<size_t>))));
207+
208+
branch = merkle_accessor::merkle_branch(maximum, add1(maximum), false);
209+
BOOST_REQUIRE_EQUAL(branch.size(), sub1(bits<size_t>));
210+
BOOST_REQUIRE_EQUAL(branch.front().sibling, sub1(maximum));
211+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
212+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
213+
BOOST_REQUIRE_EQUAL(branch.back().width, system::power2(sub1(sub1(bits<size_t>))));
214+
}
215+
72216
// interval_span
73217

74218
BOOST_AUTO_TEST_CASE(query_merkle__interval_span__uninitialized__max_size_t)

0 commit comments

Comments
 (0)