Fabcoin Core  0.16.2
P2P Digital Currency
MemTrie.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
22 #include "MemTrie.h"
23 
24 #include <libdevcore/TrieCommon.h>
25 #include <libdevcore/SHA3.h>
26 using namespace std;
27 using namespace dev;
28 
29 namespace dev
30 {
31 
32 #define ENABLE_DEBUG_PRINT 0
33 
34 /*/
35 #define APPEND_CHILD appendData
36 /*/
37 #define APPEND_CHILD appendRaw
38 /**/
39 
41 {
42 public:
44  virtual ~MemTrieNode() {}
45 
46  virtual std::string const& at(bytesConstRef _key) const = 0;
47  virtual MemTrieNode* insert(bytesConstRef _key, std::string const& _value) = 0;
48  virtual MemTrieNode* remove(bytesConstRef _key) = 0;
49  void putRLP(RLPStream& _parentStream) const;
50 
51 #if ENABLE_DEBUG_PRINT
52  void debugPrint(std::string const& _indent = "") const { std::cerr << std::hex << hash256() << ":" << std::dec << std::endl; debugPrintBody(_indent); }
53 #endif
54 
56  h256 hash256() const { RLPStream s; makeRLP(s); return dev::sha3(s.out()); }
57  bytes rlp() const { RLPStream s; makeRLP(s); return s.out(); }
58  void mark() { m_hash256 = h256(); }
59 
60 protected:
61  virtual void makeRLP(RLPStream& _intoStream) const = 0;
62 
63 #if ENABLE_DEBUG_PRINT
64  virtual void debugPrintBody(std::string const& _indent = "") const = 0;
65 #endif
66 
67  static MemTrieNode* newBranch(bytesConstRef _k1, std::string const& _v1, bytesConstRef _k2, std::string const& _v2);
68 
69 private:
70  mutable h256 m_hash256;
71 };
72 
73 static const std::string c_nullString;
74 
75 class TrieExtNode: public MemTrieNode
76 {
77 public:
78  TrieExtNode(bytesConstRef _bytes): m_ext(_bytes.begin(), _bytes.end()) {}
79 
81 };
82 
84 {
85 public:
86  TrieBranchNode(std::string const& _value): m_value(_value)
87  {
88  memset(m_nodes.data(), 0, sizeof(MemTrieNode*) * 16);
89  }
90 
91  TrieBranchNode(byte _i1, MemTrieNode* _n1, std::string const& _value = std::string()): m_value(_value)
92  {
93  memset(m_nodes.data(), 0, sizeof(MemTrieNode*) * 16);
94  m_nodes[_i1] = _n1;
95  }
96 
98  {
99  memset(m_nodes.data(), 0, sizeof(MemTrieNode*) * 16);
100  m_nodes[_i1] = _n1;
101  m_nodes[_i2] = _n2;
102  }
103 
104  virtual ~TrieBranchNode()
105  {
106  for (auto i: m_nodes)
107  delete i;
108  }
109 
110 #if ENABLE_DEBUG_PRINT
111  virtual void debugPrintBody(std::string const& _indent) const
112  {
113 
114  if (m_value.size())
115  std::cerr << _indent << "@: " << m_value << std::endl;
116  for (auto i = 0; i < 16; ++i)
117  if (m_nodes[i])
118  {
119  std::cerr << _indent << std::hex << i << ": " << std::dec;
120  m_nodes[i]->debugPrint(_indent + " ");
121  }
122  }
123 #endif
124 
125  virtual std::string const& at(bytesConstRef _key) const override;
126  virtual MemTrieNode* insert(bytesConstRef _key, std::string const& _value) override;
127  virtual MemTrieNode* remove(bytesConstRef _key) override;
128  virtual void makeRLP(RLPStream& _parentStream) const override;
129 
130 private:
132  byte activeBranch() const;
133 
134  MemTrieNode* rejig();
135 
136  std::array<MemTrieNode*, 16> m_nodes;
137  std::string m_value;
138 };
139 
141 {
142 public:
143  TrieLeafNode(bytesConstRef _key, std::string const& _value): TrieExtNode(_key), m_value(_value) {}
144 
145 #if ENABLE_DEBUG_PRINT
146  virtual void debugPrintBody(std::string const& _indent) const
147  {
148  assert(m_value.size());
149  std::cerr << _indent;
150  if (m_ext.size())
151  std::cerr << toHex(m_ext, 1) << ": ";
152  else
153  std::cerr << "@: ";
154  std::cerr << m_value << std::endl;
155  }
156 #endif
157 
158  virtual std::string const& at(bytesConstRef _key) const override { return contains(_key) ? m_value : c_nullString; }
159  virtual MemTrieNode* insert(bytesConstRef _key, std::string const& _value) override;
160  virtual MemTrieNode* remove(bytesConstRef _key) override;
161  virtual void makeRLP(RLPStream& _parentStream) const override;
162 
163 private:
164  bool contains(bytesConstRef _key) const { return _key.size() == m_ext.size() && !memcmp(_key.data(), m_ext.data(), _key.size()); }
165 
166  std::string m_value;
167 };
168 
170 {
171 public:
172  TrieInfixNode(bytesConstRef _key, MemTrieNode* _next): TrieExtNode(_key), m_next(_next) {}
173  virtual ~TrieInfixNode() { delete m_next; }
174 
175 #if ENABLE_DEBUG_PRINT
176  virtual void debugPrintBody(std::string const& _indent) const
177  {
178  std::cerr << _indent << toHex(m_ext, 1) << ": ";
179  m_next->debugPrint(_indent + " ");
180  }
181 #endif
182 
183  virtual std::string const& at(bytesConstRef _key) const override { assert(m_next); return contains(_key) ? m_next->at(_key.cropped(m_ext.size())) : c_nullString; }
184  virtual MemTrieNode* insert(bytesConstRef _key, std::string const& _value) override;
185  virtual MemTrieNode* remove(bytesConstRef _key) override;
186  virtual void makeRLP(RLPStream& _parentStream) const override;
187 
188 private:
189  bool contains(bytesConstRef _key) const { return _key.size() >= m_ext.size() && !memcmp(_key.data(), m_ext.data(), m_ext.size()); }
190 
192 };
193 
194 void MemTrieNode::putRLP(RLPStream& _parentStream) const
195 {
196  RLPStream s;
197  makeRLP(s);
198  if (s.out().size() < 32)
199  _parentStream.APPEND_CHILD(s.out());
200  else
201  _parentStream << dev::sha3(s.out());
202 }
203 
204 void TrieBranchNode::makeRLP(RLPStream& _intoStream) const
205 {
206  _intoStream.appendList(17);
207  for (auto i: m_nodes)
208  if (i)
209  i->putRLP(_intoStream);
210  else
211  _intoStream << "";
212  _intoStream << m_value;
213 }
214 
215 void TrieLeafNode::makeRLP(RLPStream& _intoStream) const
216 {
217  _intoStream.appendList(2) << hexPrefixEncode(m_ext, true) << m_value;
218 }
219 
220 void TrieInfixNode::makeRLP(RLPStream& _intoStream) const
221 {
222  assert(m_next);
223  _intoStream.appendList(2);
224  _intoStream << hexPrefixEncode(m_ext, false);
225  m_next->putRLP(_intoStream);
226 }
227 
228 MemTrieNode* MemTrieNode::newBranch(bytesConstRef _k1, std::string const& _v1, bytesConstRef _k2, std::string const& _v2)
229 {
230  unsigned prefix = commonPrefix(_k1, _k2);
231 
232  MemTrieNode* ret;
233  if (_k1.size() == prefix)
234  ret = new TrieBranchNode(_k2[prefix], new TrieLeafNode(_k2.cropped(prefix + 1), _v2), _v1);
235  else if (_k2.size() == prefix)
236  ret = new TrieBranchNode(_k1[prefix], new TrieLeafNode(_k1.cropped(prefix + 1), _v1), _v2);
237  else // both continue after split
238  ret = new TrieBranchNode(_k1[prefix], new TrieLeafNode(_k1.cropped(prefix + 1), _v1), _k2[prefix], new TrieLeafNode(_k2.cropped(prefix + 1), _v2));
239 
240  if (prefix)
241  // have shared prefix - split.
242  ret = new TrieInfixNode(_k1.cropped(0, prefix), ret);
243 
244  return ret;
245 }
246 
247 std::string const& TrieBranchNode::at(bytesConstRef _key) const
248 {
249  if (_key.empty())
250  return m_value;
251  else if (m_nodes[_key[0]] != nullptr)
252  return m_nodes[_key[0]]->at(_key.cropped(1));
253  return c_nullString;
254 }
255 
256 MemTrieNode* TrieBranchNode::insert(bytesConstRef _key, std::string const& _value)
257 {
258  assert(_value.size());
259  mark();
260  if (_key.empty())
261  m_value = _value;
262  else
263  if (!m_nodes[_key[0]])
264  m_nodes[_key[0]] = new TrieLeafNode(_key.cropped(1), _value);
265  else
266  m_nodes[_key[0]] = m_nodes[_key[0]]->insert(_key.cropped(1), _value);
267  return this;
268 }
269 
270 MemTrieNode* TrieBranchNode::remove(bytesConstRef _key)
271 {
272  if (_key.empty())
273  if (m_value.size())
274  {
275  m_value.clear();
276  return rejig();
277  }
278  else {}
279  else if (m_nodes[_key[0]] != nullptr)
280  {
281  m_nodes[_key[0]] = m_nodes[_key[0]]->remove(_key.cropped(1));
282  return rejig();
283  }
284  return this;
285 }
286 
287 MemTrieNode* TrieBranchNode::rejig()
288 {
289  mark();
290  byte n = activeBranch();
291 
292  if (n == (byte)-1 && m_value.size())
293  {
294  // switch to leaf
295  auto r = new TrieLeafNode(bytesConstRef(), m_value);
296  delete this;
297  return r;
298  }
299  else if (n < 16 && m_value.empty())
300  {
301  // only branching to n...
302  if (auto b = dynamic_cast<TrieBranchNode*>(m_nodes[n]))
303  {
304  // switch to infix
305  m_nodes[n] = nullptr;
306  delete this;
307  return new TrieInfixNode(bytesConstRef(&n, 1), b);
308  }
309  else
310  {
311  auto x = dynamic_cast<TrieExtNode*>(m_nodes[n]);
312  assert(x);
313  // include in child
314  pushFront(x->m_ext, n);
315  m_nodes[n] = nullptr;
316  delete this;
317  return x;
318  }
319  }
320 
321  return this;
322 }
323 
324 byte TrieBranchNode::activeBranch() const
325 {
326  byte n = (byte)-1;
327  for (int i = 0; i < 16; ++i)
328  if (m_nodes[i] != nullptr)
329  {
330  if (n == (byte)-1)
331  n = (byte)i;
332  else
333  return 16;
334  }
335  return n;
336 }
337 
338 MemTrieNode* TrieInfixNode::insert(bytesConstRef _key, std::string const& _value)
339 {
340  assert(_value.size());
341  mark();
342  if (contains(_key))
343  {
344  m_next = m_next->insert(_key.cropped(m_ext.size()), _value);
345  return this;
346  }
347  else
348  {
349  unsigned prefix = commonPrefix(_key, m_ext);
350  if (prefix)
351  {
352  // one infix becomes two infixes, then insert into the second
353  // instead of pop_front()...
354  trimFront(m_ext, prefix);
355 
356  return new TrieInfixNode(_key.cropped(0, prefix), insert(_key.cropped(prefix), _value));
357  }
358  else
359  {
360  // split here.
361  auto f = m_ext[0];
362  trimFront(m_ext, 1);
363  MemTrieNode* n = m_ext.empty() ? m_next : this;
364  if (n != this)
365  {
366  m_next = nullptr;
367  delete this;
368  }
369  TrieBranchNode* ret = new TrieBranchNode(f, n);
370  ret->insert(_key, _value);
371  return ret;
372  }
373  }
374 }
375 
376 MemTrieNode* TrieInfixNode::remove(bytesConstRef _key)
377 {
378  if (contains(_key))
379  {
380  mark();
381  m_next = m_next->remove(_key.cropped(m_ext.size()));
382  if (auto p = dynamic_cast<TrieExtNode*>(m_next))
383  {
384  // merge with child...
385  m_ext.reserve(m_ext.size() + p->m_ext.size());
386  for (auto i: p->m_ext)
387  m_ext.push_back(i);
388  p->m_ext = m_ext;
389  p->mark();
390  m_next = nullptr;
391  delete this;
392  return p;
393  }
394  if (!m_next)
395  {
396  delete this;
397  return nullptr;
398  }
399  }
400  return this;
401 }
402 
403 MemTrieNode* TrieLeafNode::insert(bytesConstRef _key, std::string const& _value)
404 {
405  assert(_value.size());
406  mark();
407  if (contains(_key))
408  {
409  m_value = _value;
410  return this;
411  }
412  else
413  {
414  // create new trie.
415  auto n = MemTrieNode::newBranch(_key, _value, bytesConstRef(&m_ext), m_value);
416  delete this;
417  return n;
418  }
419 }
420 
421 MemTrieNode* TrieLeafNode::remove(bytesConstRef _key)
422 {
423  if (contains(_key))
424  {
425  delete this;
426  return nullptr;
427  }
428  return this;
429 }
430 
431 MemTrie::~MemTrie()
432 {
433  delete m_root;
434 }
435 
437 {
438  return m_root ? m_root->hash256() : sha3(dev::rlp(bytesConstRef()));
439 }
440 
442 {
443  return m_root ? m_root->rlp() : dev::rlp(bytesConstRef());
444 }
445 
446 void MemTrie::debugPrint()
447 {
448 #if ENABLE_DEBUG_PRINT
449  if (m_root)
450  m_root->debugPrint();
451 #endif
452 }
453 
454 std::string const& MemTrie::at(std::string const& _key) const
455 {
456  if (!m_root)
457  return c_nullString;
458  auto h = asNibbles(_key);
459  return m_root->at(bytesConstRef(&h));
460 }
461 
462 void MemTrie::insert(std::string const& _key, std::string const& _value)
463 {
464  if (_value.empty())
465  remove(_key);
466  auto h = asNibbles(_key);
467  m_root = m_root ? m_root->insert(&h, _value) : new TrieLeafNode(bytesConstRef(&h), _value);
468 }
469 
470 void MemTrie::remove(std::string const& _key)
471 {
472  if (m_root)
473  {
474  auto h = asNibbles(_key);
475  m_root = m_root->remove(&h);
476  }
477 }
478 
479 }
480 
unsigned commonPrefix(T const &_t, _U const &_u)
Definition: CommonData.h:191
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
std::string toHex(T const &_data, int _w=2, HexPrefix _prefix=HexPrefix::DontAdd)
Definition: CommonData.h:54
virtual MemTrieNode * insert(bytesConstRef _key, std::string const &_value) override
Definition: MemTrie.cpp:256
uint8_t byte
Definition: Common.h:57
virtual ~TrieBranchNode()
Definition: MemTrie.cpp:104
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
Definition: RLP.h:467
void hash256(RaIter first, RaIter last, OutIter first2, OutIter last2)
Definition: picosha2.h:304
TrieExtNode(bytesConstRef _bytes)
Definition: MemTrie.cpp:78
TrieBranchNode(std::string const &_value)
Definition: MemTrie.cpp:86
#define h(i)
Definition: sha.cpp:736
std::string hexPrefixEncode(bytes const &_hexVector, bool _leaf, int _begin, int _end)
Definition: TrieCommon.cpp:43
bytes const & out() const
Read the byte stream.
Definition: RLP.h:433
const char * prefix
Definition: rest.cpp:623
virtual MemTrieNode * insert(bytesConstRef _key, std::string const &_value) override
Definition: MemTrie.cpp:403
void trimFront(T &_t, unsigned _elements)
Trims a given number of elements from the front of a collection.
Definition: CommonData.h:216
std::hash for asio::adress
Definition: Common.h:323
assert(len-trim+(2 *lenIndices)<=WIDTH)
std::string m_value
Definition: MemTrie.cpp:166
vector_ref< _T > cropped(size_t _begin, size_t _count) const
Definition: vector_ref.h:62
MemTrieNode * m_next
Definition: MemTrie.cpp:191
std::array< MemTrieNode *, 16 > m_nodes
Definition: MemTrie.cpp:136
virtual ~TrieInfixNode()
Definition: MemTrie.cpp:173
virtual ~MemTrieNode()
Definition: MemTrie.cpp:44
bool empty() const
Definition: vector_ref.h:56
#define x(i)
TrieBranchNode(byte _i1, MemTrieNode *_n1, std::string const &_value=std::string())
Definition: MemTrie.cpp:91
h256 hash256() const
256-bit hash of the node - this is a SHA-3/256 hash of the RLP of the node.
Definition: MemTrie.cpp:56
bytes rlp() const
Definition: MemTrie.cpp:57
TrieLeafNode(bytesConstRef _key, std::string const &_value)
Definition: MemTrie.cpp:143
bool contains(T const &_t, V const &_v)
Definition: CommonData.h:379
std::string m_value
Definition: MemTrie.cpp:137
std::vector< byte > bytes
Definition: Common.h:75
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
RLPStream & appendList(size_t _items)
Appends a list.
Definition: RLP.cpp:276
bool contains(bytesConstRef _key) const
Definition: MemTrie.cpp:164
FixedHash< 32 > h256
Definition: FixedHash.h:340
bytes asNibbles(bytesConstRef const &_s)
Definition: CommonData.cpp:129
virtual std::string const & at(bytesConstRef _key) const override
Definition: MemTrie.cpp:183
#define b(i, j)
size_t size() const
Definition: vector_ref.h:55
TrieInfixNode(bytesConstRef _key, MemTrieNode *_next)
Definition: MemTrie.cpp:172
#define f(x)
Definition: gost.cpp:57
void pushFront(T &_t, _U _e)
Pushes an element on to the front of a collection.
Definition: CommonData.h:226
_T * data() const
Definition: vector_ref.h:51
bool contains(bytesConstRef _key) const
Definition: MemTrie.cpp:189
TrieBranchNode(byte _i1, MemTrieNode *_n1, byte _i2, MemTrieNode *_n2)
Definition: MemTrie.cpp:97
uint8_t byte
Definition: Common.h:10
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
Definition: SHA3.cpp:214
virtual std::string const & at(bytesConstRef _key) const =0
Class for writing to an RLP bytestream.
Definition: RLP.h:383
virtual std::string const & at(bytesConstRef _key) const override
Definition: MemTrie.cpp:158