Skip to content

Commit

Permalink
feat: implement MPT
Browse files Browse the repository at this point in the history
  • Loading branch information
x-mass committed Aug 15, 2024
1 parent 230ea44 commit 39c515f
Show file tree
Hide file tree
Showing 11 changed files with 1,118 additions and 7 deletions.
4 changes: 2 additions & 2 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions libs/nil_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
message(FATAL_ERROR "NilCore library can be built only with GCC 13+")
endif()

add_library(${LIBRARY_NAME} INTERFACE)
add_library(${LIBRARY_NAME} SHARED)

target_compile_features(${LIBRARY_NAME} INTERFACE cxx_std_23)
add_subdirectory(src)

target_include_directories(${LIBRARY_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_features(${LIBRARY_NAME} PUBLIC cxx_std_23)

target_link_libraries(${LIBRARY_NAME} INTERFACE intx::intx sszpp::sszpp)
target_include_directories(${LIBRARY_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

target_link_libraries(${LIBRARY_NAME} PRIVATE intx::intx sszpp::sszpp)

install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
56 changes: 55 additions & 1 deletion libs/nil_core/include/zkevm_framework/core/mpt/mpt.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,63 @@
#ifndef ZKEMV_FRAMEWORK_LIBS_NIL_CORE_INCLUDE_ZKEVM_FRAMEWORK_CORE_MPT_MPT_HPP_
#define ZKEMV_FRAMEWORK_LIBS_NIL_CORE_INCLUDE_ZKEVM_FRAMEWORK_CORE_MPT_MPT_HPP_

#include <algorithm>
#include <cstdint>
#include <memory>
#include <unordered_map>
#include <vector>

#include "zkevm_framework/core/mpt/node.hpp"

namespace std {
// To allow using vector of bytes as key in unordered_map
template<>
struct hash<vector<byte>> {
size_t operator()(const vector<byte>& v) const {
return hash<string_view>()(
string_view(reinterpret_cast<const char*>(v.data()), v.size()));
}
};
} // namespace std

namespace core {
namespace mpt {
class Mpt;

namespace details {
class GetHandler;
class SetHandler;
class DeleteHandler;
struct DeleteResult;
} // namespace details

class MerklePatriciaTrie {
public:
MerklePatriciaTrie();
std::vector<std::byte> get(const std::vector<std::byte>& key) const;
void set(const std::vector<std::byte>& key, const std::vector<std::byte>& value);
void remove(const std::vector<std::byte>& key);

protected:
Path pathFromKey(const std::vector<std::byte>& key) const;
Node getNode(const Reference& ref) const;
Reference storeNode(const Node& node);
std::optional<std::vector<std::byte>> get(const Reference& nodeRef, Path& path) const;
Reference set(const Reference& nodeRef, Path& path,
const std::vector<std::byte>& value);
details::DeleteResult delete_node(const Reference& nodeRef, const Path& path);

private:
static constexpr size_t kMaxRawKeyLen = 32;

Reference root_;
std::unordered_map<Reference, std::vector<std::byte>>
nodes_; // Better design is to use other external class for storage

friend class details::GetHandler;
friend class details::SetHandler;
friend class details::DeleteHandler;
};

} // namespace mpt
} // namespace core

Expand Down
105 changes: 105 additions & 0 deletions libs/nil_core/include/zkevm_framework/core/mpt/node.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#ifndef ZKEMV_FRAMEWORK_LIBS_NIL_CORE_INCLUDE_ZKEVM_FRAMEWORK_CORE_MPT_NODE_HPP_
#define ZKEMV_FRAMEWORK_LIBS_NIL_CORE_INCLUDE_ZKEVM_FRAMEWORK_CORE_MPT_NODE_HPP_

#include <cstdint>
#include <ssz++.hpp>
#include <vector>

#include "zkevm_framework/core/mpt/path.hpp"

namespace core {
namespace mpt {

constexpr size_t kBranchesNum = 16;

using Bytes = std::vector<std::byte>;
using Reference = Bytes;

enum class NodeTypeFlag : std::uint8_t {
kLeafNode = 0,
kExtensionNode = 1,
kBranchNode = 2
};

class Serializable {
public:
virtual ~Serializable() = default;
virtual Bytes Encode() const = 0;
};

class PathHolder {
public:
PathHolder() = default;
explicit PathHolder(Path path);

Path path;
};

class ValueHolder {
public:
ValueHolder() = default;
explicit ValueHolder(const std::vector<std::byte>& value);

const std::vector<std::byte>& value() const;
void set_value(const std::vector<std::byte>& new_value);

protected:
ssz::list<std::byte, 100000000> value_;
};

class LeafNode : public ValueHolder,
public PathHolder,
public ssz::ssz_variable_size_container,
public Serializable {
public:
LeafNode() = default;
LeafNode(const Path& path, const std::vector<std::byte>& new_value);

Bytes Encode() const override;

SSZ_CONT(path, value_)
};

class ExtensionNode : public PathHolder,
public ssz::ssz_variable_size_container,
public Serializable {
public:
ExtensionNode() = default;
ExtensionNode(const Path& path, const Reference& next);

Bytes Encode() const override;
const Reference& get_next_ref() const;

SSZ_CONT(path, next_ref_)

private:
ssz::list<std::byte, 1000> next_ref_;
};

class BranchNode : public ValueHolder,
public ssz::ssz_variable_size_container,
public Serializable {
public:
BranchNode() = default;
BranchNode(const std::array<Reference, kBranchesNum>& refs,
const std::vector<std::byte>& value);

Bytes Encode() const override;
std::array<Reference, kBranchesNum> get_branches() const;
void ClearBranch(std::byte nibble);
void SetBranch(std::byte nibble, const std::vector<std::byte>& value);

SSZ_CONT(branches_, value_)

private:
ssz::list<ssz::list<std::byte, 1000>, kBranchesNum> branches_;
};

using Node = std::variant<LeafNode, ExtensionNode, BranchNode>;

Node DecodeNode(const Bytes& bytes);

} // namespace mpt
} // namespace core

#endif // ZKEMV_FRAMEWORK_LIBS_NIL_CORE_INCLUDE_ZKEVM_FRAMEWORK_CORE_MPT_NODE_HPP_
83 changes: 83 additions & 0 deletions libs/nil_core/include/zkevm_framework/core/mpt/path.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#ifndef ZKEMV_FRAMEWORK_LIBS_NIL_CORE_INCLUDE_ZKEVM_FRAMEWORK_CORE_MPT_PATH_HPP_
#define ZKEMV_FRAMEWORK_LIBS_NIL_CORE_INCLUDE_ZKEVM_FRAMEWORK_CORE_MPT_PATH_HPP_

#include <cstddef>
#include <cstdint>
#include <ssz++.hpp>
#include <vector>

namespace core {
namespace mpt {

class Path : public ssz::ssz_variable_size_container {
public:
Path();
Path(const Path &other) = default;
Path(const std::vector<std::byte> &data, std::size_t offset = 0);

int size() const;
bool empty() const;
std::byte operator[](size_t idx) const;
Path operator+(const Path &other) const;
bool operator==(const Path &other) const;
std::byte at(std::size_t idx) const;

bool StartsWith(const Path &other) const;
Path *Consume(std::size_t amount);
Path CommonPrefix(const Path &other) const;

// Methods used by sszpp. NO hash_tree_root METHOD PROVIDED
constexpr std::size_t ssz_size() const noexcept { return 1 + size() / 2; }

constexpr void serialize(ssz::ssz_iterator auto result) const {
std::size_t nibblesLen = size();
bool isOdd = (nibblesLen % 2 == 1);

// If even size, we just insert empty byte at the beginning
auto prefix = std::byte{0x00};

// If odd, we put kOddFlag at the first nibble and the first element of Path after
// it, so we could insert by full bytes afterwards
if (isOdd) {
prefix = kOddFlag | at(0);
}

std::copy(static_cast<const std::byte *>(static_cast<const void *>(&prefix)),
static_cast<const std::byte *>(static_cast<const void *>(&prefix)) + 1,
result);
++result;

for (std::size_t i = (isOdd ? 1 : 0); i < nibblesLen; i += 2) {
std::byte nextByte = (operator[](i) << 4) | operator[](i + 1);
std::copy(
static_cast<const std::byte *>(static_cast<const void *>(&nextByte)),
static_cast<const std::byte *>(static_cast<const void *>(&nextByte)) + 1,
result);
++result;
}
}

constexpr void deserialize(const std::ranges::sized_range auto &bytes) {
bool isOddLen = (bytes.front() & kOddFlag) == kOddFlag;
if (isOddLen) {
offset_ = 1;
} else {
offset_ = 2;
}

data_.reserve(std::ranges::size(bytes));
std::ranges::copy(bytes, std::back_inserter(data_));
}

private:
Path ConstructFromPrefix(std::size_t length) const;

static constexpr std::byte kOddFlag = std::byte{0x10};
std::vector<std::byte> data_;
std::size_t offset_ = 0;
};

} // namespace mpt
} // namespace core

#endif // ZKEMV_FRAMEWORK_LIBS_NIL_CORE_INCLUDE_ZKEVM_FRAMEWORK_CORE_MPT_MPT_HPP_
19 changes: 19 additions & 0 deletions libs/nil_core/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SSZ++ can be compiled only with GCC 13+
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
message(FATAL_ERROR "Data types library can be built only with GCC 13+")
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
message(FATAL_ERROR "Data types library can be built only with GCC 13+")
endif()

find_package(sszpp REQUIRED)

set(SOURCES
mpt/mpt.cpp
mpt/node.cpp
mpt/path.cpp
)

target_sources(${LIBRARY_NAME} PRIVATE ${SOURCES})

target_link_libraries(${LIBRARY_NAME} PRIVATE sszpp::sszpp)
Loading

0 comments on commit 39c515f

Please sign in to comment.