Skip to content

Commit c15ce58

Browse files
committed
Change block::merkle_branch to accept/provide more context.
1 parent 6c27f53 commit c15ce58

3 files changed

Lines changed: 163 additions & 40 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;

src/chain/block.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -446,29 +446,30 @@ bool block::is_invalid_merkle_root() const NOEXCEPT
446446
}
447447

448448
// public/static (utility)
449-
std::vector<size_t> block::merkle_branch(size_t leaf) NOEXCEPT
449+
block::positions block::merkle_branch(size_t leaf, size_t leaves) NOEXCEPT
450450
{
451-
BC_ASSERT(leaf < power2(sub1(bits<size_t>)));
451+
BC_ASSERT(leaves <= power2(sub1(bits<size_t>)));
452+
BC_ASSERT(leaf < leaves);
452453

453-
std::vector<size_t> positions{};
454-
if (is_zero(leaf))
455-
return positions;
454+
positions branch{};
455+
if (is_zero(leaves))
456+
return branch;
456457

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

460-
for (auto width = one, leaves = add1(leaf); leaves > one;)
461+
for (auto width = one, current = leaves; current > one;)
461462
{
462463
const auto sibling = bit_xor(leaf, one);
463-
if (sibling < leaves++)
464-
positions.push_back(sibling * width);
464+
if (sibling < current++)
465+
branch.emplace_back(sibling, width);
465466

466-
shift_right_into(leaf);
467-
shift_right_into(leaves);
468467
shift_left_into(width);
468+
shift_right_into(leaf);
469+
shift_right_into(current);
469470
}
470471

471-
return positions;
472+
return branch;
472473
}
473474

474475
// Accept (contextual).

test/chain/block.cpp

Lines changed: 147 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -710,72 +710,192 @@ 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>))));
813+
}
814+
815+
// TODO: unused.
816+
hash_digest get_hash(size_t /* height */) NOEXCEPT
817+
{
818+
return {};
819+
}
820+
821+
// TODO: database query, limited to interval heights, txs table.
822+
hash_digest get_interval(size_t /* last */) NOEXCEPT
823+
{
824+
return {};
825+
}
826+
827+
// TODO: database query, chase ancestry.
828+
hashes get_segment(size_t first, size_t count) NOEXCEPT
829+
{
830+
BC_ASSERT(!is_add_overflow(first, count));
831+
832+
hashes out{};
833+
out.reserve(count);
834+
for (auto height = first; height < (first + count); ++height)
835+
out.push_back(get_hash(height));
836+
837+
return out;
838+
}
839+
840+
void push(hashes& branch, hashes&& hashes, size_t first,
841+
size_t count) NOEXCEPT
842+
{
843+
for (const auto& row: block::merkle_branch(first, count))
844+
{
845+
const auto it = std::next(hashes.begin(), row.sibling * row.width);
846+
const auto mover = std::make_move_iterator(it);
847+
branch.push_back(merkle_root({ mover, std::next(mover, row.width) }));
848+
}
849+
}
850+
851+
// Compute branch for target given checkpoint and merkle tree (hashes).
852+
hashes compute_merkle_proof(hashes roots, size_t checkpoint,
853+
size_t target) NOEXCEPT
854+
{
855+
constexpr auto depth = 11u;
856+
constexpr auto size = power2(depth);
857+
const auto local = target % size;
858+
const auto index = target / size;
859+
const auto start = index * size;
860+
const auto end = std::min(sub1(start + size), checkpoint);
861+
const auto length = add1(end - start);
862+
863+
hashes branch{};
864+
branch.reserve(ceilinged_log2(length) + ceilinged_log2(roots.size()));
865+
push(branch, get_segment(start, length), local, length);
866+
push(branch, std::move(roots), index, roots.size());
867+
return branch;
868+
}
869+
870+
hashes compute_merkle_roots(size_t checkpoint) NOEXCEPT
871+
{
872+
constexpr auto depth = 11u;
873+
constexpr auto size = power2(depth);
874+
const auto total = add1(checkpoint);
875+
876+
hashes roots{};
877+
roots.reserve(ceilinged_divide(total, size));
878+
for (size_t start{}; start < total; start += size)
879+
{
880+
const auto end = std::min(sub1(start + size), checkpoint);
881+
const auto length = add1(end - start);
882+
roots.push_back(length == size ? get_interval(end) :
883+
merkle_root(get_segment(start, length)));
884+
}
885+
886+
return roots;
887+
}
888+
889+
// Computes root and branch (proof) for a block height up to a checkpoint.
890+
std::pair<hash_digest, hashes> compute_root_and_branch(size_t checkpoint,
891+
size_t height) NOEXCEPT
892+
{
893+
BC_ASSERT(height <= checkpoint);
894+
895+
auto roots = compute_merkle_roots(checkpoint);
896+
auto proof = compute_merkle_proof(roots, checkpoint, height);
897+
auto root = merkle_root(std::move(roots));
898+
return { std::move(root), std::move(proof) };
779899
}
780900

781901
// is_overweight

0 commit comments

Comments
 (0)