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