Skip to content

Commit 2a45264

Browse files
authored
Merge pull request #1780 from evoskuil/master
Change block::merkle_branch to accept/provide more context, style.
2 parents cd34bb8 + 2650ab1 commit 2a45264

13 files changed

Lines changed: 338 additions & 303 deletions

File tree

include/bitcoin/system/chain/block.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ class BC_API block
4141
DEFAULT_COPY_MOVE_DESTRUCT(block);
4242

4343
typedef std::shared_ptr<const block> cptr;
44+
struct position { size_t sibling; size_t width; };
45+
using positions = std::vector<position>;
4446

45-
static std::vector<size_t> merkle_branch(size_t leaf) NOEXCEPT;
47+
static positions merkle_branch(size_t leaf, size_t leaves) NOEXCEPT;
4648
static bool is_malleable64(const transaction_cptrs& txs) NOEXCEPT;
4749
static uint64_t subsidy(size_t height, uint64_t subsidy_interval,
4850
uint64_t initial_block_subsidy_satoshi, bool bip42) NOEXCEPT;

include/bitcoin/system/math/multiplication.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
namespace libbitcoin {
2525
namespace system {
2626

27-
/// Safely determine whether product is a whole mutiple of value.
27+
/// Safely determine whether product is a whole multiple of value.
2828
template <typename Integer,
2929
if_integer<Integer> = true>
3030
constexpr bool is_multiple(Integer product, Integer value) NOEXCEPT;

src/chain/block.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,11 @@ const transactions_cptr& block::transactions_ptr() const NOEXCEPT
229229

230230
hashes block::transaction_hashes(bool witness) const NOEXCEPT
231231
{
232-
const auto count = txs_->size();
233-
const auto size = is_odd(count) && count > one ? add1(count) : count;
234-
hashes out{ size };
235-
236232
// Extra allocation for odd count optimizes for merkle root.
237233
// Vector capacity is never reduced when resizing to smaller size.
234+
const auto count = txs_->size();
235+
const auto size = is_odd(count) && count > one ? add1(count) : count;
236+
hashes out(size);
238237
out.resize(count);
239238

240239
const auto hash = [witness](const auto& tx) NOEXCEPT
@@ -404,7 +403,7 @@ bool block::is_forward_reference() const NOEXCEPT
404403
if (txs_->empty())
405404
return false;
406405

407-
unordered_set_of_hash_cref hashes{ sub1(txs_->size()) };
406+
unordered_set_of_hash_cref hashes(sub1(txs_->size()));
408407
for (auto tx = txs_->rbegin(); tx != std::prev(txs_->rend()); ++tx)
409408
{
410409
for (const auto& in: *(*tx)->inputs_ptr())
@@ -425,7 +424,7 @@ bool block::is_internal_double_spend() const NOEXCEPT
425424
if (txs_->empty())
426425
return false;
427426

428-
unordered_set_of_point_cref points{ spends() };
427+
unordered_set_of_point_cref points(spends());
429428
for (auto tx = std::next(txs_->begin()); tx != txs_->end(); ++tx)
430429
for (const auto& in: *(*tx)->inputs_ptr())
431430
if (!points.emplace(in->point()).second)
@@ -446,29 +445,29 @@ bool block::is_invalid_merkle_root() const NOEXCEPT
446445
}
447446

448447
// public/static (utility)
449-
std::vector<size_t> block::merkle_branch(size_t leaf) NOEXCEPT
448+
block::positions block::merkle_branch(size_t leaf, size_t leaves) NOEXCEPT
450449
{
451-
BC_ASSERT(leaf < power2(sub1(bits<size_t>)));
450+
BC_ASSERT(leaves <= power2(sub1(bits<size_t>)));
452451

453-
std::vector<size_t> positions{};
454-
if (is_zero(leaf))
455-
return positions;
452+
positions branch{};
453+
if (is_zero(leaves) || leaf >= leaves)
454+
return branch;
456455

457456
// Upper bound, actual count may be less due to duplication.
458-
positions.reserve(ceilinged_log2(leaf));
457+
branch.reserve(ceilinged_log2(leaves));
459458

460-
for (auto width = one, leaves = add1(leaf); leaves > one;)
459+
for (auto width = one, current = leaves; current > one;)
461460
{
462461
const auto sibling = bit_xor(leaf, one);
463-
if (sibling < leaves++)
464-
positions.push_back(sibling * width);
462+
if (sibling < current++)
463+
branch.emplace_back(sibling, width);
465464

466-
shift_right_into(leaf);
467-
shift_right_into(leaves);
468465
shift_left_into(width);
466+
shift_right_into(leaf);
467+
shift_right_into(current);
469468
}
470469

471-
return positions;
470+
return branch;
472471
}
473472

474473
// Accept (contextual).
@@ -506,7 +505,7 @@ bool block::is_hash_limit_exceeded() const NOEXCEPT
506505
return false;
507506

508507
// A set is used to collapse duplicates.
509-
unordered_set_of_hash_cref hashes{ txs_->size() };
508+
unordered_set_of_hash_cref hashes(txs_->size());
510509

511510
// Just the coinbase tx hash, skip its null input hashes.
512511
hashes.emplace(txs_->front()->get_hash(false));
@@ -768,7 +767,7 @@ void block::populate() const NOEXCEPT
768767
if (txs_->empty())
769768
return;
770769

771-
unordered_map_of_cref_point_to_output_cptr_cref points{ outputs() };
770+
unordered_map_of_cref_point_to_output_cptr_cref points(outputs());
772771
uint32_t index{};
773772

774773
// Populate outputs hash table (coinbase included).
@@ -797,7 +796,7 @@ code block::populate_with_metadata(const chain::context& ctx) const NOEXCEPT
797796
return error::block_success;
798797

799798
const auto bip68 = ctx.is_enabled(chain::flags::bip68_rule);
800-
unordered_map_of_cref_point_to_output_cptr_cref points{ outputs() };
799+
unordered_map_of_cref_point_to_output_cptr_cref points(outputs());
801800
uint32_t index{};
802801

803802
// Populate outputs hash table (coinbase included).

test/chain/block.cpp

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -710,72 +710,106 @@ BOOST_AUTO_TEST_CASE(block__is_invalid_merkle_root__block100k__false)
710710

711711
BOOST_AUTO_TEST_CASE(block__merkle_branch__leaf_zero__empty)
712712
{
713-
BOOST_REQUIRE(block::merkle_branch(0).empty());
713+
BOOST_REQUIRE(block::merkle_branch(0, 0).empty());
714714
}
715715

716716
BOOST_AUTO_TEST_CASE(block__merkle_branch__one__zero)
717717
{
718-
const std::vector<size_t> expected{ 0 };
719-
BOOST_REQUIRE(block::merkle_branch(1) == expected);
718+
const auto result = block::merkle_branch(1, 2);
719+
BOOST_REQUIRE_EQUAL(result.size(), 1u);
720+
BOOST_REQUIRE_EQUAL(result[0].sibling, 0u);
721+
BOOST_REQUIRE_EQUAL(result[0].width, 1u);
720722
}
721723

722724
BOOST_AUTO_TEST_CASE(block__merkle_branch__two_for_odd_length__zero)
723725
{
724-
const std::vector<size_t> expected{ 0 };
725-
BOOST_REQUIRE(block::merkle_branch(2) == expected);
726+
const auto result = block::merkle_branch(2, 3);
727+
BOOST_REQUIRE_EQUAL(result.size(), 1u);
728+
BOOST_REQUIRE_EQUAL(result[0].sibling, 0u);
729+
BOOST_REQUIRE_EQUAL(result[0].width, 2u);
726730
}
727731

728732
BOOST_AUTO_TEST_CASE(block__merkle_branch__three__two_and_zero)
729733
{
730-
const std::vector<size_t> expected{ 2, 0 };
731-
BOOST_REQUIRE(block::merkle_branch(3) == expected);
734+
const auto result = block::merkle_branch(3, 4);
735+
BOOST_REQUIRE_EQUAL(result.size(), 2u);
736+
BOOST_REQUIRE_EQUAL(result[0].sibling, 2u);
737+
BOOST_REQUIRE_EQUAL(result[0].width, 1u);
738+
BOOST_REQUIRE_EQUAL(result[1].sibling, 0u);
739+
BOOST_REQUIRE_EQUAL(result[1].width, 2u);
732740
}
733741

734742
BOOST_AUTO_TEST_CASE(block__merkle_branch__seven__six_four_and_zero)
735743
{
736-
const std::vector<size_t> expected{ 6, 4, 0 };
737-
BOOST_REQUIRE(block::merkle_branch(7) == expected);
744+
const auto result = block::merkle_branch(7, 8);
745+
BOOST_REQUIRE_EQUAL(result.size(), 3u);
746+
BOOST_REQUIRE_EQUAL(result[0].sibling, 6u);
747+
BOOST_REQUIRE_EQUAL(result[0].width, 1u);
748+
BOOST_REQUIRE_EQUAL(result[1].sibling, 2u);
749+
BOOST_REQUIRE_EQUAL(result[1].width, 2u);
750+
BOOST_REQUIRE_EQUAL(result[2].sibling, 0u);
751+
BOOST_REQUIRE_EQUAL(result[2].width, 4u);
738752
}
739753

740754
BOOST_AUTO_TEST_CASE(block__merkle_branch__ten_for_odd__eight_and_zero)
741755
{
742-
const std::vector<size_t> expected{ 8, 0 };
743-
BOOST_REQUIRE(block::merkle_branch(10) == expected);
756+
const auto result = block::merkle_branch(10, 11);
757+
BOOST_REQUIRE_EQUAL(result.size(), 2u);
758+
BOOST_REQUIRE_EQUAL(result[0].sibling, 4u);
759+
BOOST_REQUIRE_EQUAL(result[0].width, 2u);
760+
BOOST_REQUIRE_EQUAL(result[1].sibling, 0u);
761+
BOOST_REQUIRE_EQUAL(result[1].width, 8u);
744762
}
745763

746764
BOOST_AUTO_TEST_CASE(block__merkle_branch__medium_power_of_two__expected)
747765
{
748-
const std::vector<size_t> expected{ 14u, 12u, 8u, 0u };
749-
BOOST_REQUIRE(block::merkle_branch(15u) == expected);
766+
const block::positions expected{ { 14, 1 }, { 6, 2 }, { 2, 4 }, { 0, 8 } };
767+
768+
const auto result = block::merkle_branch(15, 16);
769+
BOOST_REQUIRE_EQUAL(result.size(), 4u);
770+
BOOST_REQUIRE_EQUAL(result[0].sibling, 14u);
771+
BOOST_REQUIRE_EQUAL(result[0].width, 1u);
772+
BOOST_REQUIRE_EQUAL(result[1].sibling, 6u);
773+
BOOST_REQUIRE_EQUAL(result[1].width, 2u);
774+
BOOST_REQUIRE_EQUAL(result[2].sibling, 2u);
775+
BOOST_REQUIRE_EQUAL(result[2].width, 4u);
776+
BOOST_REQUIRE_EQUAL(result[3].sibling, 0u);
777+
BOOST_REQUIRE_EQUAL(result[3].width, 8u);
750778
}
751779

752780
BOOST_AUTO_TEST_CASE(block__merkle_branch__power_of_two_minus_one__expected)
753781
{
754782
constexpr auto leaf = 1023u;
755-
constexpr auto size = ceilinged_log2(leaf);
756-
const auto positions = block::merkle_branch(leaf);
757-
BOOST_CHECK_EQUAL(positions.size(), size);
758-
BOOST_CHECK_EQUAL(positions.front(), 1022u);
759-
BOOST_CHECK_EQUAL(positions.back(), 0u);
783+
constexpr auto size = sub1(ceilinged_log2(add1(leaf)));
784+
const auto branch = block::merkle_branch(leaf, add1(leaf));
785+
BOOST_REQUIRE_EQUAL(branch.size(), size);
786+
BOOST_REQUIRE_EQUAL(branch.front().sibling, 1022u);
787+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
788+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
789+
BOOST_REQUIRE_EQUAL(branch.back().width, power2(sub1(size)));
760790
}
761791

762792
BOOST_AUTO_TEST_CASE(block__merkle_branch__odd_large_leaf_with_duplication__expected)
763793
{
764794
constexpr auto leaf = 2047u;
765-
constexpr auto size = ceilinged_log2(leaf);
766-
const auto positions = block::merkle_branch(leaf);
767-
BOOST_CHECK_EQUAL(positions.size(), size);
768-
BOOST_CHECK_EQUAL(positions.front(), 2046u);
769-
BOOST_CHECK_EQUAL(positions.back(), 0u);
795+
constexpr auto size = sub1(ceilinged_log2(add1(leaf)));
796+
const auto branch = block::merkle_branch(leaf, add1(leaf));
797+
BOOST_REQUIRE_EQUAL(branch.size(), size);
798+
BOOST_REQUIRE_EQUAL(branch.front().sibling, 2046u);
799+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
800+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
801+
BOOST_REQUIRE_EQUAL(branch.back().width, power2(sub1(size)));
770802
}
771803

772804
BOOST_AUTO_TEST_CASE(block__merkle_branch__maximum_non_overflow__expected)
773805
{
774806
constexpr auto maximum = sub1(power2(sub1(bits<size_t>)));
775-
const auto positions = block::merkle_branch(maximum);
776-
BOOST_CHECK_EQUAL(positions.size(), sub1(bits<size_t>));
777-
BOOST_CHECK_EQUAL(positions.front(), sub1(maximum));
778-
BOOST_CHECK_EQUAL(positions.back(), 0u);
807+
const auto branch = block::merkle_branch(maximum, add1(maximum));
808+
BOOST_REQUIRE_EQUAL(branch.size(), sub1(bits<size_t>));
809+
BOOST_REQUIRE_EQUAL(branch.front().sibling, sub1(maximum));
810+
BOOST_REQUIRE_EQUAL(branch.front().width, 1u);
811+
BOOST_REQUIRE_EQUAL(branch.back().sibling, 0u);
812+
BOOST_REQUIRE_EQUAL(branch.back().width, power2(sub1(sub1(bits<size_t>))));
779813
}
780814

781815
// is_overweight

0 commit comments

Comments
 (0)