diff --git a/include/bitcoin/system/chain/block.hpp b/include/bitcoin/system/chain/block.hpp index cff6febb94..f4b1ee8a5e 100644 --- a/include/bitcoin/system/chain/block.hpp +++ b/include/bitcoin/system/chain/block.hpp @@ -44,10 +44,11 @@ class BC_API block struct position { size_t sibling; size_t width; }; using positions = std::vector; - static positions merkle_branch(size_t leaf, size_t leaves) NOEXCEPT; static bool is_malleable64(const transaction_cptrs& txs) NOEXCEPT; static uint64_t subsidy(size_t height, uint64_t subsidy_interval, uint64_t initial_block_subsidy_satoshi, bool bip42) NOEXCEPT; + static positions merkle_branch(size_t leaf, size_t leaves, + bool compress=false) NOEXCEPT; /// Constructors. /// ----------------------------------------------------------------------- diff --git a/src/chain/block.cpp b/src/chain/block.cpp index 75df1bb412..1181ac986d 100644 --- a/src/chain/block.cpp +++ b/src/chain/block.cpp @@ -232,7 +232,7 @@ hashes block::transaction_hashes(bool witness) const NOEXCEPT // Extra allocation for odd count optimizes for merkle root. // Vector capacity is never reduced when resizing to smaller size. const auto count = txs_->size(); - const auto size = is_odd(count) && count > one ? add1(count) : count; + const auto size = !is_one(count) && is_odd(count) ? add1(count) : count; hashes out(size); out.resize(count); @@ -445,7 +445,8 @@ bool block::is_invalid_merkle_root() const NOEXCEPT } // public/static (utility) -block::positions block::merkle_branch(size_t leaf, size_t leaves) NOEXCEPT +block::positions block::merkle_branch(size_t leaf, size_t leaves, + bool compress) NOEXCEPT { BC_ASSERT(leaves <= power2(sub1(bits))); @@ -453,15 +454,16 @@ block::positions block::merkle_branch(size_t leaf, size_t leaves) NOEXCEPT if (is_zero(leaves) || leaf >= leaves) return branch; - // Upper bound, actual count may be less due to duplication. + // Upper bound, actual count may be less given compression. branch.reserve(ceilinged_log2(leaves)); for (auto width = one, current = leaves; current > one;) { const auto sibling = bit_xor(leaf, one); - if (sibling < current++) + if (!compress || sibling < current) branch.emplace_back(sibling, width); + ++current; shift_left_into(width); shift_right_into(leaf); shift_right_into(current); diff --git a/test/chain/block.cpp b/test/chain/block.cpp index 3a983dc342..b5bcb62d2a 100644 --- a/test/chain/block.cpp +++ b/test/chain/block.cpp @@ -710,78 +710,136 @@ BOOST_AUTO_TEST_CASE(block__is_invalid_merkle_root__block100k__false) BOOST_AUTO_TEST_CASE(block__merkle_branch__leaf_zero__empty) { - BOOST_REQUIRE(block::merkle_branch(0, 0).empty()); + BOOST_REQUIRE(block::merkle_branch(0, 0, true).empty()); + BOOST_REQUIRE(block::merkle_branch(0, 0, false).empty()); } BOOST_AUTO_TEST_CASE(block__merkle_branch__one__zero) { - const auto result = block::merkle_branch(1, 2); - BOOST_REQUIRE_EQUAL(result.size(), 1u); - BOOST_REQUIRE_EQUAL(result[0].sibling, 0u); - BOOST_REQUIRE_EQUAL(result[0].width, 1u); + auto branch = block::merkle_branch(1, 2, true); + BOOST_REQUIRE_EQUAL(branch.size(), 1u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + + branch = block::merkle_branch(1, 2, false); + BOOST_REQUIRE_EQUAL(branch.size(), 1u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); } BOOST_AUTO_TEST_CASE(block__merkle_branch__two_for_odd_length__zero) { - const auto result = block::merkle_branch(2, 3); - BOOST_REQUIRE_EQUAL(result.size(), 1u); - BOOST_REQUIRE_EQUAL(result[0].sibling, 0u); - BOOST_REQUIRE_EQUAL(result[0].width, 2u); + auto branch = block::merkle_branch(2, 3, true); + BOOST_REQUIRE_EQUAL(branch.size(), 1u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[0].width, 2u); + + branch = block::merkle_branch(2, 3, false); + BOOST_REQUIRE_EQUAL(branch.size(), 2u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 3u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[1].width, 2u); } BOOST_AUTO_TEST_CASE(block__merkle_branch__three__two_and_zero) { - const auto result = block::merkle_branch(3, 4); - BOOST_REQUIRE_EQUAL(result.size(), 2u); - BOOST_REQUIRE_EQUAL(result[0].sibling, 2u); - BOOST_REQUIRE_EQUAL(result[0].width, 1u); - BOOST_REQUIRE_EQUAL(result[1].sibling, 0u); - BOOST_REQUIRE_EQUAL(result[1].width, 2u); + auto branch = block::merkle_branch(3, 4, true); + BOOST_REQUIRE_EQUAL(branch.size(), 2u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 2u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[1].width, 2u); + + branch = block::merkle_branch(3, 4, false); + BOOST_REQUIRE_EQUAL(branch.size(), 2u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 2u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[1].width, 2u); } BOOST_AUTO_TEST_CASE(block__merkle_branch__seven__six_four_and_zero) { - const auto result = block::merkle_branch(7, 8); - BOOST_REQUIRE_EQUAL(result.size(), 3u); - BOOST_REQUIRE_EQUAL(result[0].sibling, 6u); - BOOST_REQUIRE_EQUAL(result[0].width, 1u); - BOOST_REQUIRE_EQUAL(result[1].sibling, 2u); - BOOST_REQUIRE_EQUAL(result[1].width, 2u); - BOOST_REQUIRE_EQUAL(result[2].sibling, 0u); - BOOST_REQUIRE_EQUAL(result[2].width, 4u); + auto branch = block::merkle_branch(7, 8, true); + BOOST_REQUIRE_EQUAL(branch.size(), 3u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 6u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 2u); + BOOST_REQUIRE_EQUAL(branch[1].width, 2u); + BOOST_REQUIRE_EQUAL(branch[2].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[2].width, 4u); + + branch = block::merkle_branch(7, 8, false); + BOOST_REQUIRE_EQUAL(branch.size(), 3u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 6u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 2u); + BOOST_REQUIRE_EQUAL(branch[1].width, 2u); + BOOST_REQUIRE_EQUAL(branch[2].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[2].width, 4u); } BOOST_AUTO_TEST_CASE(block__merkle_branch__ten_for_odd__eight_and_zero) { - const auto result = block::merkle_branch(10, 11); - BOOST_REQUIRE_EQUAL(result.size(), 2u); - BOOST_REQUIRE_EQUAL(result[0].sibling, 4u); - BOOST_REQUIRE_EQUAL(result[0].width, 2u); - BOOST_REQUIRE_EQUAL(result[1].sibling, 0u); - BOOST_REQUIRE_EQUAL(result[1].width, 8u); + auto branch = block::merkle_branch(10, 11, true); + BOOST_REQUIRE_EQUAL(branch.size(), 2u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 4u); + BOOST_REQUIRE_EQUAL(branch[0].width, 2u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[1].width, 8u); + + branch = block::merkle_branch(10, 11, false); + BOOST_REQUIRE_EQUAL(branch.size(), 4u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 11u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 4u); + BOOST_REQUIRE_EQUAL(branch[1].width, 2u); + BOOST_REQUIRE_EQUAL(branch[2].sibling, 3u); + BOOST_REQUIRE_EQUAL(branch[2].width, 4u); + BOOST_REQUIRE_EQUAL(branch[3].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[3].width, 8u); } BOOST_AUTO_TEST_CASE(block__merkle_branch__medium_power_of_two__expected) { const block::positions expected{ { 14, 1 }, { 6, 2 }, { 2, 4 }, { 0, 8 } }; - const auto result = block::merkle_branch(15, 16); - BOOST_REQUIRE_EQUAL(result.size(), 4u); - BOOST_REQUIRE_EQUAL(result[0].sibling, 14u); - BOOST_REQUIRE_EQUAL(result[0].width, 1u); - BOOST_REQUIRE_EQUAL(result[1].sibling, 6u); - BOOST_REQUIRE_EQUAL(result[1].width, 2u); - BOOST_REQUIRE_EQUAL(result[2].sibling, 2u); - BOOST_REQUIRE_EQUAL(result[2].width, 4u); - BOOST_REQUIRE_EQUAL(result[3].sibling, 0u); - BOOST_REQUIRE_EQUAL(result[3].width, 8u); + auto branch = block::merkle_branch(15, 16, true); + BOOST_REQUIRE_EQUAL(branch.size(), 4u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 14u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 6u); + BOOST_REQUIRE_EQUAL(branch[1].width, 2u); + BOOST_REQUIRE_EQUAL(branch[2].sibling, 2u); + BOOST_REQUIRE_EQUAL(branch[2].width, 4u); + BOOST_REQUIRE_EQUAL(branch[3].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[3].width, 8u); + + branch = block::merkle_branch(15, 16, false); + BOOST_REQUIRE_EQUAL(branch.size(), 4u); + BOOST_REQUIRE_EQUAL(branch[0].sibling, 14u); + BOOST_REQUIRE_EQUAL(branch[0].width, 1u); + BOOST_REQUIRE_EQUAL(branch[1].sibling, 6u); + BOOST_REQUIRE_EQUAL(branch[1].width, 2u); + BOOST_REQUIRE_EQUAL(branch[2].sibling, 2u); + BOOST_REQUIRE_EQUAL(branch[2].width, 4u); + BOOST_REQUIRE_EQUAL(branch[3].sibling, 0u); + BOOST_REQUIRE_EQUAL(branch[3].width, 8u); } BOOST_AUTO_TEST_CASE(block__merkle_branch__power_of_two_minus_one__expected) { constexpr auto leaf = 1023u; constexpr auto size = ceilinged_log2(add1(leaf)); - const auto branch = block::merkle_branch(leaf, add1(leaf)); + auto branch = block::merkle_branch(leaf, add1(leaf), true); + BOOST_REQUIRE_EQUAL(branch.size(), size); + BOOST_REQUIRE_EQUAL(branch.front().sibling, 1022u); + BOOST_REQUIRE_EQUAL(branch.front().width, 1u); + BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u); + BOOST_REQUIRE_EQUAL(branch.back().width, power2(sub1(size))); + + branch = block::merkle_branch(leaf, add1(leaf), false); BOOST_REQUIRE_EQUAL(branch.size(), size); BOOST_REQUIRE_EQUAL(branch.front().sibling, 1022u); BOOST_REQUIRE_EQUAL(branch.front().width, 1u); @@ -793,7 +851,14 @@ BOOST_AUTO_TEST_CASE(block__merkle_branch__odd_large_leaf_with_duplication__expe { constexpr auto leaf = 2047u; constexpr auto size = ceilinged_log2(add1(leaf)); - const auto branch = block::merkle_branch(leaf, add1(leaf)); + auto branch = block::merkle_branch(leaf, add1(leaf), true); + BOOST_REQUIRE_EQUAL(branch.size(), size); + BOOST_REQUIRE_EQUAL(branch.front().sibling, 2046u); + BOOST_REQUIRE_EQUAL(branch.front().width, 1u); + BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u); + BOOST_REQUIRE_EQUAL(branch.back().width, power2(sub1(size))); + + branch = block::merkle_branch(leaf, add1(leaf), false); BOOST_REQUIRE_EQUAL(branch.size(), size); BOOST_REQUIRE_EQUAL(branch.front().sibling, 2046u); BOOST_REQUIRE_EQUAL(branch.front().width, 1u); @@ -804,7 +869,14 @@ BOOST_AUTO_TEST_CASE(block__merkle_branch__odd_large_leaf_with_duplication__expe BOOST_AUTO_TEST_CASE(block__merkle_branch__maximum_non_overflow__expected) { constexpr auto maximum = sub1(power2(sub1(bits))); - const auto branch = block::merkle_branch(maximum, add1(maximum)); + auto branch = block::merkle_branch(maximum, add1(maximum), true); + BOOST_REQUIRE_EQUAL(branch.size(), sub1(bits)); + BOOST_REQUIRE_EQUAL(branch.front().sibling, sub1(maximum)); + BOOST_REQUIRE_EQUAL(branch.front().width, 1u); + BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u); + BOOST_REQUIRE_EQUAL(branch.back().width, power2(sub1(sub1(bits)))); + + branch = block::merkle_branch(maximum, add1(maximum), false); BOOST_REQUIRE_EQUAL(branch.size(), sub1(bits)); BOOST_REQUIRE_EQUAL(branch.front().sibling, sub1(maximum)); BOOST_REQUIRE_EQUAL(branch.front().width, 1u);