@@ -77,10 +77,14 @@ CLASS::hash_option CLASS::get_confirmed_interval(size_t height) const NOEXCEPT
7777TEMPLATE
7878void CLASS::merge_merkle (hashes& to, hashes&& from, size_t first) NOEXCEPT
7979{
80+ // from is either even or has one additional element of reserved space.
81+ if (!is_one (from.size ()) && is_odd (from.size ()))
82+ from.push_back (from.back ());
83+
8084 using namespace system ;
8185 for (const auto & row: block::merkle_branch (first, from.size ()))
8286 {
83- BC_ASSERT (row.sibling * add1 ( row.width ) <= from.size ());
87+ BC_ASSERT (add1 ( row.sibling ) * row.width <= from.size ());
8488 const auto it = std::next (from.begin (), row.sibling * row.width );
8589 const auto mover = std::make_move_iterator (it);
8690 to.push_back (merkle_root ({ mover, std::next (mover, row.width ) }));
@@ -108,15 +112,52 @@ code CLASS::get_merkle_proof(hashes& proof, hashes roots, size_t target,
108112 return error::success;
109113}
110114
115+ // static/private
116+ TEMPLATE
117+ hash_digest CLASS::merkle_subroot (hashes&& tree, size_t span) NOEXCEPT
118+ {
119+ using namespace system ;
120+
121+ // Tree cannot be empty or exceed span (span is power of two).
122+ if (tree.empty () || tree.size () > span)
123+ return {};
124+
125+ // zero depth implies single tree element, which is the root.
126+ const auto depth = ceilinged_log2 (span);
127+ if (is_zero (depth))
128+ return tree.front ();
129+
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.
132+ if (is_odd (tree.size ()))
133+ tree.push_back (tree.back ());
134+
135+ // Log2 of the evened breadth gives the elevation by merkle_root.
136+ const auto partial = ceilinged_log2 (tree.size ());
137+
138+ // Partial cannot exceed depth, since tree.size() <= span (a power of 2).
139+ if (is_subtract_overflow (depth, partial))
140+ return {};
141+
142+ // Elevate hashes to partial level.
143+ 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)
147+ hash = sha256::double_hash (hash, hash);
148+
149+ return hash;
150+ }
151+
111152// protected
112153TEMPLATE
113- code CLASS::get_merkle_tree (hashes& tree , size_t waypoint) const NOEXCEPT
154+ code CLASS::get_merkle_subroots (hashes& roots , size_t waypoint) const NOEXCEPT
114155{
115156 const auto span = interval_span ();
116157 BC_ASSERT (!is_zero (span));
117158
118159 const auto range = add1 (waypoint);
119- tree .reserve (system::ceilinged_divide (range, span));
160+ roots .reserve (system::ceilinged_divide (range, span));
120161 for (size_t first{}; first < range; first += span)
121162 {
122163 const auto last = std::min (sub1 (first + span), waypoint);
@@ -126,13 +167,13 @@ code CLASS::get_merkle_tree(hashes& tree, size_t waypoint) const NOEXCEPT
126167 {
127168 auto interval = get_confirmed_interval (last);
128169 if (!interval.has_value ()) return error::merkle_interval;
129- tree .push_back (std::move (interval.value ()));
170+ roots .push_back (std::move (interval.value ()));
130171 }
131172 else
132173 {
133- auto confirmed = get_confirmed_hashes (first, size);
134- if (confirmed .empty ()) return error::merkle_hashes;
135- tree .push_back (system::merkle_root (std::move (confirmed) ));
174+ auto partial = get_confirmed_hashes (first, size);
175+ if (partial .empty ()) return error::merkle_hashes;
176+ roots .push_back (merkle_subroot (std::move (partial), span ));
136177 }
137178 }
138179
@@ -150,7 +191,7 @@ code CLASS::get_merkle_root_and_proof(hash_digest& root, hashes& proof,
150191 return error::not_found;
151192
152193 hashes tree{};
153- if (const auto ec = get_merkle_tree (tree, waypoint))
194+ if (const auto ec = get_merkle_subroots (tree, waypoint))
154195 return ec;
155196
156197 proof.clear ();
@@ -165,7 +206,7 @@ TEMPLATE
165206hash_digest CLASS::get_merkle_root (size_t height) const NOEXCEPT
166207{
167208 hashes tree{};
168- if (const auto ec = get_merkle_tree (tree, height))
209+ if (const auto ec = get_merkle_subroots (tree, height))
169210 return {};
170211
171212 return system::merkle_root (std::move (tree));
0 commit comments