Skip to content

Add math left_zeros, right_zeros, left_ones, right_ones. #1571

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 20, 2024
Merged
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
2 changes: 1 addition & 1 deletion include/bitcoin/system/chain/block.hpp
Original file line number Diff line number Diff line change
@@ -137,7 +137,7 @@ class BC_API block
code confirm(const context& ctx) const NOEXCEPT;

/// Populate previous outputs (only, no metadata) internal to the block.
void populate() const NOEXCEPT;
size_t populate() const NOEXCEPT;

protected:
block(const chain::header::cptr& header,
24 changes: 24 additions & 0 deletions include/bitcoin/system/impl/math/bits.ipp
Original file line number Diff line number Diff line change
@@ -49,6 +49,30 @@ constexpr size_t bit_width(Value value) NOEXCEPT
return is_negative(value) ? bits<Value> : bit_width(to_unsigned(value));
}

template <typename Value, if_unsigned_integer<Value>>
constexpr size_t left_zeros(Value value) NOEXCEPT
{
return to_unsigned(std::countl_zero<Value>(value));
}

template <typename Value, if_unsigned_integer<Value>>
constexpr size_t right_zeros(Value value) NOEXCEPT
{
return to_unsigned(std::countr_zero<Value>(value));
}

template <typename Value, if_unsigned_integer<Value>>
constexpr size_t left_ones(Value value) NOEXCEPT
{
return to_unsigned(std::countl_one<Value>(value));
}

template <typename Value, if_unsigned_integer<Value>>
constexpr size_t right_ones(Value value) NOEXCEPT
{
return to_unsigned(std::countr_one<Value>(value));
}

// Bitwise logical operations.
// ----------------------------------------------------------------------------

12 changes: 12 additions & 0 deletions include/bitcoin/system/math/bits.hpp
Original file line number Diff line number Diff line change
@@ -39,6 +39,18 @@ constexpr size_t bit_width(Value value) NOEXCEPT;
template <typename Value, if_signed_integer<Value> = true>
constexpr size_t bit_width(Value value) NOEXCEPT;

// Because std::countl_* (C++20) functions return int.
template <typename Value, if_unsigned_integer<Value> = true>
constexpr size_t left_zeros(Value value) NOEXCEPT;
template <typename Value, if_unsigned_integer<Value> = true>
constexpr size_t right_zeros(Value value) NOEXCEPT;

// Because std::countr_* (C++20) functions return int.
template <typename Value, if_unsigned_integer<Value> = true>
constexpr size_t left_ones(Value value) NOEXCEPT;
template <typename Value, if_unsigned_integer<Value> = true>
constexpr size_t right_ones(Value value) NOEXCEPT;

/// Bitwise logical operations.
/// ---------------------------------------------------------------------------

10 changes: 8 additions & 2 deletions src/chain/block.cpp
Original file line number Diff line number Diff line change
@@ -688,7 +688,7 @@ bool block::is_unspent_coinbase_collision() const NOEXCEPT
}

// Search is not ordered, forward references are caught by block.check.
void block::populate() const NOEXCEPT
size_t block::populate() const NOEXCEPT
{
std::unordered_map<point, output::cptr> points{};
uint32_t index{};
@@ -699,16 +699,22 @@ void block::populate() const NOEXCEPT
points.emplace(std::pair{ point{ (*tx)->hash(false), index++ },
out });

// Populate input prevouts from hash table.
// Populate input prevouts from hash table and obtain count.
size_t count{};
for (auto tx = txs_->begin(); tx != txs_->end(); ++tx)
{
for (const auto& in: *(*tx)->inputs_ptr())
{
const auto point = points.find(in->point());
if (point != points.end())
{
++count;
in->prevout = point->second;
}
}
}

return count;
}

// Delegated.
24 changes: 24 additions & 0 deletions test/math/bits.cpp
Original file line number Diff line number Diff line change
@@ -111,6 +111,30 @@ static_assert(bit_width<int64_t>(0x800000000000_ni64) == 64u);
static_assert(bit_width<int64_t>(0x80010000000000_ni64) == 64u);
static_assert(bit_width<int64_t>(0x8000000000000000_ni64) == 64u);

// zeroes

static_assert(left_zeros(uint8_t{ 0b00000000 }) == 8);
static_assert(left_zeros(uint8_t{ 0b11111111 }) == 0);
static_assert(left_zeros(uint8_t{ 0b11110000 }) == 0);
static_assert(left_zeros(uint8_t{ 0b00011110 }) == 3);

static_assert(right_zeros(uint8_t{ 0b00000000 }) == 8);
static_assert(right_zeros(uint8_t{ 0b11111111 }) == 0);
static_assert(right_zeros(uint8_t{ 0b00011100 }) == 2);
static_assert(right_zeros(uint8_t{ 0b00011101 }) == 0);

// ones

static_assert(left_ones(uint8_t{ 0b00000000 }) == 0);
static_assert(left_ones(uint8_t{ 0b11111111 }) == 8);
static_assert(left_ones(uint8_t{ 0b01111111 }) == 0);
static_assert(left_ones(uint8_t{ 0b11100011 }) == 3);

static_assert(right_ones(uint8_t{ 0b00000000 }) == 0);
static_assert(right_ones(uint8_t{ 0b11111111 }) == 8);
static_assert(right_ones(uint8_t{ 0b11111110 }) == 0);
static_assert(right_ones(uint8_t{ 0b11100011 }) == 2);

// ones_complement (NOT)
// inverts all bits (~n, !bool)
static_assert(bit_not(-4) == 3);
288 changes: 288 additions & 0 deletions test/utreexo/utreexo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
/**
* Copyright (c) 2011-2024 libbitcoin developers (see AUTHORS)
*
* This file is part of libbitcoin.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../test.hpp"
#include "utreexo.hpp"

using namespace utreexo;

BOOST_AUTO_TEST_SUITE(utreexo_tests)

// inferred from rustreexo implementation (no test provided)

BOOST_AUTO_TEST_CASE(utreexo__is_root_populated__various__expected)
{
static_assert(!is_root_populated(0b00000000, 0));
static_assert( is_root_populated(0b00000001, 0));
static_assert(!is_root_populated(0b00000000, 1));
static_assert( is_root_populated(0b00000010, 1));
static_assert(!is_root_populated(0b00000000, 2));
static_assert( is_root_populated(0b00000100, 2));
BOOST_REQUIRE(!is_root_populated(0, 0));
BOOST_REQUIRE( is_root_populated(1, 0));
BOOST_REQUIRE(!is_root_populated(0, 1));
BOOST_REQUIRE( is_root_populated(2, 1));
BOOST_REQUIRE(!is_root_populated(0, 2));
BOOST_REQUIRE( is_root_populated(4, 2));
}

BOOST_AUTO_TEST_CASE(utreexo__is_left_niece__various__expected)
{
static_assert( is_left_niece(0b00000000));
static_assert(!is_left_niece(0b00000001));
static_assert( is_left_niece(0b00000010));
BOOST_REQUIRE( is_left_niece(0));
BOOST_REQUIRE(!is_left_niece(1));
BOOST_REQUIRE( is_left_niece(2));
}

BOOST_AUTO_TEST_CASE(utreexo__left_sibling__various__expected)
{
static_assert(left_sibling(0b00000000) == 0b00000000);
static_assert(left_sibling(0b00000001) == 0b00000000);
static_assert(left_sibling(0b10101010) == 0b10101010);
static_assert(left_sibling(0b10101011) == 0b10101010);
BOOST_REQUIRE_EQUAL(left_sibling(0b00000000), 0b00000000);
BOOST_REQUIRE_EQUAL(left_sibling(0b00000001), 0b00000000);
BOOST_REQUIRE_EQUAL(left_sibling(0b10101010), 0b10101010);
BOOST_REQUIRE_EQUAL(left_sibling(0b10101011), 0b10101010);
}

BOOST_AUTO_TEST_CASE(utreexo__start_position_at_row__various__expected)
{
// forest_rows must be >= row.
static_assert(start_position_at_row(0, 0) == 0_u64);
static_assert(start_position_at_row(0, 1) == 0_u64);
static_assert(start_position_at_row(1, 1) == 2_u64);
static_assert(start_position_at_row(1, 2) == 4_u64);
static_assert(start_position_at_row(1, 3) == 8_u64);
static_assert(start_position_at_row(2, 2) == 6_u64);
static_assert(start_position_at_row(2, 3) == 12_u64);
static_assert(start_position_at_row(3, 3) == 14_u64);
BOOST_REQUIRE_EQUAL(start_position_at_row(0, 0), 0_u64);
BOOST_REQUIRE_EQUAL(start_position_at_row(0, 1), 0_u64);
BOOST_REQUIRE_EQUAL(start_position_at_row(1, 1), 2_u64);
BOOST_REQUIRE_EQUAL(start_position_at_row(1, 2), 4_u64);
BOOST_REQUIRE_EQUAL(start_position_at_row(1, 3), 8_u64);
BOOST_REQUIRE_EQUAL(start_position_at_row(2, 2), 6_u64);
BOOST_REQUIRE_EQUAL(start_position_at_row(2, 3), 12_u64);
BOOST_REQUIRE_EQUAL(start_position_at_row(3, 3), 14_u64);
}

BOOST_AUTO_TEST_CASE(utreexo__number_of_roots__various__expected)
{
static_assert(number_of_roots(0) == 0_size);
static_assert(number_of_roots(1) == 1_size);
static_assert(number_of_roots(2) == 1_size);
static_assert(number_of_roots(3) == 2_size);
static_assert(number_of_roots(0xfefefefefefefefe) == (64_size - 8_size));
BOOST_REQUIRE_EQUAL(number_of_roots(0), 0_size);
BOOST_REQUIRE_EQUAL(number_of_roots(1), 1_size);
BOOST_REQUIRE_EQUAL(number_of_roots(2), 1_size);
BOOST_REQUIRE_EQUAL(number_of_roots(3), 2_size);
BOOST_REQUIRE_EQUAL(number_of_roots(0xfefefefefefefefe), 56_size);
}

// based on rustreexo tests

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/node_hash.rs#L327
BOOST_AUTO_TEST_CASE(utreexo__parent_hash__zero_one__expected)
{
constexpr auto expected = base16_array("02242b37d8e851f1e86f46790298c7097df06893d6226b7c1453c213e91717de");
static_assert(parent_hash(hash_from_u8(0), hash_from_u8(1)) == expected);
BOOST_REQUIRE_EQUAL(parent_hash(hash_from_u8(0), hash_from_u8(1)), expected);
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L368
BOOST_AUTO_TEST_CASE(utreexo__is_right_sibling__zero_one__true)
{
static_assert(is_right_sibling(0, 1));
BOOST_REQUIRE(is_right_sibling(0, 1));
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L351
BOOST_AUTO_TEST_CASE(utreexo__is_sibling__various__expected)
{
static_assert( is_sibling(0, 1));
static_assert( is_sibling(1, 0));
static_assert(!is_sibling(1, 2));
static_assert(!is_sibling(2, 1));
BOOST_REQUIRE( is_sibling(0, 1));
BOOST_REQUIRE( is_sibling(1, 0));
BOOST_REQUIRE(!is_sibling(1, 2));
BOOST_REQUIRE(!is_sibling(2, 1));
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L474
BOOST_AUTO_TEST_CASE(utreexo__children__various__expected)
{
static_assert(children(4, 2) == 0_u64);
static_assert(children(49, 5) == 34_u64);
static_assert(children(50, 5) == 36_u64);
static_assert(children(44, 5) == 24_u64);
BOOST_REQUIRE_EQUAL(children(4, 2), 0_u64);
BOOST_REQUIRE_EQUAL(children(49, 5), 34_u64);
BOOST_REQUIRE_EQUAL(children(50, 5), 36_u64);
BOOST_REQUIRE_EQUAL(children(44, 5), 24_u64);
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L468
BOOST_AUTO_TEST_CASE(utreexo__is_root_position__various__expected)
{
static_assert(is_root_position(14, 8, 3));
BOOST_REQUIRE(is_root_position(14, 8, 3));
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L424
BOOST_AUTO_TEST_CASE(utreexo__tree_rows__various__expected)
{
static_assert(tree_rows(8) == 3_u8);
static_assert(tree_rows(9) == 4_u8);
static_assert(tree_rows(12) == 4_u8);
static_assert(tree_rows(255) == 8_u8);
BOOST_REQUIRE_EQUAL(tree_rows(8), 3_u8);
BOOST_REQUIRE_EQUAL(tree_rows(9), 4_u8);
BOOST_REQUIRE_EQUAL(tree_rows(12), 4_u8);
BOOST_REQUIRE_EQUAL(tree_rows(255), 8_u8);
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L439
BOOST_AUTO_TEST_CASE(utreexo__detect_row__scenario__expected)
{
constexpr auto test_detect_row_ = []() NOEXCEPT
{
auto success{ true };

// This is start_position_at_row.
constexpr auto row_offset = [](auto row, auto forest_rows) NOEXCEPT
{
return subtract(
bit_right<uint64_t>(add1<size_t>(forest_rows)),
bit_right<uint64_t>(add1<size_t>(subtract(forest_rows, row))));
};

// NONSTANDARD TEST (non-declarative).
for (uint8_t forest_rows = 1; forest_rows < 64; ++forest_rows)
{
const auto top = sub1(sub1(shift_left<uint64_t>(2, forest_rows)));
success &= (detect_row(top, forest_rows) == forest_rows);

for (uint8_t row = 0; row < forest_rows; ++row)
{
const auto offset = row_offset(row, forest_rows);
success &= (detect_row(offset, forest_rows) == row);
}
}

return success;
};

static_assert(test_detect_row_());
BOOST_REQUIRE(test_detect_row_());
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L359
BOOST_AUTO_TEST_CASE(utreexo__root_position__various__expected)
{
static_assert(root_position(5, 2, 3) == 12_u64);
static_assert(root_position(5, 0, 3) == 4_u64);
BOOST_REQUIRE_EQUAL(root_position(5, 2, 3), 12_u64);
BOOST_REQUIRE_EQUAL(root_position(5, 0, 3), 4_u64);
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L391
BOOST_AUTO_TEST_CASE(utreexo__remove_bit__various__expected)
{
static_assert(remove_bit(15, 2) == 7);
static_assert(remove_bit(14, 1) == 6);
static_assert(remove_bit(10, 0) == 5);
BOOST_REQUIRE_EQUAL(remove_bit(15, 2), 7_u64);
BOOST_REQUIRE_EQUAL(remove_bit(14, 1), 6_u64);
BOOST_REQUIRE_EQUAL(remove_bit(10, 0), 5_u64);
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L482
BOOST_AUTO_TEST_CASE(utreexo__calculate_next__various__expected)
{
constexpr auto calculate_next_ =
[](uint64_t a, uint64_t b, uint8_t c, uint64_t expected) NOEXCEPT
{
uint64_t next{};
return calculate_next(next, a, b, c) && (next == expected);
};

static_assert(calculate_next_(0, 1, 3, 8));
static_assert(calculate_next_(1, 9, 3, 9));

uint64_t next{};
BOOST_REQUIRE(calculate_next(next, 0, 1, 3) && next == 8);
BOOST_REQUIRE(calculate_next(next, 1, 9, 3) && next == 9);
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/util.rs#L406
BOOST_AUTO_TEST_CASE(utreexo__detwin__various__expected)
{
// 14
// |---------------\
// 12 13
// |-------\ |-------\
// 8 9 10 11
// |---\ |---\ |---\ |---\
// 0 1 2 3 4 5 6 7

const positions expected1{ 7, 8, 10 };
positions targets1{ 0, 1, 4, 5, 7 };
detwin(targets1, 3);
BOOST_REQUIRE_EQUAL(targets1, expected1);

const positions expected2{ 4, 6, 12 };
positions targets2{ 4, 6, 8, 9 };
detwin(targets2, 3);
BOOST_REQUIRE_EQUAL(targets2, expected2);
}

// rustreexo examples
// -------------------------------------------------------------------------------------------

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/node_hash.rs#L260
BOOST_AUTO_TEST_CASE(utreexo__node_hash__rustreexo_example__expected)
{
constexpr auto left = base16_array("0000000000000000000000000000000000000000000000000000000000000000");
constexpr auto right = base16_array("0101010101010101010101010101010101010101010101010101010101010101");
constexpr auto expected = base16_array("34e33ca0c40b7bd33d28932ca9e35170def7309a3bf91ecda5e1ceb067548a12");
static_assert(parent_hash(left, right) == expected);
BOOST_REQUIRE_EQUAL(parent_hash(left, right), expected);
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/node_hash.rs#L346
BOOST_AUTO_TEST_CASE(utreexo__empty_hash__rustreexo_example__expected)
{
constexpr auto expected = base16_array("0000000000000000000000000000000000000000000000000000000000000000");
static_assert(empty_hash == expected);
BOOST_REQUIRE_EQUAL(empty_hash, expected);
}

// github.com/mit-dci/rustreexo/blob/main/src/accumulator/node_hash.rs#L338
BOOST_AUTO_TEST_CASE(utreexo__hash_from_u8__rustreexo_example__expected)
{
constexpr auto expected = base16_array("6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d");
static_assert(hash_from_u8(0) == expected);
BOOST_REQUIRE_EQUAL(hash_from_u8(0), expected);
}

BOOST_AUTO_TEST_SUITE_END()
375 changes: 375 additions & 0 deletions test/utreexo/utreexo.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,375 @@
/**
* Copyright (c) 2011-2024 libbitcoin developers (see AUTHORS)
*
* This file is part of libbitcoin.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBBITCOIN_SYSTEM_UTREEXO_HPP
#define LIBBITCOIN_SYSTEM_UTREEXO_HPP

#include <bit>
#include <utility>
#include <bitcoin/system.hpp>

namespace libbitcoin {
namespace system {
namespace utreexo {

using node_hash = hash_digest;
using positions = std::vector<uint64_t>;
constexpr auto empty_hash = node_hash{};

constexpr std::pair<bool, std::string> okay(bool result) NOEXCEPT
{
return { result, (result ? "success" : "fail") };
}

constexpr node_hash parent_hash(const node_hash& left,
const node_hash& right) NOEXCEPT
{
return sha512_256::hash(left, right);
}

constexpr node_hash hash_from_u8(uint8_t byte) NOEXCEPT
{
return sha256::hash(byte);
}

// TODO: test.
// return parent position of passed-in child
constexpr uint64_t parent(uint64_t position, uint8_t forest_rows) NOEXCEPT
{
return set_right(shift_right(position), forest_rows);
}

constexpr uint64_t children(uint64_t position, uint8_t forest_rows) NOEXCEPT
{
const auto mask = unmask_right<uint64_t>(add1<size_t>(forest_rows));
return bit_and(shift_left(position), mask);
}

// TODO: test.
constexpr uint64_t left_child(uint64_t position, uint8_t forest_rows) NOEXCEPT
{
return children(position, forest_rows);
}

// TODO: test.
constexpr uint64_t right_child(uint64_t position, uint8_t forest_rows) NOEXCEPT
{
BC_ASSERT(!is_add_overflow<uint64_t>(children(position, forest_rows), one));

return add1(children(position, forest_rows));
}

constexpr uint64_t left_sibling(uint64_t position) NOEXCEPT
{
return set_right(position, zero, false);
}

constexpr bool is_left_niece(uint64_t position) NOEXCEPT
{
return !get_right(position);
}

constexpr bool is_right_sibling(uint64_t node, uint64_t next) NOEXCEPT
{
return set_right(node) == next;
}

constexpr bool is_sibling(uint64_t node1, uint64_t node2) NOEXCEPT
{
return bit_xor<uint64_t>(node1, one) == node2;
}

// NOTE: parameters reversed from example.
constexpr bool is_root_populated(uint64_t leaves, uint8_t row) NOEXCEPT
{
return get_right(leaves, row);
}

constexpr uint8_t detect_row(uint64_t position, uint8_t forest_rows) NOEXCEPT
{
auto bit = forest_rows;
while (!is_zero(bit) && get_right(position, bit)) --bit;
return subtract(forest_rows, bit);
}

constexpr uint64_t root_position(uint64_t leaves, uint8_t row,
uint8_t forest_rows) NOEXCEPT
{
// TODO: undefined behavior if given row does not have a root.
BC_ASSERT(!is_add_overflow<uint8_t>(row, 1));
BC_ASSERT(!is_add_overflow<uint8_t>(forest_rows, 1));
BC_ASSERT(!is_subtract_overflow<uint8_t>(add1(forest_rows), row));

// sub1 cannot overflow here.
const auto mask = unmask_right<uint64_t>(add1(forest_rows));
const auto before = bit_and(leaves, shift_left(mask, add1(row)));
const auto left = shift_left(mask, subtract(add1(forest_rows), row));
const auto right = shift_right(before, row);
const auto shifted = bit_or(left, right);
return bit_and(shifted, mask);
}

constexpr bool is_root_position(uint64_t position, uint64_t leaves,
uint8_t forest_rows) NOEXCEPT
{
const auto row = detect_row(position, forest_rows);
const auto present = get_right(leaves, row);
const auto expected = root_position(leaves, row, forest_rows);
return present && (position == expected);
}

constexpr uint64_t remove_bit(uint64_t value, size_t bit) NOEXCEPT
{
const auto mask_lo = mask_right<uint64_t>(add1(bit));
const auto mask_hi = unmask_right<uint64_t>(bit);
return bit_or(shift_right(bit_and(value, mask_lo), 1),
bit_and(value, mask_hi));
}

constexpr bool calculate_next(uint64_t& out, uint64_t position,
uint64_t delete_position, uint8_t forest_rows) NOEXCEPT
{
const auto position_row = detect_row(position, forest_rows);
const auto delete_row = detect_row(delete_position, forest_rows);
if (delete_row < position_row)
return false;

const auto bit = subtract<uint64_t>(delete_row, position_row);
const auto lo = remove_bit(position, bit);

const auto row = add1(position_row);
const auto hi = shift_left(bit_right<uint64_t>(row),
subtract(forest_rows, row));

out = bit_or(hi, lo);
return true;
}

constexpr uint64_t start_position_at_row(uint8_t row,
uint8_t forest_rows) NOEXCEPT
{
// Second subtraction cannot overflow if this one does not.
BC_ASSERT(!is_subtract_overflow(forest_rows, row));

return subtract(
bit_right<uint64_t>(add1<size_t>(forest_rows)),
bit_right<uint64_t>(add1<size_t>(subtract(forest_rows, row))));
}

constexpr size_t number_of_roots(uint64_t leaves) NOEXCEPT
{
return std::popcount(leaves);
}

constexpr uint8_t tree_rows(uint64_t leaves) NOEXCEPT
{
// nothing here can overflow.
return narrow_cast<uint8_t>(is_zero(leaves) ? zero :
subtract(bits<uint64_t>, left_zeros<uint64_t>(sub1(leaves))));
}

inline void detwin(positions& nodes, uint8_t forest_rows) NOEXCEPT
{
if (nodes.empty())
return;

for (auto node = std::next(nodes.begin()); node != nodes.end();)
{
const auto prior = std::prev(node);

if (is_right_sibling(*prior, *node))
{
const auto dad = parent(*prior, forest_rows);
node = nodes.erase(prior, std::next(node));
nodes.push_back(dad);
sort(nodes);
continue;
}

++node;
}
}

} // namespace utreexo
} // namespace system
} // namespace libbitcoin

#endif

////// roots_to_destroy returns the empty roots that get written over after num_adds
////// amount of leaves have been added.
////pub fn roots_to_destroy<Hash: AccumulatorHash>(
//// num_adds: u64,
//// mut num_leaves: u64,
//// orig_roots: &[Hash],
////) -> Vec<u64> {
//// let mut roots = orig_roots.to_vec();
//// let mut deleted = vec![];
//// let mut h = 0;
//// for add in 0..num_adds {
//// while (num_leaves >> h) & 1 == 1 {
//// let root = roots
//// .pop()
//// .expect("If (num_leaves >> h) & 1 == 1, it must have at least one root left");
//// if root.is_empty() {
//// let root_pos =
//// root_position(num_leaves, h, tree_rows(num_leaves + (num_adds - add)));
//// deleted.push(root_pos);
//// }
//// h += 1;
//// }
//// // Just adding a non-zero value to the slice.
//// roots.push(AccumulatorHash::placeholder());
//// num_leaves += 1;
//// }
////
//// deleted
////}

////pub fn detect_offset(pos: u64, num_leaves: u64) -> (u8, u8, u64) {
//// let mut tr = tree_rows(num_leaves);
//// let nr = detect_row(pos, tr);
////
//// let mut bigger_trees: u8 = 0;
//// let mut marker = pos;
////
//// // add trees until you would exceed position of node
////
//// // This is a bit of an ugly predicate. The goal is to detect if we've
//// // gone past the node we're looking for by inspecting progressively shorter
//// // trees; once we have, the loop is over.

//// // The predicate breaks down into 3 main terms:
//// // A: pos << nh
//// // B: mask
//// // C: 1<<th & num_leaves (tree_size)
//// // The predicate is then if (A&B >= C)
//// // A is position up-shifted by the row of the node we're targeting.
//// // B is the "mask" we use in other functions; a bunch of 0s at the MSB side
//// // and then a bunch of 1s on the LSB side, such that we can use bitwise AND
//// // to discard high bits. Together, A&B is shifting position up by nr bits,
//// // and then discarding (zeroing out) the high bits. This is the same as in
//// // n_grandchild. C checks for whether a tree exists at the current tree
//// // rows. If there is no tree at tr, C is 0. If there is a tree, it will
//// // return a power of 2: the base size of that tree.
//// // The C term actually is used 3 times here, which is ugly; it's redefined
//// // right on the next line.
//// // In total, what this loop does is to take a node position, and
//// // see if it's in the next largest tree. If not, then subtract everything
//// // covered by that tree from the position, and proceed to the next tree,
//// // skipping trees that don't exist.

//// while (marker << nr) & ((2 << tr) - 1) >= (1 << tr) & num_leaves {
//// let tree_size = (1 << tr) & num_leaves;
//// if tree_size != 0 {
//// marker -= tree_size;
//// bigger_trees += 1;
//// }
//// tr -= 1;
//// }
////
//// (bigger_trees, tr - nr, !marker)
////}

/////// max_position_at_row returns the biggest position an accumulator can have for the
/////// requested row for the given num_leaves.
////pub fn max_position_at_row(row: u8, total_rows: u8, num_leaves: u64) -> Result<u64, String> {
//// Ok(parent_many(num_leaves, row, total_rows)?.saturating_sub(1))
////}
////
////pub fn read_u64<Source: Read>(buf: &mut Source) -> Result<u64, String> {
//// let mut bytes = [0u8; 8];
//// buf.read_exact(&mut bytes)
//// .map_err(|_| "Failed to read u64")?;
//// Ok(u64::from_le_bytes(bytes))
////}

////pub fn parent_many(pos: u64, rise: u8, forest_rows: u8) -> Result<u64, String> {
//// if rise == 0 {
//// return Ok(pos);
//// }
//// if rise > forest_rows {
//// return Err(format!(
//// "Cannot rise more than the forestRows: rise: {} forest_rows: {}",
//// rise, forest_rows
//// ));
//// }
////
//// let mask = (2_u64 << forest_rows) - 1;
//// Ok((pos >> rise | (mask << (forest_rows - (rise - 1)) as u64)) & mask)
////}

////std::pair<bool, std::string> is_ancestor(uint64_t higher_pos,
//// uint64_t lower_pos, uint8_t forest_rows)
////{
//// if (higher_pos == lower_pos)
//// return okay(false);
////
//// auto lower_row = detect_row(lower_pos, forest_rows);
//// auto higher_row = detect_row(higher_pos, forest_rows);
////
//// // Prevent underflows by checking that the higherRow is not less than lowerRow.
//// if (higher_row < lower_row)
//// return okay(false);
////
//// // TODO: Return false if we error out or the calculated ancestor doesn't match the higherPos.
//// auto ancestor = parent_many(lower_pos, higher_row - lower_row, forest_rows);
////
//// return (higher_pos == ancestor);
////}

/////// Returns which node should have its hashes on the proof, along with all nodes
/////// whose hashes will be calculated to reach a root
////Vec<u64> get_proof_positions(targets: &[u64], num_leaves: u64, forest_rows: u8) NOEXCEPT
////{
//// let mut proof_positions = vec![];
//// let mut computed_positions = targets.to_vec();
//// computed_positions.sort();
////
//// for row in 0..=forest_rows {
//// let mut row_targets = computed_positions
//// .iter()
//// .cloned()
//// .filter(|x| super::util::detect_row(*x, forest_rows) == row)
//// .collect::<Vec<_>>()
//// .into_iter()
//// .peekable();
////
//// while let Some(node) = row_targets.next() {
//// if is_root_position(node, num_leaves, forest_rows) {
//// continue;
//// }
////
//// if let Some(next) = row_targets.peek() {
//// if !is_sibling(node, *next) {
//// proof_positions.push(node ^ 1);
//// } else {
//// row_targets.next();
//// }
//// } else {
//// proof_positions.push(node ^ 1);
//// }
////
//// computed_positions.push(parent(node, forest_rows));
//// }
////
//// computed_positions.sort();
//// }
////
//// proof_positions
////}