Skip to content

Commit ebdf6f5

Browse files
committed
Fix get_merkle_subroots and get_merkle_root queries.
1 parent 20ee666 commit ebdf6f5

4 files changed

Lines changed: 428 additions & 48 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ TEMPLATE
225225
hashes CLASS::get_confirmed_hashes(size_t first, size_t count) const NOEXCEPT
226226
{
227227
using namespace system;
228-
const auto size = is_odd(count) && count > one ? add1(count) : count;
228+
const auto size = count + to_int<size_t>(!is_one(count) && is_odd(count));
229229
if (is_zero(count) ||
230230
is_add_overflow(count, one) ||
231231
is_add_overflow(first, size))

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

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -114,37 +114,45 @@ code CLASS::get_merkle_proof(hashes& proof, hashes roots, size_t target,
114114

115115
// static/private
116116
TEMPLATE
117-
hash_digest CLASS::merkle_subroot(hashes&& tree, size_t span) NOEXCEPT
117+
hash_digest CLASS::partial_subroot(hashes&& tree, size_t span) NOEXCEPT
118118
{
119-
using namespace system;
120-
121-
// Tree cannot be empty or exceed span (span is power of two).
119+
// Tree cannot be empty or exceed span (a power of 2).
122120
if (tree.empty() || tree.size() > span)
123121
return {};
124122

125-
// zero depth implies single tree element, which is the root.
123+
using namespace system;
126124
const auto depth = ceilinged_log2(span);
125+
////std::cout << "depth : " << depth << std::endl;
126+
127+
// Zero depth implies single tree element, which is the root.
127128
if (is_zero(depth))
128129
return tree.front();
129130

130-
// Merkle root treats a single hash as top/complete, but for a non-zero
131-
// depth subtree, any odd leaf requires duplication including a single.
131+
// merkle_root() treats a single hash as top/complete, but for a partial
132+
// depth subtree, an odd leaf (including a single) requires duplication.
132133
if (is_odd(tree.size()))
134+
{
133135
tree.push_back(tree.back());
136+
////std::cout << "evened : " << tree.size() << std::endl;
137+
}
134138

135139
// Log2 of the evened breadth gives the elevation by merkle_root.
136-
const auto partial = ceilinged_log2(tree.size());
140+
auto partial = ceilinged_log2(tree.size());
137141

138142
// Partial cannot exceed depth, since tree.size() <= span (a power of 2).
139143
if (is_subtract_overflow(depth, partial))
140144
return {};
141145

142146
// Elevate hashes to partial level.
147+
////std::cout << "merkled : " << tree.size() << std::endl;
143148
auto hash = merkle_root(std::move(tree));
144149

145-
// Elevate hashes from partial to depth level.
146-
for (size_t level{}; level < (depth - partial); ++level)
150+
// Elevate hashes from partial to depth.
151+
for (; partial < depth; ++partial)
152+
{
147153
hash = sha256::double_hash(hash, hash);
154+
////std::cout << "hashed : " << partial << std::endl;
155+
}
148156

149157
return hash;
150158
}
@@ -156,9 +164,22 @@ code CLASS::get_merkle_subroots(hashes& roots, size_t waypoint) const NOEXCEPT
156164
const auto span = interval_span();
157165
BC_ASSERT(!is_zero(span));
158166

159-
const auto range = add1(waypoint);
160-
roots.reserve(system::ceilinged_divide(range, span));
161-
for (size_t first{}; first < range; first += span)
167+
// Roots is even-size-except-one-reserved for merkle root push.
168+
const auto leaves = add1(waypoint);
169+
const auto limit = system::ceilinged_divide(leaves, span);
170+
const auto reserve = limit + to_int<size_t>(!is_one(limit) && is_odd(limit));
171+
roots.reserve(reserve);
172+
173+
//// const auto config = system::ceilinged_log2(span);
174+
////std::cout << "==================================" << std::endl;
175+
////std::cout << "config : " << config << std::endl;
176+
////std::cout << "span : " << span << std::endl;
177+
////std::cout << "leaves : " << leaves << std::endl;
178+
////std::cout << "waypoint : " << waypoint << std::endl;
179+
////std::cout << "reserve : " << reserve << std::endl;
180+
181+
// Either all subroots elevated to same level, or there is a single root.
182+
for (size_t first{}; first < leaves; first += span)
162183
{
163184
const auto last = std::min(sub1(first + span), waypoint);
164185
const auto size = add1(last - first);
@@ -168,13 +189,26 @@ code CLASS::get_merkle_subroots(hashes& roots, size_t waypoint) const NOEXCEPT
168189
auto interval = get_confirmed_interval(last);
169190
if (!interval.has_value()) return error::merkle_interval;
170191
roots.push_back(std::move(interval.value()));
192+
////std::cout << "A cached subroot : ";
193+
}
194+
else if (is_zero(first))
195+
{
196+
// Single hash, is the complete merkle root.
197+
auto complete = get_confirmed_hashes(zero, size);
198+
roots.push_back(system::merkle_root(std::move(complete)));
199+
////std::cout << "The merkle root : ";
171200
}
172201
else
173202
{
203+
// Roots is even-size-except-one-reserved for merkle root push.
174204
auto partial = get_confirmed_hashes(first, size);
175205
if (partial.empty()) return error::merkle_hashes;
176-
roots.push_back(merkle_subroot(std::move(partial), span));
206+
roots.push_back(partial_subroot(std::move(partial), span));
207+
////std::cout << "Computed subroot : ";
177208
}
209+
210+
////std::cout << first << " - " << last
211+
//// << " [" << system::encode_hash(roots.back()) << "]" << std::endl;
178212
}
179213

180214
return error::success;
@@ -190,26 +224,26 @@ code CLASS::get_merkle_root_and_proof(hash_digest& root, hashes& proof,
190224
if (waypoint > get_top_confirmed())
191225
return error::not_found;
192226

193-
hashes tree{};
194-
if (const auto ec = get_merkle_subroots(tree, waypoint))
227+
hashes roots{};
228+
if (const auto ec = get_merkle_subroots(roots, waypoint))
195229
return ec;
196230

197231
proof.clear();
198-
if (const auto ec = get_merkle_proof(proof, tree, target, waypoint))
232+
if (const auto ec = get_merkle_proof(proof, roots, target, waypoint))
199233
return ec;
200234

201-
root = system::merkle_root(std::move(tree));
235+
root = system::merkle_root(std::move(roots));
202236
return {};
203237
}
204238

205239
TEMPLATE
206240
hash_digest CLASS::get_merkle_root(size_t height) const NOEXCEPT
207241
{
208-
hashes tree{};
209-
if (const auto ec = get_merkle_subroots(tree, height))
242+
hashes roots{};
243+
if (const auto ec = get_merkle_subroots(roots, height))
210244
return {};
211245

212-
return system::merkle_root(std::move(tree));
246+
return system::merkle_root(std::move(roots));
213247
}
214248

215249
} // namespace database

include/bitcoin/database/query.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,8 +768,8 @@ class query
768768
/// -----------------------------------------------------------------------
769769

770770
// merkle related utilities
771-
static hash_digest merkle_subroot(hashes&& tree, size_t span) NOEXCEPT;
772-
static void merge_merkle(hashes& branch, hashes&& hashes,
771+
static hash_digest partial_subroot(hashes&& tree, size_t span) NOEXCEPT;
772+
static void merge_merkle(hashes& to, hashes&& from,
773773
size_t first) NOEXCEPT;
774774

775775
// merkle related configuration

0 commit comments

Comments
 (0)