2020#define LIBBITCOIN_DATABASE_QUERY_MERKLE_IPP
2121
2222#include < algorithm>
23+ #include < iterator>
2324#include < ranges>
2425#include < utility>
2526#include < bitcoin/database/define.hpp>
@@ -45,15 +46,15 @@ CLASS::hash_option CLASS::create_interval(header_link link,
4546 return {};
4647
4748 // Generate the leaf nodes for the span.
48- hashes leaves (span);
49- for (auto & leaf: std::views::reverse (leaves ))
49+ hashes leafs (span);
50+ for (auto & leaf: std::views::reverse (leafs ))
5051 {
5152 leaf = get_header_key (link);
5253 link = to_parent (link);
5354 }
5455
5556 // Generate the merkle root of the interval ending on link header.
56- return system::merkle_root (std::move (leaves ));
57+ return system::merkle_root (std::move (leafs ));
5758}
5859
5960// protected
@@ -77,17 +78,18 @@ CLASS::hash_option CLASS::get_confirmed_interval(size_t height) const NOEXCEPT
7778TEMPLATE
7879void CLASS::merge_merkle (hashes& to, hashes&& from, size_t first) NOEXCEPT
7980{
80- // from is either even or has one additional element of reserved space.
81+ // From is either even or has one additional element of reserved space.
8182 if (!is_one (from.size ()) && is_odd (from.size ()))
8283 from.push_back (from.back ());
8384
84- using namespace system ;
8585 for (const auto & row: block::merkle_branch (first, from.size ()))
8686 {
87- BC_ASSERT (add1 (row.sibling ) * row.width <= from.size ());
88- const auto it = std::next (from.begin (), row.sibling * row.width );
89- const auto mover = std::make_move_iterator (it);
90- to.push_back (merkle_root ({ mover, std::next (mover, row.width ) }));
87+ if (const auto start = row.sibling * row.width ; start < from.size ())
88+ {
89+ const auto count = std::min (row.width , from.size () - start);
90+ auto it = std::make_move_iterator (std::next (from.begin (), start));
91+ to.push_back (partial_subroot ({ it, std::next (it, count) }, row.width ));
92+ }
9193 }
9294}
9395
@@ -114,36 +116,32 @@ code CLASS::get_merkle_proof(hashes& proof, hashes roots, size_t target,
114116
115117// static/private
116118TEMPLATE
117- hash_digest CLASS::merkle_subroot (hashes&& tree, size_t span) NOEXCEPT
119+ hash_digest CLASS::partial_subroot (hashes&& tree, size_t span) NOEXCEPT
118120{
119- using namespace system ;
120-
121- // Tree cannot be empty or exceed span (span is power of two).
121+ // Tree cannot be empty or exceed span (a power of 2).
122122 if (tree.empty () || tree.size () > span)
123123 return {};
124124
125- // zero depth implies single tree element, which is the root.
125+ // Zero depth implies single tree element, which is the root.
126+ using namespace system ;
126127 const auto depth = ceilinged_log2 (span);
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 ()))
133134 tree.push_back (tree.back ());
134135
135136 // Log2 of the evened breadth gives the elevation by merkle_root.
136- const auto partial = ceilinged_log2 (tree.size ());
137-
138137 // Partial cannot exceed depth, since tree.size() <= span (a power of 2).
138+ auto partial = ceilinged_log2 (tree.size ());
139139 if (is_subtract_overflow (depth, partial))
140140 return {};
141141
142- // Elevate hashes to partial level.
142+ // Elevate hashes to partial level, and then from partial to depth .
143143 auto hash = merkle_root (std::move (tree));
144-
145- // Elevate hashes from partial to depth level.
146- for (size_t level{}; level < (depth - partial); ++level)
144+ for (; partial < depth; ++partial)
147145 hash = sha256::double_hash (hash, hash);
148146
149147 return hash;
@@ -156,9 +154,16 @@ code CLASS::get_merkle_subroots(hashes& roots, size_t waypoint) const NOEXCEPT
156154 const auto span = interval_span ();
157155 BC_ASSERT (!is_zero (span));
158156
159- const auto range = add1 (waypoint);
160- roots.reserve (system::ceilinged_divide (range, span));
161- for (size_t first{}; first < range; first += span)
157+ using namespace system ;
158+ const auto leafs = add1 (waypoint);
159+ const auto limit = ceilinged_divide (leafs, span);
160+ const auto count = limit + to_int<size_t >(!is_one (limit) && is_odd (limit));
161+
162+ // Roots is even-size-except-one-reserved for merkle root push.
163+ roots.reserve (count);
164+
165+ // Either all subroots elevated to same level, or there is a single root.
166+ for (size_t first{}; first < leafs; first += span)
162167 {
163168 const auto last = std::min (sub1 (first + span), waypoint);
164169 const auto size = add1 (last - first);
@@ -169,11 +174,18 @@ code CLASS::get_merkle_subroots(hashes& roots, size_t waypoint) const NOEXCEPT
169174 if (!interval.has_value ()) return error::merkle_interval;
170175 roots.push_back (std::move (interval.value ()));
171176 }
177+ else if (is_zero (first))
178+ {
179+ // Single hash, is the complete merkle root.
180+ auto complete = get_confirmed_hashes (zero, size);
181+ roots.push_back (merkle_root (std::move (complete)));
182+ }
172183 else
173184 {
185+ // Roots is even-size-except-one-reserved for merkle root push.
174186 auto partial = get_confirmed_hashes (first, size);
175187 if (partial.empty ()) return error::merkle_hashes;
176- roots.push_back (merkle_subroot (std::move (partial), span));
188+ roots.push_back (partial_subroot (std::move (partial), span));
177189 }
178190 }
179191
@@ -190,26 +202,26 @@ code CLASS::get_merkle_root_and_proof(hash_digest& root, hashes& proof,
190202 if (waypoint > get_top_confirmed ())
191203 return error::not_found;
192204
193- hashes tree {};
194- if (const auto ec = get_merkle_subroots (tree , waypoint))
205+ hashes roots {};
206+ if (const auto ec = get_merkle_subroots (roots , waypoint))
195207 return ec;
196208
197209 proof.clear ();
198- if (const auto ec = get_merkle_proof (proof, tree , target, waypoint))
210+ if (const auto ec = get_merkle_proof (proof, roots , target, waypoint))
199211 return ec;
200212
201- root = system::merkle_root (std::move (tree ));
213+ root = system::merkle_root (std::move (roots ));
202214 return {};
203215}
204216
205217TEMPLATE
206218hash_digest CLASS::get_merkle_root (size_t height) const NOEXCEPT
207219{
208- hashes tree {};
209- if (const auto ec = get_merkle_subroots (tree , height))
220+ hashes roots {};
221+ if (const auto ec = get_merkle_subroots (roots , height))
210222 return {};
211223
212- return system::merkle_root (std::move (tree ));
224+ return system::merkle_root (std::move (roots ));
213225}
214226
215227} // namespace database
0 commit comments