From 4ad94ae2ff5c3845bb308e93eb49a140f2d0cb23 Mon Sep 17 00:00:00 2001 From: Valentin Balaschenko <13349202+vlntb@users.noreply.github.com> Date: Wed, 13 May 2026 14:53:01 +0100 Subject: [PATCH] refactor: Use named constant for leaf item size (#39) (#7130) Co-authored-by: Ed Hennis --- include/xrpl/shamap/SHAMapTreeNode.h | 4 +++ src/libxrpl/shamap/SHAMapLeafNode.cpp | 4 +-- src/libxrpl/shamap/SHAMapTreeNode.cpp | 45 ++++++++++++++++++++++++--- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/include/xrpl/shamap/SHAMapTreeNode.h b/include/xrpl/shamap/SHAMapTreeNode.h index d50fc65ccb..ac48df8d46 100644 --- a/include/xrpl/shamap/SHAMapTreeNode.h +++ b/include/xrpl/shamap/SHAMapTreeNode.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -20,6 +21,9 @@ static constexpr unsigned char const kWIRE_TYPE_INNER = 2; static constexpr unsigned char const kWIRE_TYPE_COMPRESSED_INNER = 3; static constexpr unsigned char const kWIRE_TYPE_TRANSACTION_WITH_META = 4; +// Lower bound on SHAMap leaf item payload size, in bytes. +inline constexpr std::size_t kMIN_SHA_MAP_ITEM_BYTES = 12; + enum class SHAMapNodeType { TnInner = 1, TnTransactionNm = 2, // transaction, no metadata diff --git a/src/libxrpl/shamap/SHAMapLeafNode.cpp b/src/libxrpl/shamap/SHAMapLeafNode.cpp index ce41a64e56..84c4498698 100644 --- a/src/libxrpl/shamap/SHAMapLeafNode.cpp +++ b/src/libxrpl/shamap/SHAMapLeafNode.cpp @@ -19,7 +19,7 @@ SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr item, std: : SHAMapTreeNode(cowid), item_(std::move(item)) { XRPL_ASSERT( - item_->size() >= 12, + item_->size() >= kMIN_SHA_MAP_ITEM_BYTES, "xrpl::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" "SHAMapItem const>, std::uint32_t) : minimum input size"); } @@ -31,7 +31,7 @@ SHAMapLeafNode::SHAMapLeafNode( : SHAMapTreeNode(cowid, hash), item_(std::move(item)) { XRPL_ASSERT( - item_->size() >= 12, + item_->size() >= kMIN_SHA_MAP_ITEM_BYTES, "xrpl::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" "SHAMapItem const>, std::uint32_t, SHAMapHash const&) : minimum input " "size"); diff --git a/src/libxrpl/shamap/SHAMapTreeNode.cpp b/src/libxrpl/shamap/SHAMapTreeNode.cpp index ac405f3286..66eced2192 100644 --- a/src/libxrpl/shamap/SHAMapTreeNode.cpp +++ b/src/libxrpl/shamap/SHAMapTreeNode.cpp @@ -28,6 +28,13 @@ namespace xrpl { intr_ptr::SharedPtr SHAMapTreeNode::makeTransaction(Slice data, SHAMapHash const& hash, bool hashValid) { + if (data.size() < kMIN_SHA_MAP_ITEM_BYTES) + { + Throw( + "Short TXN node: " + std::to_string(data.size()) + " bytes (minimum " + + std::to_string(kMIN_SHA_MAP_ITEM_BYTES) + " required)"); + } + auto item = makeShamapitem(sha512Half(HashPrefix::TransactionId, data), data); if (hashValid) @@ -44,14 +51,30 @@ SHAMapTreeNode::makeTransactionWithMeta(Slice data, SHAMapHash const& hash, bool uint256 tag; if (s.size() < tag.kBYTES) - Throw("Short TXN+MD node"); + { + Throw( + "Short TXN+MD node: " + std::to_string(s.size()) + " bytes (minimum " + + std::to_string(tag.kBYTES) + " required for tag)"); + } // FIXME: improve this interface so that the above check isn't needed if (!s.getBitString(tag, s.size() - tag.kBYTES)) - Throw("Short TXN+MD node (" + std::to_string(s.size()) + ")"); + { + Throw( + "Short TXN+MD node: failed to read tag at offset " + + std::to_string(s.size() - tag.kBYTES)); + } s.chop(tag.kBYTES); + if (s.size() < kMIN_SHA_MAP_ITEM_BYTES) + { + Throw( + "Short TXN+MD node: " + std::to_string(s.size()) + + " bytes after tag removal (minimum " + std::to_string(kMIN_SHA_MAP_ITEM_BYTES) + + " required)"); + } + auto item = makeShamapitem(tag, s.slice()); if (hashValid) @@ -68,17 +91,31 @@ SHAMapTreeNode::makeAccountState(Slice data, SHAMapHash const& hash, bool hashVa uint256 tag; if (s.size() < tag.kBYTES) - Throw("short AS node"); + { + Throw( + "Short AS node: " + std::to_string(s.size()) + " bytes (minimum " + + std::to_string(tag.kBYTES) + " required for tag)"); + } // FIXME: improve this interface so that the above check isn't needed if (!s.getBitString(tag, s.size() - tag.kBYTES)) - Throw("Short AS node (" + std::to_string(s.size()) + ")"); + { + Throw( + "Short AS node: failed to read tag at offset " + std::to_string(s.size() - tag.kBYTES)); + } s.chop(tag.kBYTES); if (tag.isZero()) Throw("Invalid AS node"); + if (s.size() < kMIN_SHA_MAP_ITEM_BYTES) + { + Throw( + "Short AS node: " + std::to_string(s.size()) + " bytes after tag removal (minimum " + + std::to_string(kMIN_SHA_MAP_ITEM_BYTES) + " required)"); + } + auto item = makeShamapitem(tag, s.slice()); if (hashValid)