From e9e5e61cb73ed8cdd23fa26ff68e438c7bf50f67 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 11 Apr 2024 18:26:57 -0400 Subject: [PATCH 1/2] Rename :is_malleable32_size to :is_malleable32, style. --- include/bitcoin/system/chain/block.hpp | 5 +- src/chain/block.cpp | 4 +- test/chain/block_malleable.cpp | 210 ++++++++++++------------- 3 files changed, 109 insertions(+), 110 deletions(-) diff --git a/include/bitcoin/system/chain/block.hpp b/include/bitcoin/system/chain/block.hpp index f3657db684..696846fff4 100644 --- a/include/bitcoin/system/chain/block.hpp +++ b/include/bitcoin/system/chain/block.hpp @@ -121,13 +121,12 @@ class BC_API block size_t malleated32_size() const NOEXCEPT; bool is_malleated32(size_t width) const NOEXCEPT; - static constexpr bool is_malleable32_size(size_t set, size_t width) NOEXCEPT + static constexpr bool is_malleable32(size_t set, size_t width) NOEXCEPT { // Malleable when set is odd at width depth and not before and not one. // This is the only case in which Merkle clones the last item in a set. for (auto depth = one; depth <= width; depth *= two, set = to_half(set)) - if (is_odd(set)) - return depth == width && !is_one(set); + if (is_odd(set)) return depth == width && !is_one(set); return false; } diff --git a/src/chain/block.cpp b/src/chain/block.cpp index 055384f74b..153ae07017 100644 --- a/src/chain/block.cpp +++ b/src/chain/block.cpp @@ -447,7 +447,7 @@ bool block::is_malleable32() const NOEXCEPT { const auto unmalleated = txs_->size(); for (auto mally = one; mally <= unmalleated; mally *= two) - if (is_malleable32_size(unmalleated, mally)) + if (is_malleable32(unmalleated, mally)) return true; return false; @@ -464,7 +464,7 @@ size_t block::malleated32_size() const NOEXCEPT { const auto malleated = txs_->size(); for (auto mally = one; mally <= to_half(malleated); mally *= two) - if (is_malleable32_size(malleated - mally, mally) && + if (is_malleable32(malleated - mally, mally) && is_malleated32(mally)) return mally; diff --git a/test/chain/block_malleable.cpp b/test/chain/block_malleable.cpp index 9a3a99cdb5..ac09f5cce7 100644 --- a/test/chain/block_malleable.cpp +++ b/test/chain/block_malleable.cpp @@ -51,10 +51,10 @@ class accessor return block::is_malleated32(width); } - static constexpr bool is_malleable32_size(size_t set, + static constexpr bool is_malleable32_(size_t set, size_t width) NOEXCEPT { - return block::is_malleable32_size(set, width); + return block::is_malleable32(set, width); } }; @@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(block__malleable__empty__false) BOOST_REQUIRE(!instance.is_malleable()); BOOST_REQUIRE(!instance.is_malleable64()); BOOST_REQUIRE(!instance.is_malleable32()); - BOOST_REQUIRE(!instance.is_malleable32_size(0, 0)); + BOOST_REQUIRE(!instance.is_malleable32_(0, 0)); BOOST_REQUIRE(!instance.is_malleated32()); BOOST_REQUIRE(!instance.is_malleated32_(0)); } @@ -299,112 +299,112 @@ BOOST_AUTO_TEST_CASE(block__is_malleable64__three_64_64_64__true) BOOST_REQUIRE(instance.is_malleable64()); } -// is_malleable32_size +// is_malleable32 -BOOST_AUTO_TEST_CASE(block__is_malleable32_size__overflow__false) +BOOST_AUTO_TEST_CASE(block__is_malleable32__overflow__false) { - BOOST_REQUIRE(!accessor::is_malleable32_size(0, 1)); - BOOST_REQUIRE(!accessor::is_malleable32_size(1, 50)); - BOOST_REQUIRE(!accessor::is_malleable32_size(2, 100)); + BOOST_REQUIRE(!accessor::is_malleable32_(0, 1)); + BOOST_REQUIRE(!accessor::is_malleable32_(1, 50)); + BOOST_REQUIRE(!accessor::is_malleable32_(2, 100)); } -BOOST_AUTO_TEST_CASE(block__is_malleable32_size__various__expected) -{ - BOOST_REQUIRE(!accessor::is_malleable32_size(1, 1)); - - BOOST_REQUIRE(!accessor::is_malleable32_size(2, 1)); - BOOST_REQUIRE(!accessor::is_malleable32_size(2, 2)); - - BOOST_REQUIRE(accessor::is_malleable32_size(3, 1)); // 4:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(3, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(3, 3)); - - BOOST_REQUIRE(!accessor::is_malleable32_size(4, 1)); - BOOST_REQUIRE(!accessor::is_malleable32_size(4, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(4, 3)); - BOOST_REQUIRE(!accessor::is_malleable32_size(4, 4)); - - BOOST_REQUIRE(accessor::is_malleable32_size(5, 1)); // 6:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(5, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(5, 3)); - BOOST_REQUIRE(!accessor::is_malleable32_size(5, 4)); - BOOST_REQUIRE(!accessor::is_malleable32_size(5, 5)); - - BOOST_REQUIRE(!accessor::is_malleable32_size(6, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(6, 2)); // 8:2 - BOOST_REQUIRE(!accessor::is_malleable32_size(6, 3)); - BOOST_REQUIRE(!accessor::is_malleable32_size(6, 4)); - BOOST_REQUIRE(!accessor::is_malleable32_size(6, 5)); - BOOST_REQUIRE(!accessor::is_malleable32_size(6, 6)); - - BOOST_REQUIRE(accessor::is_malleable32_size(7, 1)); // 8:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(7, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(7, 3)); - BOOST_REQUIRE(!accessor::is_malleable32_size(7, 4)); - BOOST_REQUIRE(!accessor::is_malleable32_size(7, 5)); - BOOST_REQUIRE(!accessor::is_malleable32_size(7, 6)); - BOOST_REQUIRE(!accessor::is_malleable32_size(7, 7)); - - BOOST_REQUIRE(!accessor::is_malleable32_size(8, 1)); - BOOST_REQUIRE(!accessor::is_malleable32_size(8, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(8, 3)); - BOOST_REQUIRE(!accessor::is_malleable32_size(8, 4)); - BOOST_REQUIRE(!accessor::is_malleable32_size(8, 5)); - BOOST_REQUIRE(!accessor::is_malleable32_size(8, 6)); - BOOST_REQUIRE(!accessor::is_malleable32_size(8, 7)); - BOOST_REQUIRE(!accessor::is_malleable32_size(8, 8)); - - BOOST_REQUIRE(accessor::is_malleable32_size(9, 1)); // 10:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(9, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(9, 3)); - BOOST_REQUIRE(!accessor::is_malleable32_size(9, 4)); - BOOST_REQUIRE(!accessor::is_malleable32_size(9, 5)); - BOOST_REQUIRE(!accessor::is_malleable32_size(9, 6)); - BOOST_REQUIRE(!accessor::is_malleable32_size(9, 7)); - BOOST_REQUIRE(!accessor::is_malleable32_size(9, 8)); - BOOST_REQUIRE(!accessor::is_malleable32_size(9, 9)); - - BOOST_REQUIRE(!accessor::is_malleable32_size(10, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(10, 2)); // 12:2 - BOOST_REQUIRE(!accessor::is_malleable32_size(10, 3)); - BOOST_REQUIRE(accessor::is_malleable32_size(11, 1)); // 12:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(11, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(12, 1)); - BOOST_REQUIRE(!accessor::is_malleable32_size(12, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(12, 3)); - BOOST_REQUIRE(accessor::is_malleable32_size(12, 4)); // 16:4 - BOOST_REQUIRE(accessor::is_malleable32_size(13, 1)); // 14:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(13, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(14, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(14, 2)); // 16:2 - BOOST_REQUIRE(!accessor::is_malleable32_size(14, 3)); - BOOST_REQUIRE(accessor::is_malleable32_size(15, 1)); // 16:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(16, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(17, 1)); // 18:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(18, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(18, 2)); // 20:2 - BOOST_REQUIRE(accessor::is_malleable32_size(19, 1)); // 20:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(20, 1)); - BOOST_REQUIRE(!accessor::is_malleable32_size(20, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(20, 3)); - BOOST_REQUIRE(accessor::is_malleable32_size(20, 4)); // 24:4 - BOOST_REQUIRE(accessor::is_malleable32_size(21, 1)); // 22:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(22, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(22, 2)); // 24:2 - BOOST_REQUIRE(accessor::is_malleable32_size(23, 1)); // 24:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(24, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(25, 1)); // 26:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(26, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(26, 2)); // 28:2 - BOOST_REQUIRE(accessor::is_malleable32_size(27, 1)); // 28:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(28, 1)); - BOOST_REQUIRE(!accessor::is_malleable32_size(28, 2)); - BOOST_REQUIRE(!accessor::is_malleable32_size(28, 3)); - BOOST_REQUIRE(accessor::is_malleable32_size(28, 4)); // 32:4 - BOOST_REQUIRE(accessor::is_malleable32_size(29, 1)); // 30:1 - BOOST_REQUIRE(!accessor::is_malleable32_size(30, 1)); - BOOST_REQUIRE(accessor::is_malleable32_size(30, 2)); // 32:2 - BOOST_REQUIRE(accessor::is_malleable32_size(31, 1)); // 32:1 +BOOST_AUTO_TEST_CASE(block__is_malleable32__various__expected) +{ + BOOST_REQUIRE(!accessor::is_malleable32_(1, 1)); + + BOOST_REQUIRE(!accessor::is_malleable32_(2, 1)); + BOOST_REQUIRE(!accessor::is_malleable32_(2, 2)); + + BOOST_REQUIRE( accessor::is_malleable32_(3, 1)); // 4:1 + BOOST_REQUIRE(!accessor::is_malleable32_(3, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(3, 3)); + + BOOST_REQUIRE(!accessor::is_malleable32_(4, 1)); + BOOST_REQUIRE(!accessor::is_malleable32_(4, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(4, 3)); + BOOST_REQUIRE(!accessor::is_malleable32_(4, 4)); + + BOOST_REQUIRE( accessor::is_malleable32_(5, 1)); // 6:1 + BOOST_REQUIRE(!accessor::is_malleable32_(5, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(5, 3)); + BOOST_REQUIRE(!accessor::is_malleable32_(5, 4)); + BOOST_REQUIRE(!accessor::is_malleable32_(5, 5)); + + BOOST_REQUIRE(!accessor::is_malleable32_(6, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(6, 2)); // 8:2 + BOOST_REQUIRE(!accessor::is_malleable32_(6, 3)); + BOOST_REQUIRE(!accessor::is_malleable32_(6, 4)); + BOOST_REQUIRE(!accessor::is_malleable32_(6, 5)); + BOOST_REQUIRE(!accessor::is_malleable32_(6, 6)); + + BOOST_REQUIRE( accessor::is_malleable32_(7, 1)); // 8:1 + BOOST_REQUIRE(!accessor::is_malleable32_(7, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(7, 3)); + BOOST_REQUIRE(!accessor::is_malleable32_(7, 4)); + BOOST_REQUIRE(!accessor::is_malleable32_(7, 5)); + BOOST_REQUIRE(!accessor::is_malleable32_(7, 6)); + BOOST_REQUIRE(!accessor::is_malleable32_(7, 7)); + + BOOST_REQUIRE(!accessor::is_malleable32_(8, 1)); + BOOST_REQUIRE(!accessor::is_malleable32_(8, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(8, 3)); + BOOST_REQUIRE(!accessor::is_malleable32_(8, 4)); + BOOST_REQUIRE(!accessor::is_malleable32_(8, 5)); + BOOST_REQUIRE(!accessor::is_malleable32_(8, 6)); + BOOST_REQUIRE(!accessor::is_malleable32_(8, 7)); + BOOST_REQUIRE(!accessor::is_malleable32_(8, 8)); + + BOOST_REQUIRE( accessor::is_malleable32_(9, 1)); // 10:1 + BOOST_REQUIRE(!accessor::is_malleable32_(9, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(9, 3)); + BOOST_REQUIRE(!accessor::is_malleable32_(9, 4)); + BOOST_REQUIRE(!accessor::is_malleable32_(9, 5)); + BOOST_REQUIRE(!accessor::is_malleable32_(9, 6)); + BOOST_REQUIRE(!accessor::is_malleable32_(9, 7)); + BOOST_REQUIRE(!accessor::is_malleable32_(9, 8)); + BOOST_REQUIRE(!accessor::is_malleable32_(9, 9)); + + BOOST_REQUIRE(!accessor::is_malleable32_(10, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(10, 2)); // 12:2 + BOOST_REQUIRE(!accessor::is_malleable32_(10, 3)); + BOOST_REQUIRE( accessor::is_malleable32_(11, 1)); // 12:1 + BOOST_REQUIRE(!accessor::is_malleable32_(11, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(12, 1)); + BOOST_REQUIRE(!accessor::is_malleable32_(12, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(12, 3)); + BOOST_REQUIRE( accessor::is_malleable32_(12, 4)); // 16:4 + BOOST_REQUIRE( accessor::is_malleable32_(13, 1)); // 14:1 + BOOST_REQUIRE(!accessor::is_malleable32_(13, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(14, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(14, 2)); // 16:2 + BOOST_REQUIRE(!accessor::is_malleable32_(14, 3)); + BOOST_REQUIRE( accessor::is_malleable32_(15, 1)); // 16:1 + BOOST_REQUIRE(!accessor::is_malleable32_(16, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(17, 1)); // 18:1 + BOOST_REQUIRE(!accessor::is_malleable32_(18, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(18, 2)); // 20:2 + BOOST_REQUIRE( accessor::is_malleable32_(19, 1)); // 20:1 + BOOST_REQUIRE(!accessor::is_malleable32_(20, 1)); + BOOST_REQUIRE(!accessor::is_malleable32_(20, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(20, 3)); + BOOST_REQUIRE( accessor::is_malleable32_(20, 4)); // 24:4 + BOOST_REQUIRE( accessor::is_malleable32_(21, 1)); // 22:1 + BOOST_REQUIRE(!accessor::is_malleable32_(22, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(22, 2)); // 24:2 + BOOST_REQUIRE( accessor::is_malleable32_(23, 1)); // 24:1 + BOOST_REQUIRE(!accessor::is_malleable32_(24, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(25, 1)); // 26:1 + BOOST_REQUIRE(!accessor::is_malleable32_(26, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(26, 2)); // 28:2 + BOOST_REQUIRE( accessor::is_malleable32_(27, 1)); // 28:1 + BOOST_REQUIRE(!accessor::is_malleable32_(28, 1)); + BOOST_REQUIRE(!accessor::is_malleable32_(28, 2)); + BOOST_REQUIRE(!accessor::is_malleable32_(28, 3)); + BOOST_REQUIRE( accessor::is_malleable32_(28, 4)); // 32:4 + BOOST_REQUIRE( accessor::is_malleable32_(29, 1)); // 30:1 + BOOST_REQUIRE(!accessor::is_malleable32_(30, 1)); + BOOST_REQUIRE( accessor::is_malleable32_(30, 2)); // 32:2 + BOOST_REQUIRE( accessor::is_malleable32_(31, 1)); // 32:1 } BOOST_AUTO_TEST_SUITE_END() From dbdbacc07e9fc21283159f1d57399bb575e78614 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 11 Apr 2024 18:52:45 -0400 Subject: [PATCH 2/2] Add static bool is_malleable64(txs). --- include/bitcoin/system/chain/block.hpp | 2 ++ src/chain/block.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/bitcoin/system/chain/block.hpp b/include/bitcoin/system/chain/block.hpp index 696846fff4..0a8e865e48 100644 --- a/include/bitcoin/system/chain/block.hpp +++ b/include/bitcoin/system/chain/block.hpp @@ -44,6 +44,8 @@ class BC_API block typedef std_vector sizes; typedef std::shared_ptr cptr; + static bool is_malleable64(const transaction_cptrs& txs) NOEXCEPT; + /// Constructors. /// ----------------------------------------------------------------------- diff --git a/src/chain/block.cpp b/src/chain/block.cpp index 153ae07017..8627c620a8 100644 --- a/src/chain/block.cpp +++ b/src/chain/block.cpp @@ -488,16 +488,22 @@ bool block::is_malleated32(size_t width) const NOEXCEPT return true; } +bool block::is_malleable64() const NOEXCEPT +{ + return is_malleable64(*txs_); +} + +// static // If all non-witness tx serializations are 64 bytes the id is malleable. // This form of malleability does not imply current block instance is invalid. -bool block::is_malleable64() const NOEXCEPT +bool block::is_malleable64(const transaction_cptrs& txs) NOEXCEPT { const auto two_leaves = [](const transaction::cptr& tx) NOEXCEPT { return tx->serialized_size(false) == two * hash_size; }; - return !is_empty() && std::all_of(txs_->begin(), txs_->end(), two_leaves); + return !txs.empty() && std::all_of(txs.begin(), txs.end(), two_leaves); } bool block::is_segregated() const NOEXCEPT