Skip to content

Commit

Permalink
mpt: Remove ext node type
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Dec 20, 2023
1 parent 65c369a commit 75ec69a
Showing 1 changed file with 34 additions and 72 deletions.
106 changes: 34 additions & 72 deletions test/state/mpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ namespace evmone::state
{
namespace
{

/// The MPT node kind.
enum class Kind : uint8_t
enum class Kind : bool
{
leaf,
ext,
branch
};

Expand Down Expand Up @@ -53,12 +53,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<uint8_t>(
(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<uint8_t>((nibbles[i] << 4) | nibbles[i + 1]));
return bs;
return rlp::encode(bs);
}
};
} // namespace
Expand All @@ -81,24 +84,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<MPTNode> 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<MPTNode> optional_ext(
const Path& path, std::unique_ptr<MPTNode> child) noexcept
{
return (path.length != 0) ? std::make_unique<MPTNode>(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<MPTNode> child1,
Expand All @@ -108,12 +93,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<MPTNode>(std::move(br))) :
std::move(br);
return br;
}

/// The information how two paths are different.
Expand Down Expand Up @@ -175,28 +158,24 @@ void MPTNode::insert(const Path& path, bytes&& value) // NOLINT(misc-no-recursi
{
case Kind::branch:
{
assert(m_path.length == 0); // Branch has no path.
if (auto& child = m_children[insert_idx]; child)
child->insert(insert_tail, std::move(value));
else
child = leaf(insert_tail, std::move(value));
break;
}

case Kind::ext:
{
assert(m_path.length != 0); // Ext must have non-empty path.
if (common.length == m_path.length) // Paths match: go into the child.
return m_children[0]->insert(path.tail(common.length), std::move(value));
{
if (auto& child = m_children[insert_idx]; child)
child->insert(insert_tail, std::move(value));
else
child = leaf(insert_tail, std::move(value));
return;
}

// 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
// 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 this_branch = optional_ext(this_tail, std::move(m_children[0]));
auto new_leaf = leaf(insert_tail, std::move(value));
*this =
ext_branch(common, this_idx, std::move(this_branch), insert_idx, std::move(new_leaf));

m_path = this_tail; // Shorten path of this node and push the node down.

*this = ext_branch(common, this_idx, std::make_unique<MPTNode>(std::move(*this)),
insert_idx, leaf(insert_tail, std::move(value)));
break;
}

Expand All @@ -209,55 +188,38 @@ void MPTNode::insert(const Path& path, bytes&& value) // NOLINT(misc-no-recursi
*this = ext_branch(common, this_idx, std::move(this_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

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 += child ? shorten(child->encode()) : bytes{empty};
payload += empty; // 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);
}


Expand Down

0 comments on commit 75ec69a

Please sign in to comment.