From fcb7222fcb1b79bb52a328c87c39b2eeba5f7927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 12 Sep 2023 22:49:05 +0200 Subject: [PATCH] mpt: Remove ext node type --- test/state/mpt.cpp | 135 +++++++++++++++++---------------------------- 1 file changed, 50 insertions(+), 85 deletions(-) diff --git a/test/state/mpt.cpp b/test/state/mpt.cpp index 8ed563cc2..5bed4773f 100644 --- a/test/state/mpt.cpp +++ b/test/state/mpt.cpp @@ -4,18 +4,18 @@ #include "mpt.hpp" #include "rlp.hpp" -#include #include +#include namespace evmone::state { namespace { + /// The MPT node kind. -enum class Kind : uint8_t +enum class Kind : bool { leaf, - ext, branch }; @@ -52,12 +52,15 @@ struct Path [[nodiscard]] bytes encode(Kind kind) const { + if (kind == Kind::branch && length == 0) + return {}; + const auto is_even = length % 2 == 0; bytes bs{static_cast( (is_even ? 0x00 : (0x10 | nibbles[0])) | (kind == Kind::leaf ? 0x20 : 0x00))}; for (size_t i = is_even ? 0 : 1; i < length; i += 2) bs.push_back(static_cast((nibbles[i] << 4) | nibbles[i + 1])); - return bs; + return rlp::encode(bs); } }; } // namespace @@ -80,24 +83,6 @@ class MPTNode : m_kind{kind}, m_path{path}, m_value{std::move(value)} {} - /// Creates an extended node. - static MPTNode ext(const Path& path, std::unique_ptr child) noexcept - { - assert(child->m_kind == Kind::branch); - MPTNode node{Kind::ext, path}; - node.m_children[0] = std::move(child); - return node; - } - - /// Optionally wraps the child node with newly created extended node in case - /// the provided path is not empty. - static std::unique_ptr optional_ext( - const Path& path, std::unique_ptr child) noexcept - { - return (path.length != 0) ? std::make_unique(ext(path, std::move(child))) : - std::move(child); - } - /// Creates a branch node out of two children and optionally extends it with an extended /// node in case the path is not empty. static MPTNode ext_branch(const Path& path, size_t idx1, std::unique_ptr child1, @@ -107,12 +92,10 @@ class MPTNode assert(idx1 < num_children); assert(idx2 < num_children); - MPTNode br{Kind::branch}; + MPTNode br{Kind::branch, path}; br.m_children[idx1] = std::move(child1); br.m_children[idx2] = std::move(child2); - - return (path.length != 0) ? ext(path, std::make_unique(std::move(br))) : - std::move(br); + return br; } /// The information how two paths are different. @@ -166,38 +149,36 @@ void MPTNode::insert(const Path& path, bytes&& value) // NOLINT(misc-no-recursi // in an existing branch node. Otherwise, we need to create new branch node // (possibly with an adjusted extended node) and transform existing nodes around it. + const auto [head, orig_idx, insert_idx, tail1, tail2] = mismatch(m_path, path); + switch (m_kind) { case Kind::branch: { - assert(m_path.length == 0); // Branch has no path. - - const auto idx = path.nibbles[0]; - auto& child = m_children[idx]; - if (!child) - child = leaf(path.tail(1), std::move(value)); - else - child->insert(path.tail(1), std::move(value)); - break; - } + if (head.length == m_path.length) // Paths match: go into the child. + { + auto& child = m_children[insert_idx]; + if (!child) + child = leaf(tail2, std::move(value)); + else + child->insert(tail2, std::move(value)); + return; + } - case Kind::ext: - { - assert(m_path.length != 0); // Ext must have non-empty path. + // The original branch node must be pushed down, possible extended with + // the adjusted extended node if the path split point is not directly at the branch + // node. Clang Analyzer bug: https://github.com/llvm/llvm-project/issues/47814 + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - const auto [common, orig_idx, insert_idx, orig_tail, insert_tail] = mismatch(m_path, path); + const auto up_branch_path = head; + const auto down_branch_path = tail1; - if (common.length == m_path.length) // Paths match: go into the child. - return m_children[0]->insert(path.tail(common.length), std::move(value)); + auto this_branch = std::move(*this); + this_branch.m_path = down_branch_path; - // The original branch node must be pushed down, possible extended with - // the adjusted extended node if the path split point is not directly at the branch node. - // Clang Analyzer bug: https://github.com/llvm/llvm-project/issues/47814 - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - auto orig_branch = optional_ext(orig_tail, std::move(m_children[0])); - auto new_leaf = leaf(insert_tail, std::move(value)); *this = - ext_branch(common, orig_idx, std::move(orig_branch), insert_idx, std::move(new_leaf)); + ext_branch(up_branch_path, orig_idx, std::make_unique(std::move(this_branch)), + insert_idx, leaf(tail2, std::move(value))); break; } @@ -205,63 +186,47 @@ void MPTNode::insert(const Path& path, bytes&& value) // NOLINT(misc-no-recursi { assert(m_path.length != 0); // Leaf must have non-empty path. - const auto [common, orig_idx, insert_idx, orig_tail, insert_tail] = mismatch(m_path, path); - assert(common.length != m_path.length); // Paths must be different. + assert(head.length != m_path.length); // Paths must be different. - auto orig_leaf = leaf(orig_tail, std::move(m_value)); - auto new_leaf = leaf(insert_tail, std::move(value)); - *this = ext_branch(common, orig_idx, std::move(orig_leaf), insert_idx, std::move(new_leaf)); + auto orig_leaf = leaf(tail1, std::move(m_value)); + auto new_leaf = leaf(tail2, std::move(value)); + *this = ext_branch(head, orig_idx, std::move(orig_leaf), insert_idx, std::move(new_leaf)); break; } - - default: - assert(false); } } -/// Encodes a node and optionally hashes the encoded bytes -/// if their length exceeds the specified threshold. -static bytes encode_child(const MPTNode& child) noexcept // NOLINT(misc-no-recursion) -{ - if (auto e = child.encode(); e.size() < 32) - return e; // "short" node - else - return rlp::encode(keccak256(e)); -} bytes MPTNode::encode() const // NOLINT(misc-no-recursion) { - bytes encoded; + static constexpr auto shorten = [](bytes&& b) { + return (b.size() < 32) ? std::move(b) : rlp::encode(keccak256(b)); + }; + + bytes payload; // the encoded content of the node without its path switch (m_kind) { case Kind::leaf: { - encoded = rlp::encode(m_path.encode(m_kind)) + rlp::encode(m_value); + payload = rlp::encode(m_value); break; } case Kind::branch: { - assert(m_path.length == 0); - static constexpr uint8_t empty = 0x80; // encoded empty child + static constexpr uint8_t Empty = 0x80; // encoded empty child - for (const auto& child : m_children) - { - if (child) - encoded += encode_child(*child); - else - encoded += empty; - } - encoded += empty; // end indicator - break; - } - case Kind::ext: - { - encoded = rlp::encode(m_path.encode(m_kind)) + encode_child(*m_children[0]); + payload = std::accumulate(std::begin(m_children), std::end(m_children), bytes{}, + [](const bytes& encoded, const auto& child) { + return encoded + (child ? shorten(child->encode()) : bytes{Empty}); + }) + + Empty; // children list end indicator + + if (m_path.length != 0) // extended node + payload = shorten(rlp::internal::wrap_list(payload)); break; } } - - return rlp::internal::wrap_list(encoded); + return rlp::internal::wrap_list(m_path.encode(m_kind) + payload); }