Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/bitcoin/system/chain/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ class BC_API block
struct position { size_t sibling; size_t width; };
using positions = std::vector<position>;

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.
/// -----------------------------------------------------------------------
Expand Down
10 changes: 6 additions & 4 deletions src/chain/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -445,23 +445,25 @@ 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<size_t>)));

positions branch{};
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);
Expand Down
156 changes: 114 additions & 42 deletions test/chain/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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<size_t>)));
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<size_t>));
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<size_t>))));

branch = block::merkle_branch(maximum, add1(maximum), false);
BOOST_REQUIRE_EQUAL(branch.size(), sub1(bits<size_t>));
BOOST_REQUIRE_EQUAL(branch.front().sibling, sub1(maximum));
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
Expand Down
Loading