Kagome
Polkadot Runtime Engine in C++17
trie_node.hpp
Go to the documentation of this file.
1 
6 #ifndef KAGOME_STORAGE_TRIE_POLKADOT_NODE
7 #define KAGOME_STORAGE_TRIE_POLKADOT_NODE
8 
9 #include <optional>
10 
11 #include <fmt/format.h>
12 
13 #include "common/blob.hpp"
14 #include "common/buffer.hpp"
15 #include "storage/trie/node.hpp"
16 
17 namespace kagome::storage::trie {
18 
20 
21  struct KeyNibbles : public common::Buffer {
23 
24  using Buffer::Buffer;
25  using Buffer::operator==;
26  using Buffer::operator<;
27 
28  KeyNibbles(common::Buffer b) : Buffer{std::move(b)} {}
29 
36  if (key.empty()) {
37  return {};
38  }
39  if (key.size() == 1 && key[0] == 0) {
40  return KeyNibbles{common::Buffer{0, 0}};
41  }
42 
43  auto l = key.size() * 2;
44  KeyNibbles res(common::Buffer(l, 0));
45  for (ssize_t i = 0; i < key.size(); i++) {
46  res[2 * i] = key[i] >> 4u;
47  res[2 * i + 1] = key[i] & 0xfu;
48  }
49 
50  return res;
51  }
52 
57  auto toByteBuffer() const {
58  Buffer res;
59  if (size() % 2 == 0) {
60  res = Buffer(size() / 2, 0);
61  for (size_t i = 0; i < size() / 2; i++) {
62  res[i] = toByte((*this)[i * 2], (*this)[i * 2 + 1]);
63  }
64  } else {
65  res = Buffer(size() / 2 + 1, 0);
66  res[0] = (*this)[0];
67  for (size_t i = 1; i < size() / 2 + 1; i++) {
68  res[i] = toByte((*this)[i * 2 - 1], (*this)[i * 2]);
69  }
70  }
71  return res;
72  }
73 
74  static uint8_t toByte(uint8_t high, uint8_t low) {
75  return (high << 4u) | (low & 0xfu);
76  }
77 
78  NibblesView subspan(size_t offset = 0, size_t length = -1) const {
79  return NibblesView{*this}.subspan(offset, length);
80  }
81  };
82 
88  struct OpaqueTrieNode : public Node {};
89 
90  struct TrieNode : public OpaqueTrieNode {
91  TrieNode() = default;
92  TrieNode(KeyNibbles key_nibbles, std::optional<common::Buffer> value)
93  : key_nibbles{std::move(key_nibbles)}, value{std::move(value)} {}
94 
95  ~TrieNode() override = default;
96 
97  enum class Type {
98  Special, // -
99  Leaf, // 01
100  BranchEmptyValue, // 10
101  BranchWithValue, // 11
102  LeafContainingHashes, // 001
103  BranchContainingHashes, // 0001
104  Empty, // 0000 0000
105  ReservedForCompactEncoding // 0001 0000
106  };
107 
108  // just to avoid static_casts every time you need a switch on a node type
109  Type getTrieType() const noexcept {
110  return static_cast<Type>(getType());
111  }
112 
113  bool isBranch() const noexcept {
114  auto type = getTrieType();
115  return type == Type::BranchWithValue or type == Type::BranchEmptyValue
116  or type == Type::BranchContainingHashes;
117  }
118 
120  std::optional<common::Buffer> value;
121  };
122 
123  struct BranchNode : public TrieNode {
124  static constexpr uint8_t kMaxChildren = 16;
125 
126  BranchNode() = default;
127  explicit BranchNode(KeyNibbles key_nibbles,
128  std::optional<common::Buffer> value = std::nullopt)
129  : TrieNode{std::move(key_nibbles), std::move(value)} {}
130 
131  ~BranchNode() override = default;
132 
133  int getType() const override;
134 
135  uint16_t childrenBitmap() const;
136  uint8_t childrenNum() const;
137 
138  // Has 1..16 children.
139  // Stores their hashes to search for them in a storage and encode them more
140  // easily. @see DummyNode
141  std::array<std::shared_ptr<OpaqueTrieNode>, kMaxChildren> children;
142  };
143 
144  struct LeafNode : public TrieNode {
145  LeafNode() = default;
146  LeafNode(KeyNibbles key_nibbles, std::optional<common::Buffer> value)
147  : TrieNode{std::move(key_nibbles), std::move(value)} {}
148 
149  ~LeafNode() override = default;
150 
151  int getType() const override;
152  };
153 
155  static constexpr uint8_t kMaxChildren = 16;
156 
157  BranchContainingHashesNode() = default;
159  KeyNibbles key_nibbles,
160  std::optional<common::Buffer> value = std::nullopt)
161  : TrieNode{std::move(key_nibbles), std::move(value)} {}
162 
163  ~BranchContainingHashesNode() override = default;
164 
165  int getType() const override;
166 
167  uint16_t childrenBitmap() const;
168  uint8_t childrenNum() const;
169 
170  // Has 1..16 children.
171  // Stores their hashes to search for them in a storage and encode them more
172  // easily. @see DummyNode
173  std::array<std::shared_ptr<OpaqueTrieNode>, kMaxChildren> children;
174  };
175 
177  LeafContainingHashesNode() = default;
179  std::optional<common::Buffer> value)
180  : TrieNode{std::move(key_nibbles), std::move(value)} {}
181 
182  ~LeafContainingHashesNode() override = default;
183 
184  int getType() const override;
185  };
186 
191  struct DummyNode : public OpaqueTrieNode {
197  explicit DummyNode(common::Buffer key) : db_key{std::move(key)} {}
198 
199  int getType() const override {
200  // Special only because a node has to have a type. Actually this is not
201  // the real node and the type of the underlying node is inaccessible
202  // before reading from the storage
203  return static_cast<int>(TrieNode::Type::Special);
204  }
205 
207  };
208 
209 } // namespace kagome::storage::trie
210 
211 template <>
212 struct fmt::formatter<kagome::storage::trie::KeyNibbles> {
213  template <typename FormatContext>
214  auto format(const kagome::storage::trie::KeyNibbles &p, FormatContext &ctx)
215  -> decltype(ctx.out()) {
216  if (p.size() % 2 != 0) {
217  format_to(ctx.out(), "{:x}", p[0]);
218  }
219  for (size_t i = p.size() % 2; i < p.size() - 1; i += 2) {
220  format_to(ctx.out(), "{:02x}", p.toByte(p[i], p[i + 1]));
221  }
222  }
223 };
224 
225 #endif // KAGOME_STORAGE_TRIE_POLKADOT_NODE
Class represents arbitrary (including empty) byte buffer.
Definition: buffer.hpp:29
std::array< std::shared_ptr< OpaqueTrieNode >, kMaxChildren > children
Definition: trie_node.hpp:141
int getType() const override
Definition: trie_node.hpp:199
BranchContainingHashesNode(KeyNibbles key_nibbles, std::optional< common::Buffer > value=std::nullopt)
Definition: trie_node.hpp:158
common::BufferView BufferView
BranchNode(KeyNibbles key_nibbles, std::optional< common::Buffer > value=std::nullopt)
Definition: trie_node.hpp:127
LeafNode(KeyNibbles key_nibbles, std::optional< common::Buffer > value)
Definition: trie_node.hpp:146
SLBuffer< std::numeric_limits< size_t >::max()> Buffer
Definition: buffer.hpp:244
auto format(const kagome::storage::trie::KeyNibbles &p, FormatContext &ctx) -> decltype(ctx.out())
Definition: trie_node.hpp:214
DummyNode(common::Buffer key)
Definition: trie_node.hpp:197
std::array< std::shared_ptr< OpaqueTrieNode >, kMaxChildren > children
Definition: trie_node.hpp:173
TrieNode(KeyNibbles key_nibbles, std::optional< common::Buffer > value)
Definition: trie_node.hpp:92
NibblesView subspan(size_t offset=0, size_t length=-1) const
Definition: trie_node.hpp:78
Type getTrieType() const noexcept
Definition: trie_node.hpp:109
LeafContainingHashesNode(KeyNibbles key_nibbles, std::optional< common::Buffer > value)
Definition: trie_node.hpp:178
std::optional< common::Buffer > value
Definition: trie_node.hpp:120
bool isBranch() const noexcept
Definition: trie_node.hpp:113
static KeyNibbles fromByteBuffer(const common::BufferView &key)
Definition: trie_node.hpp:35
static uint8_t toByte(uint8_t high, uint8_t low)
Definition: trie_node.hpp:74