rippled
SHAMapSync.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/random.h>
21 #include <ripple/shamap/SHAMap.h>
22 #include <ripple/shamap/SHAMapSyncFilter.h>
23 
24 namespace ripple {
25 
26 void
28  std::function<void(std::shared_ptr<SHAMapItem const> const& item)> const&
29  leafFunction) const
30 {
31  visitNodes([&leafFunction](SHAMapTreeNode& node) {
32  if (!node.isInner())
33  leafFunction(static_cast<SHAMapLeafNode&>(node).peekItem());
34  return true;
35  });
36 }
37 
38 void
39 SHAMap::visitNodes(std::function<bool(SHAMapTreeNode&)> const& function) const
40 {
41  if (!root_)
42  return;
43 
44  function(*root_);
45 
46  if (!root_->isInner())
47  return;
48 
51 
52  auto node = std::static_pointer_cast<SHAMapInnerNode>(root_);
53  int pos = 0;
54 
55  while (1)
56  {
57  while (pos < 16)
58  {
59  uint256 childHash;
60  if (!node->isEmptyBranch(pos))
61  {
63  descendNoStore(node, pos);
64  if (!function(*child))
65  return;
66 
67  if (child->isLeaf())
68  ++pos;
69  else
70  {
71  // If there are no more children, don't push this node
72  while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
73  ++pos;
74 
75  if (pos != 15)
76  {
77  // save next position to resume at
78  stack.push(std::make_pair(pos + 1, std::move(node)));
79  }
80 
81  // descend to the child's first position
82  node = std::static_pointer_cast<SHAMapInnerNode>(child);
83  pos = 0;
84  }
85  }
86  else
87  {
88  ++pos; // move to next position
89  }
90  }
91 
92  if (stack.empty())
93  break;
94 
95  std::tie(pos, node) = stack.top();
96  stack.pop();
97  }
98 }
99 
100 void
102  SHAMap const* have,
103  std::function<bool(SHAMapTreeNode const&)> function) const
104 {
105  // Visit every node in this SHAMap that is not present
106  // in the specified SHAMap
107  if (!root_)
108  return;
109 
110  if (root_->getHash().isZero())
111  return;
112 
113  if (have && (root_->getHash() == have->root_->getHash()))
114  return;
115 
116  if (root_->isLeaf())
117  {
118  auto leaf = std::static_pointer_cast<SHAMapLeafNode>(root_);
119  if (!have ||
120  !have->hasLeafNode(leaf->peekItem()->key(), leaf->getHash()))
121  function(*root_);
122  return;
123  }
124  // contains unexplored non-matching inner node entries
127 
128  stack.push({static_cast<SHAMapInnerNode*>(root_.get()), SHAMapNodeID{}});
129 
130  while (!stack.empty())
131  {
132  auto const [node, nodeID] = stack.top();
133  stack.pop();
134 
135  // 1) Add this node to the pack
136  if (!function(*node))
137  return;
138 
139  // 2) push non-matching child inner nodes
140  for (int i = 0; i < 16; ++i)
141  {
142  if (!node->isEmptyBranch(i))
143  {
144  auto const& childHash = node->getChildHash(i);
145  SHAMapNodeID childID = nodeID.getChildNodeID(i);
146  auto next = descendThrow(node, i);
147 
148  if (next->isInner())
149  {
150  if (!have || !have->hasInnerNode(childID, childHash))
151  stack.push(
152  {static_cast<SHAMapInnerNode*>(next), childID});
153  }
154  else if (
155  !have ||
156  !have->hasLeafNode(
157  static_cast<SHAMapLeafNode*>(next)->peekItem()->key(),
158  childHash))
159  {
160  if (!function(*next))
161  return;
162  }
163  }
164  }
165  }
166 }
167 
168 // Starting at the position referred to by the specfied
169 // StackEntry, process that node and its first resident
170 // children, descending the SHAMap until we complete the
171 // processing of a node.
172 void
174 {
175  SHAMapInnerNode*& node = std::get<0>(se);
176  SHAMapNodeID& nodeID = std::get<1>(se);
177  int& firstChild = std::get<2>(se);
178  int& currentChild = std::get<3>(se);
179  bool& fullBelow = std::get<4>(se);
180 
181  while (currentChild < 16)
182  {
183  int branch = (firstChild + currentChild++) % 16;
184  if (node->isEmptyBranch(branch))
185  continue;
186 
187  auto const& childHash = node->getChildHash(branch);
188 
189  if (mn.missingHashes_.count(childHash) != 0)
190  {
191  // we already know this child node is missing
192  fullBelow = false;
193  }
194  else if (
195  !backed_ ||
197  ->touch_if_exists(childHash.as_uint256()))
198  {
199  SHAMapNodeID childID = nodeID.getChildNodeID(branch);
200  bool pending = false;
201  auto d = descendAsync(node, branch, mn.filter_, pending);
202 
203  if (!d)
204  {
205  fullBelow = false; // for now, not known full below
206 
207  if (!pending)
208  { // node is not in the database
209  mn.missingHashes_.insert(childHash);
210  mn.missingNodes_.emplace_back(
211  childID, childHash.as_uint256());
212 
213  if (--mn.max_ <= 0)
214  return;
215  }
216  else
217  mn.deferredReads_.emplace_back(node, nodeID, branch);
218  }
219  else if (
220  d->isInner() &&
221  !static_cast<SHAMapInnerNode*>(d)->isFullBelow(mn.generation_))
222  {
223  mn.stack_.push(se);
224 
225  // Switch to processing the child node
226  node = static_cast<SHAMapInnerNode*>(d);
227  nodeID = childID;
228  firstChild = rand_int(255);
229  currentChild = 0;
230  fullBelow = true;
231  }
232  }
233  }
234 
235  // We have finished processing an inner node
236  // and thus (for now) all its children
237 
238  if (fullBelow)
239  { // No partial node encountered below this node
240  node->setFullBelowGen(mn.generation_);
241  if (backed_)
242  {
244  ->insert(node->getHash().as_uint256());
245  }
246  }
247 
248  node = nullptr;
249 }
250 
251 // Wait for deferred reads to finish and
252 // process their results
253 void
255 {
256  // Wait for our deferred reads to finish
257  auto const before = std::chrono::steady_clock::now();
258  f_.db().waitReads();
259  auto const after = std::chrono::steady_clock::now();
260 
261  auto const elapsed =
262  std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
263  auto const count = mn.deferredReads_.size();
264 
265  // Process all deferred reads
266  int hits = 0;
267  for (auto const& deferredNode : mn.deferredReads_)
268  {
269  auto parent = std::get<0>(deferredNode);
270  auto const& parentID = std::get<1>(deferredNode);
271  auto branch = std::get<2>(deferredNode);
272  auto const& nodeHash = parent->getChildHash(branch);
273 
274  auto nodePtr = fetchNodeNT(nodeHash, mn.filter_);
275  if (nodePtr)
276  { // Got the node
277  ++hits;
278  if (backed_)
279  canonicalize(nodeHash, nodePtr);
280  nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
281 
282  // When we finish this stack, we need to restart
283  // with the parent of this node
284  mn.resumes_[parent] = parentID;
285  }
286  else if ((mn.max_ > 0) && (mn.missingHashes_.insert(nodeHash).second))
287  {
288  mn.missingNodes_.emplace_back(
289  parentID.getChildNodeID(branch), nodeHash.as_uint256());
290 
291  --mn.max_;
292  }
293  }
294  mn.deferredReads_.clear();
295 
296  auto const process_time =
297  std::chrono::duration_cast<std::chrono::milliseconds>(
299 
300  using namespace std::chrono_literals;
301  if ((count > 50) || (elapsed > 50ms))
302  {
303  JLOG(journal_.debug())
304  << "getMissingNodes reads " << count << " nodes (" << hits
305  << " hits) in " << elapsed.count() << " + " << process_time.count()
306  << " ms";
307  }
308 }
309 
316 {
317  assert(root_->getHash().isNonZero());
318  assert(max > 0);
319 
320  MissingNodes mn(
321  max,
322  filter,
324  f_.getFullBelowCache(ledgerSeq_)->getGeneration());
325 
326  if (!root_->isInner() ||
327  std::static_pointer_cast<SHAMapInnerNode>(root_)->isFullBelow(
328  mn.generation_))
329  {
330  clearSynching();
331  return std::move(mn.missingNodes_);
332  }
333 
334  // Start at the root.
335  // The firstChild value is selected randomly so if multiple threads
336  // are traversing the map, each thread will start at a different
337  // (randomly selected) inner node. This increases the likelihood
338  // that the two threads will produce different request sets (which is
339  // more efficient than sending identical requests).
341  static_cast<SHAMapInnerNode*>(root_.get()),
342  SHAMapNodeID(),
343  rand_int(255),
344  0,
345  true};
346  auto& node = std::get<0>(pos);
347  auto& nextChild = std::get<3>(pos);
348  auto& fullBelow = std::get<4>(pos);
349 
350  // Traverse the map without blocking
351  do
352  {
353  while ((node != nullptr) && (mn.deferredReads_.size() <= mn.maxDefer_))
354  {
355  gmn_ProcessNodes(mn, pos);
356 
357  if (mn.max_ <= 0)
358  return std::move(mn.missingNodes_);
359 
360  if ((node == nullptr) && !mn.stack_.empty())
361  {
362  // Pick up where we left off with this node's parent
363  bool was = fullBelow; // was full below
364 
365  pos = mn.stack_.top();
366  mn.stack_.pop();
367  if (nextChild == 0)
368  {
369  // This is a node we are processing for the first time
370  fullBelow = true;
371  }
372  else
373  {
374  // This is a node we are continuing to process
375  fullBelow = fullBelow && was; // was and still is
376  }
377  assert(node);
378  }
379  }
380 
381  // We have either emptied the stack or
382  // posted as many deferred reads as we can
383 
384  if (!mn.deferredReads_.empty())
386 
387  if (mn.max_ <= 0)
388  return std::move(mn.missingNodes_);
389 
390  if (node == nullptr)
391  { // We weren't in the middle of processing a node
392 
393  if (mn.stack_.empty() && !mn.resumes_.empty())
394  {
395  // Recheck nodes we could not finish before
396  for (auto const& [innerNode, nodeId] : mn.resumes_)
397  if (!innerNode->isFullBelow(mn.generation_))
398  mn.stack_.push(std::make_tuple(
399  innerNode, nodeId, rand_int(255), 0, true));
400 
401  mn.resumes_.clear();
402  }
403 
404  if (!mn.stack_.empty())
405  {
406  // Resume at the top of the stack
407  pos = mn.stack_.top();
408  mn.stack_.pop();
409  assert(node != nullptr);
410  }
411  }
412 
413  // node will only still be nullptr if
414  // we finished the current node, the stack is empty
415  // and we have no nodes to resume
416 
417  } while (node != nullptr);
418 
419  if (mn.missingNodes_.empty())
420  clearSynching();
421 
422  return std::move(mn.missingNodes_);
423 }
424 
425 bool
427  SHAMapNodeID const& wanted,
428  std::vector<SHAMapNodeID>& nodeIDs,
429  std::vector<Blob>& rawNodes,
430  bool fatLeaves,
431  std::uint32_t depth) const
432 {
433  // Gets a node and some of its children
434  // to a specified depth
435 
436  auto node = root_.get();
437  SHAMapNodeID nodeID;
438 
439  while (node && node->isInner() && (nodeID.getDepth() < wanted.getDepth()))
440  {
441  int branch = selectBranch(nodeID, wanted.getNodeID());
442  auto inner = static_cast<SHAMapInnerNode*>(node);
443  if (inner->isEmptyBranch(branch))
444  return false;
445 
446  node = descendThrow(inner, branch);
447  nodeID = nodeID.getChildNodeID(branch);
448  }
449 
450  if (node == nullptr || wanted != nodeID)
451  {
452  JLOG(journal_.warn()) << "peer requested node that is not in the map:\n"
453  << wanted << " but found\n"
454  << nodeID;
455  return false;
456  }
457 
458  if (node->isInner() && static_cast<SHAMapInnerNode*>(node)->isEmpty())
459  {
460  JLOG(journal_.warn()) << "peer requests empty node";
461  return false;
462  }
463 
465  stack.emplace(node, nodeID, depth);
466 
467  while (!stack.empty())
468  {
469  std::tie(node, nodeID, depth) = stack.top();
470  stack.pop();
471 
472  {
473  // Add this node to the reply
474  Serializer s;
475  node->serializeForWire(s);
476  nodeIDs.push_back(nodeID);
477  rawNodes.push_back(std::move(s.modData()));
478  }
479 
480  if (node->isInner())
481  {
482  // We descend inner nodes with only a single child
483  // without decrementing the depth
484  auto inner = static_cast<SHAMapInnerNode*>(node);
485  int bc = inner->getBranchCount();
486  if ((depth > 0) || (bc == 1))
487  {
488  // We need to process this node's children
489  for (int i = 0; i < 16; ++i)
490  {
491  if (!inner->isEmptyBranch(i))
492  {
493  auto const childNode = descendThrow(inner, i);
494  SHAMapNodeID const childID = nodeID.getChildNodeID(i);
495 
496  if (childNode->isInner() && ((depth > 1) || (bc == 1)))
497  {
498  // If there's more than one child, reduce the depth
499  // If only one child, follow the chain
500  stack.emplace(
501  childNode,
502  childID,
503  (bc > 1) ? (depth - 1) : depth);
504  }
505  else if (childNode->isInner() || fatLeaves)
506  {
507  // Just include this node
508  Serializer ns;
509  childNode->serializeForWire(ns);
510  nodeIDs.push_back(childID);
511  rawNodes.push_back(std::move(ns.modData()));
512  }
513  }
514  }
515  }
516  }
517  }
518 
519  return true;
520 }
521 
522 void
524 {
525  root_->serializeForWire(s);
526 }
527 
530  SHAMapHash const& hash,
531  Slice const& rootNode,
532  SHAMapSyncFilter* filter)
533 {
534  // we already have a root_ node
535  if (root_->getHash().isNonZero())
536  {
537  JLOG(journal_.trace()) << "got root node, already have one";
538  assert(root_->getHash() == hash);
539  return SHAMapAddNode::duplicate();
540  }
541 
542  assert(cowid_ >= 1);
543  auto node = SHAMapTreeNode::makeFromWire(rootNode);
544  if (!node || node->getHash() != hash)
545  return SHAMapAddNode::invalid();
546 
547  if (backed_)
548  canonicalize(hash, node);
549 
550  root_ = node;
551 
552  if (root_->isLeaf())
553  clearSynching();
554 
555  if (filter)
556  {
557  Serializer s;
558  root_->serializeWithPrefix(s);
559  filter->gotNode(
560  false,
561  root_->getHash(),
562  ledgerSeq_,
563  std::move(s.modData()),
564  root_->getType());
565  }
566 
567  return SHAMapAddNode::useful();
568 }
569 
572  const SHAMapNodeID& node,
573  Slice const& rawNode,
574  SHAMapSyncFilter* filter)
575 {
576  assert(!node.isRoot());
577 
578  if (!isSynching())
579  {
580  JLOG(journal_.trace()) << "AddKnownNode while not synching";
581  return SHAMapAddNode::duplicate();
582  }
583 
584  auto const generation = f_.getFullBelowCache(ledgerSeq_)->getGeneration();
585  auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
586  SHAMapNodeID iNodeID;
587  auto iNode = root_.get();
588 
589  while (iNode->isInner() &&
590  !static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
591  (iNodeID.getDepth() < node.getDepth()))
592  {
593  int branch = selectBranch(iNodeID, node.getNodeID());
594  assert(branch >= 0);
595  auto inner = static_cast<SHAMapInnerNode*>(iNode);
596  if (inner->isEmptyBranch(branch))
597  {
598  JLOG(journal_.warn()) << "Add known node for empty branch" << node;
599  return SHAMapAddNode::invalid();
600  }
601 
602  auto childHash = inner->getChildHash(branch);
604  ->touch_if_exists(childHash.as_uint256()))
605  {
606  return SHAMapAddNode::duplicate();
607  }
608 
609  auto prevNode = inner;
610  std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
611 
612  if (iNode == nullptr)
613  {
614  if (!newNode || childHash != newNode->getHash())
615  {
616  JLOG(journal_.warn()) << "Corrupt node received";
617  return SHAMapAddNode::invalid();
618  }
619 
620  // Inner nodes must be at a level strictly less than 64
621  // but leaf nodes (while notionally at level 64) can be
622  // at any depth up to and including 64:
623  if ((iNodeID.getDepth() > leafDepth) ||
624  (newNode->isInner() && iNodeID.getDepth() == leafDepth))
625  {
626  // Map is provably invalid
628  return SHAMapAddNode::useful();
629  }
630 
631  if (iNodeID != node)
632  {
633  // Either this node is broken or we didn't request it (yet)
634  JLOG(journal_.warn()) << "unable to hook node " << node;
635  JLOG(journal_.info()) << " stuck at " << iNodeID;
636  JLOG(journal_.info()) << "got depth=" << node.getDepth()
637  << ", walked to= " << iNodeID.getDepth();
638  return SHAMapAddNode::useful();
639  }
640 
641  if (backed_)
642  canonicalize(childHash, newNode);
643 
644  newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
645 
646  if (filter)
647  {
648  Serializer s;
649  newNode->serializeWithPrefix(s);
650  filter->gotNode(
651  false,
652  childHash,
653  ledgerSeq_,
654  std::move(s.modData()),
655  newNode->getType());
656  }
657 
658  return SHAMapAddNode::useful();
659  }
660  }
661 
662  JLOG(journal_.trace()) << "got node, already had it (late)";
663  return SHAMapAddNode::duplicate();
664 }
665 
666 bool
668 {
669  // Intended for debug/test only
671 
672  stack.push({root_.get(), other.root_.get()});
673 
674  while (!stack.empty())
675  {
676  auto const [node, otherNode] = stack.top();
677  stack.pop();
678 
679  if (!node || !otherNode)
680  {
681  JLOG(journal_.info()) << "unable to fetch node";
682  return false;
683  }
684  else if (otherNode->getHash() != node->getHash())
685  {
686  JLOG(journal_.warn()) << "node hash mismatch";
687  return false;
688  }
689 
690  if (node->isLeaf())
691  {
692  if (!otherNode->isLeaf())
693  return false;
694  auto& nodePeek = static_cast<SHAMapLeafNode*>(node)->peekItem();
695  auto& otherNodePeek =
696  static_cast<SHAMapLeafNode*>(otherNode)->peekItem();
697  if (nodePeek->key() != otherNodePeek->key())
698  return false;
699  if (nodePeek->peekData() != otherNodePeek->peekData())
700  return false;
701  }
702  else if (node->isInner())
703  {
704  if (!otherNode->isInner())
705  return false;
706  auto node_inner = static_cast<SHAMapInnerNode*>(node);
707  auto other_inner = static_cast<SHAMapInnerNode*>(otherNode);
708  for (int i = 0; i < 16; ++i)
709  {
710  if (node_inner->isEmptyBranch(i))
711  {
712  if (!other_inner->isEmptyBranch(i))
713  return false;
714  }
715  else
716  {
717  if (other_inner->isEmptyBranch(i))
718  return false;
719 
720  auto next = descend(node_inner, i);
721  auto otherNext = other.descend(other_inner, i);
722  if (!next || !otherNext)
723  {
724  JLOG(journal_.warn()) << "unable to fetch inner node";
725  return false;
726  }
727  stack.push({next, otherNext});
728  }
729  }
730  }
731  }
732 
733  return true;
734 }
735 
738 bool
740  SHAMapNodeID const& targetNodeID,
741  SHAMapHash const& targetNodeHash) const
742 {
743  auto node = root_.get();
744  SHAMapNodeID nodeID;
745 
746  while (node->isInner() && (nodeID.getDepth() < targetNodeID.getDepth()))
747  {
748  int branch = selectBranch(nodeID, targetNodeID.getNodeID());
749  auto inner = static_cast<SHAMapInnerNode*>(node);
750  if (inner->isEmptyBranch(branch))
751  return false;
752 
753  node = descendThrow(inner, branch);
754  nodeID = nodeID.getChildNodeID(branch);
755  }
756 
757  return (node->isInner()) && (node->getHash() == targetNodeHash);
758 }
759 
762 bool
763 SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
764 {
765  auto node = root_.get();
766  SHAMapNodeID nodeID;
767 
768  if (!node->isInner()) // only one leaf node in the tree
769  return node->getHash() == targetNodeHash;
770 
771  do
772  {
773  int branch = selectBranch(nodeID, tag);
774  auto inner = static_cast<SHAMapInnerNode*>(node);
775  if (inner->isEmptyBranch(branch))
776  return false; // Dead end, node must not be here
777 
778  if (inner->getChildHash(branch) ==
779  targetNodeHash) // Matching leaf, no need to retrieve it
780  return true;
781 
782  node = descendThrow(inner, branch);
783  nodeID = nodeID.getChildNodeID(branch);
784  } while (node->isInner());
785 
786  return false; // If this was a matching leaf, we would have caught it
787  // already
788 }
789 
790 } // namespace ripple
ripple::SHAMap::MissingNodes
Definition: SHAMap.h:437
ripple::SHAMapAddNode
Definition: SHAMapAddNode.h:28
ripple::SHAMap::visitDifferences
void visitDifferences(SHAMap const *have, std::function< bool(SHAMapTreeNode const &)>) const
Visit every node in this SHAMap that is not present in the specified SHAMap.
Definition: SHAMapSync.cpp:101
ripple::SHAMap::clearSynching
void clearSynching()
Definition: SHAMap.h:531
std::make_tuple
T make_tuple(T... args)
ripple::SHAMap::descendNoStore
std::shared_ptr< SHAMapTreeNode > descendNoStore(std::shared_ptr< SHAMapInnerNode > const &, int branch) const
Definition: SHAMap.cpp:333
ripple::SHAMapNodeID::getChildNodeID
SHAMapNodeID getChildNodeID(unsigned int m) const
Definition: SHAMapNodeID.cpp:74
std::shared_ptr
STL class.
ripple::SHAMap::backed_
bool backed_
Definition: SHAMap.h:110
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::selectBranch
unsigned int selectBranch(SHAMapNodeID const &id, uint256 const &hash)
Returns the branch that would contain the given hash.
Definition: SHAMapNodeID.cpp:121
ripple::SHAMap::deepCompare
bool deepCompare(SHAMap &other) const
Definition: SHAMapSync.cpp:667
ripple::SHAMap::MissingNodes::stack_
std::stack< StackEntry, std::deque< StackEntry > > stack_
Definition: SHAMap.h:467
ripple::SHAMap::hasInnerNode
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
Definition: SHAMapSync.cpp:739
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:176
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
std::pair
std::vector
STL class.
ripple::SHAMap::MissingNodes::maxDefer_
const int maxDefer_
Definition: SHAMap.h:447
ripple::SHAMap::MissingNodes::generation_
std::uint32_t generation_
Definition: SHAMap.h:448
std::stack
STL class.
ripple::SHAMap::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:556
ripple::SHAMap::serializeRoot
void serializeRoot(Serializer &s) const
Serializes the root in a format appropriate for sending over the wire.
Definition: SHAMapSync.cpp:523
std::stack::emplace
T emplace(T... args)
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::SHAMap::fetchNodeNT
std::shared_ptr< SHAMapTreeNode > fetchNodeNT(SHAMapHash const &hash) const
Definition: SHAMap.cpp:253
std::tuple
std::function
ripple::Family::getFullBelowCache
virtual std::shared_ptr< FullBelowCache > getFullBelowCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Full Below Cache.
ripple::SHAMapTreeNode::makeFromWire
static std::shared_ptr< SHAMapTreeNode > makeFromWire(Slice rawNode)
Definition: SHAMapTreeNode.cpp:119
ripple::SHAMapNodeID
Identifies a node inside a SHAMap.
Definition: SHAMapNodeID.h:33
ripple::SHAMap::MissingNodes::filter_
SHAMapSyncFilter * filter_
Definition: SHAMap.h:446
ripple::SHAMapTreeNode::isInner
virtual bool isInner() const =0
Determines if this is an inner node.
ripple::SHAMap::gmn_ProcessNodes
void gmn_ProcessNodes(MissingNodes &, MissingNodes::StackEntry &node)
Definition: SHAMapSync.cpp:173
ripple::Family::db
virtual NodeStore::Database & db()=0
ripple::SHAMapLeafNode
Definition: SHAMapLeafNode.h:32
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:47
ripple::SHAMapAddNode::duplicate
static SHAMapAddNode duplicate()
Definition: SHAMapAddNode.h:138
ripple::SHAMap::f_
Family & f_
Definition: SHAMap.h:98
ripple::SHAMapAddNode::useful
static SHAMapAddNode useful()
Definition: SHAMapAddNode.h:144
std::tie
T tie(T... args)
std::vector::push_back
T push_back(T... args)
ripple::SHAMap::descendAsync
SHAMapTreeNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending) const
Definition: SHAMap.cpp:373
ripple::SHAMapInnerNode::isEmptyBranch
bool isEmptyBranch(int m) const
Definition: SHAMapInnerNode.h:130
ripple::base_uint< 256 >
ripple::SHAMap::MissingNodes::resumes_
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
Definition: SHAMap.h:475
ripple::SHAMap::MissingNodes::deferredReads_
std::vector< std::tuple< SHAMapInnerNode *, SHAMapNodeID, int > > deferredReads_
Definition: SHAMap.h:471
ripple::rand_int
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
Definition: ripple/basics/random.h:115
ripple::HashPrefix::innerNode
@ innerNode
inner node in V1 tree
ripple::SHAMapInnerNode::getChildHash
SHAMapHash const & getChildHash(int m) const
Definition: SHAMapInnerNode.h:136
ripple::SHAMap::hasLeafNode
bool hasLeafNode(uint256 const &tag, SHAMapHash const &hash) const
Does this map have this leaf node?
Definition: SHAMapSync.cpp:763
ripple::SHAMapInnerNode
Definition: SHAMapInnerNode.h:38
ripple::SHAMap::MissingNodes::max_
int max_
Definition: SHAMap.h:445
ripple::SHAMap::visitLeaves
void visitLeaves(std::function< void(std::shared_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
Definition: SHAMapSync.cpp:27
ripple::SHAMapInnerNode::isFullBelow
bool isFullBelow(std::uint32_t generation) const
Definition: SHAMapInnerNode.h:143
ripple::SHAMapAddNode::invalid
static SHAMapAddNode invalid()
Definition: SHAMapAddNode.h:150
ripple::SHAMapSyncFilter::gotNode
virtual void gotNode(bool fromFilter, SHAMapHash const &nodeHash, std::uint32_t ledgerSeq, Blob &&nodeData, SHAMapNodeType type) const =0
ripple::SHAMap::isSynching
bool isSynching() const
Definition: SHAMap.h:519
ripple::SHAMap
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:95
std::stack::pop
T pop(T... args)
std::stack::top
T top(T... args)
ripple::SHAMapTreeNode
Definition: SHAMapTreeNode.h:133
ripple::SHAMap::descendThrow
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:276
ripple::NodeStore::Database::waitReads
void waitReads()
Wait for all currently pending async reads to complete.
Definition: Database.cpp:61
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::SHAMap::journal_
beast::Journal journal_
Definition: SHAMap.h:99
ripple::SHAMap::canonicalize
void canonicalize(SHAMapHash const &hash, std::shared_ptr< SHAMapTreeNode > &) const
Definition: SHAMap.cpp:1101
ripple::SHAMap::MissingNodes::missingHashes_
std::set< SHAMapHash > missingHashes_
Definition: SHAMap.h:452
ripple::SHAMapNodeID::getDepth
unsigned int getDepth() const
Definition: SHAMapNodeID.h:58
ripple::SHAMapInnerNode::getBranchCount
int getBranchCount() const
Definition: SHAMapInnerNode.cpp:190
std::uint32_t
ripple::SHAMap::getMissingNodes
std::vector< std::pair< SHAMapNodeID, uint256 > > getMissingNodes(int maxNodes, SHAMapSyncFilter *filter)
Check for nodes in the SHAMap not available.
Definition: SHAMapSync.cpp:315
ripple::SHAMapTreeNode::getHash
SHAMapHash const & getHash() const
Return the hash of this node.
Definition: SHAMapTreeNode.h:223
ripple::Serializer
Definition: Serializer.h:39
ripple::NodeStore::Database::getDesiredAsyncReadCount
virtual int getDesiredAsyncReadCount(std::uint32_t ledgerSeq)=0
Get the maximum number of async reads the node store prefers.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::SHAMap::leafDepth
static constexpr unsigned int leafDepth
The depth of the hash map: data is only present in the leaves.
Definition: SHAMap.h:118
std::stack::empty
T empty(T... args)
std::stack::push
T push(T... args)
ripple::SHAMap::visitNodes
void visitNodes(std::function< bool(SHAMapTreeNode &)> const &function) const
Visit every node in this SHAMap.
Definition: SHAMapSync.cpp:39
ripple::SHAMap::gmn_ProcessDeferredReads
void gmn_ProcessDeferredReads(MissingNodes &)
Definition: SHAMapSync.cpp:254
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::after
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition: Escrow.cpp:88
ripple::SHAMapState::Invalid
@ Invalid
The map is known to not be valid.
std::make_pair
T make_pair(T... args)
ripple::SHAMapNodeID::getNodeID
uint256 const & getNodeID() const
Definition: SHAMapNodeID.h:64
ripple::SHAMapInnerNode::isEmpty
bool isEmpty() const
Definition: SHAMapInnerNode.cpp:184
ripple::SHAMap::addKnownNode
SHAMapAddNode addKnownNode(SHAMapNodeID const &nodeID, Slice const &rawNode, SHAMapSyncFilter *filter)
Definition: SHAMapSync.cpp:571
ripple::SHAMapLeafNode::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem() const
Definition: SHAMapLeafNode.cpp:44
ripple::SHAMapHash::as_uint256
uint256 const & as_uint256() const
Definition: SHAMapTreeNode.h:58
ripple::SHAMap::descend
SHAMapTreeNode * descend(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:299
ripple::SHAMap::addRootNode
SHAMapAddNode addRootNode(SHAMapHash const &hash, Slice const &rootNode, SHAMapSyncFilter *filter)
Definition: SHAMapSync.cpp:529
ripple::SHAMapInnerNode::setFullBelowGen
void setFullBelowGen(std::uint32_t gen)
Definition: SHAMapInnerNode.h:149
ripple::SHAMap::ledgerSeq_
std::uint32_t ledgerSeq_
The sequence of the ledger that this map references, if any.
Definition: SHAMap.h:105
ripple::SHAMap::getNodeFat
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< SHAMapNodeID > &nodeIDs, std::vector< Blob > &rawNodes, bool fatLeaves, std::uint32_t depth) const
Definition: SHAMapSync.cpp:426
ripple::SHAMapSyncFilter
Definition: SHAMapSyncFilter.h:30
ripple::SHAMap::MissingNodes::missingNodes_
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
Definition: SHAMap.h:451
ripple::SHAMap::cowid_
std::uint32_t cowid_
ID to distinguish this map for all others we're sharing nodes with.
Definition: SHAMap.h:102
ripple::SHAMap::state_
SHAMapState state_
Definition: SHAMap.h:108
ripple::SHAMapNodeID::isRoot
bool isRoot() const
Definition: SHAMapNodeID.h:48
ripple::SHAMap::root_
std::shared_ptr< SHAMapTreeNode > root_
Definition: SHAMap.h:107
std::chrono::steady_clock::now
T now(T... args)