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  if (!node->isEmptyBranch(pos))
60  {
62  descendNoStore(node, pos);
63  if (!function(*child))
64  return;
65 
66  if (child->isLeaf())
67  ++pos;
68  else
69  {
70  // If there are no more children, don't push this node
71  while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
72  ++pos;
73 
74  if (pos != 15)
75  {
76  // save next position to resume at
77  stack.push(std::make_pair(pos + 1, std::move(node)));
78  }
79 
80  // descend to the child's first position
81  node = std::static_pointer_cast<SHAMapInnerNode>(child);
82  pos = 0;
83  }
84  }
85  else
86  {
87  ++pos; // move to next position
88  }
89  }
90 
91  if (stack.empty())
92  break;
93 
94  std::tie(pos, node) = stack.top();
95  stack.pop();
96  }
97 }
98 
99 void
101  SHAMap const* have,
102  std::function<bool(SHAMapTreeNode const&)> function) const
103 {
104  // Visit every node in this SHAMap that is not present
105  // in the specified SHAMap
106  if (!root_)
107  return;
108 
109  if (root_->getHash().isZero())
110  return;
111 
112  if (have && (root_->getHash() == have->root_->getHash()))
113  return;
114 
115  if (root_->isLeaf())
116  {
117  auto leaf = std::static_pointer_cast<SHAMapLeafNode>(root_);
118  if (!have ||
119  !have->hasLeafNode(leaf->peekItem()->key(), leaf->getHash()))
120  function(*root_);
121  return;
122  }
123  // contains unexplored non-matching inner node entries
126 
127  stack.push({static_cast<SHAMapInnerNode*>(root_.get()), SHAMapNodeID{}});
128 
129  while (!stack.empty())
130  {
131  auto const [node, nodeID] = stack.top();
132  stack.pop();
133 
134  // 1) Add this node to the pack
135  if (!function(*node))
136  return;
137 
138  // 2) push non-matching child inner nodes
139  for (int i = 0; i < 16; ++i)
140  {
141  if (!node->isEmptyBranch(i))
142  {
143  auto const& childHash = node->getChildHash(i);
144  SHAMapNodeID childID = nodeID.getChildNodeID(i);
145  auto next = descendThrow(node, i);
146 
147  if (next->isInner())
148  {
149  if (!have || !have->hasInnerNode(childID, childHash))
150  stack.push(
151  {static_cast<SHAMapInnerNode*>(next), childID});
152  }
153  else if (
154  !have ||
155  !have->hasLeafNode(
156  static_cast<SHAMapLeafNode*>(next)->peekItem()->key(),
157  childHash))
158  {
159  if (!function(*next))
160  return;
161  }
162  }
163  }
164  }
165 }
166 
167 // Starting at the position referred to by the specfied
168 // StackEntry, process that node and its first resident
169 // children, descending the SHAMap until we complete the
170 // processing of a node.
171 void
173 {
174  SHAMapInnerNode*& node = std::get<0>(se);
175  SHAMapNodeID& nodeID = std::get<1>(se);
176  int& firstChild = std::get<2>(se);
177  int& currentChild = std::get<3>(se);
178  bool& fullBelow = std::get<4>(se);
179 
180  while (currentChild < 16)
181  {
182  int branch = (firstChild + currentChild++) % 16;
183  if (node->isEmptyBranch(branch))
184  continue;
185 
186  auto const& childHash = node->getChildHash(branch);
187 
188  if (mn.missingHashes_.count(childHash) != 0)
189  {
190  // we already know this child node is missing
191  fullBelow = false;
192  }
193  else if (
194  !backed_ ||
196  ->touch_if_exists(childHash.as_uint256()))
197  {
198  bool pending = false;
199  auto d = descendAsync(
200  node,
201  branch,
202  mn.filter_,
203  pending,
204  [node, nodeID, branch, &mn](
206  // a read completed asynchronously
207  std::unique_lock<std::mutex> lock{mn.deferLock_};
208  mn.finishedReads_.emplace_back(
209  node, nodeID, branch, std::move(found));
211  });
212 
213  if (pending)
214  {
215  fullBelow = false;
216  ++mn.deferred_;
217  }
218  else if (!d)
219  {
220  // node is not in database
221 
222  fullBelow = false; // for now, not known full below
223  mn.missingHashes_.insert(childHash);
224  mn.missingNodes_.emplace_back(
225  nodeID.getChildNodeID(branch), childHash.as_uint256());
226 
227  if (--mn.max_ <= 0)
228  return;
229  }
230  else if (
231  d->isInner() &&
232  !static_cast<SHAMapInnerNode*>(d)->isFullBelow(mn.generation_))
233  {
234  mn.stack_.push(se);
235 
236  // Switch to processing the child node
237  node = static_cast<SHAMapInnerNode*>(d);
238  nodeID = nodeID.getChildNodeID(branch);
239  firstChild = rand_int(255);
240  currentChild = 0;
241  fullBelow = true;
242  }
243  }
244  }
245 
246  // We have finished processing an inner node
247  // and thus (for now) all its children
248 
249  if (fullBelow)
250  { // No partial node encountered below this node
251  node->setFullBelowGen(mn.generation_);
252  if (backed_)
253  {
254  f_.getFullBelowCache(ledgerSeq_)
255  ->insert(node->getHash().as_uint256());
256  }
257  }
258 
259  node = nullptr;
260 }
261 
262 // Wait for deferred reads to finish and
263 // process their results
264 void
265 SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn)
266 {
267  // Process all deferred reads
268  int complete = 0;
269  while (complete != mn.deferred_)
270  {
271  std::tuple<
273  SHAMapNodeID,
274  int,
276  deferredNode;
277  {
279 
280  while (mn.finishedReads_.size() <= complete)
281  mn.deferCondVar_.wait(lock);
282  deferredNode = std::move(mn.finishedReads_[complete++]);
283  }
284 
285  auto parent = std::get<0>(deferredNode);
286  auto const& parentID = std::get<1>(deferredNode);
287  auto branch = std::get<2>(deferredNode);
288  auto nodePtr = std::get<3>(deferredNode);
289  auto const& nodeHash = parent->getChildHash(branch);
290 
291  if (nodePtr)
292  { // Got the node
293  nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
294 
295  // When we finish this stack, we need to restart
296  // with the parent of this node
297  mn.resumes_[parent] = parentID;
298  }
299  else if ((mn.max_ > 0) && (mn.missingHashes_.insert(nodeHash).second))
300  {
301  mn.missingNodes_.emplace_back(
302  parentID.getChildNodeID(branch), nodeHash.as_uint256());
303  --mn.max_;
304  }
305  }
306 
307  mn.finishedReads_.clear();
308  mn.deferred_ = 0;
309 }
310 
316 SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter)
317 {
318  assert(root_->getHash().isNonZero());
319  assert(max > 0);
320 
321  MissingNodes mn(
322  max,
323  filter,
324  4096, // number of async reads per pass
325  f_.getFullBelowCache(ledgerSeq_)->getGeneration());
326 
327  if (!root_->isInner() ||
328  std::static_pointer_cast<SHAMapInnerNode>(root_)->isFullBelow(
329  mn.generation_))
330  {
331  clearSynching();
332  return std::move(mn.missingNodes_);
333  }
334 
335  // Start at the root.
336  // The firstChild value is selected randomly so if multiple threads
337  // are traversing the map, each thread will start at a different
338  // (randomly selected) inner node. This increases the likelihood
339  // that the two threads will produce different request sets (which is
340  // more efficient than sending identical requests).
342  static_cast<SHAMapInnerNode*>(root_.get()),
343  SHAMapNodeID(),
344  rand_int(255),
345  0,
346  true};
347  auto& node = std::get<0>(pos);
348  auto& nextChild = std::get<3>(pos);
349  auto& fullBelow = std::get<4>(pos);
350 
351  // Traverse the map without blocking
352  do
353  {
354  while ((node != nullptr) && (mn.deferred_ <= mn.maxDefer_))
355  {
356  gmn_ProcessNodes(mn, pos);
357 
358  if (mn.max_ <= 0)
359  break;
360 
361  if ((node == nullptr) && !mn.stack_.empty())
362  {
363  // Pick up where we left off with this node's parent
364  bool was = fullBelow; // was full below
365 
366  pos = mn.stack_.top();
367  mn.stack_.pop();
368  if (nextChild == 0)
369  {
370  // This is a node we are processing for the first time
371  fullBelow = true;
372  }
373  else
374  {
375  // This is a node we are continuing to process
376  fullBelow = fullBelow && was; // was and still is
377  }
378  assert(node);
379  }
380  }
381 
382  // We have either emptied the stack or
383  // posted as many deferred reads as we can
384  if (mn.deferred_)
385  gmn_ProcessDeferredReads(mn);
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
426 SHAMap::getNodeFat(
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
523 SHAMap::serializeRoot(Serializer& s) const
524 {
525  root_->serializeForWire(s);
526 }
527 
529 SHAMap::addRootNode(
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 
571 SHAMap::addKnownNode(
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);
603  if (f_.getFullBelowCache(ledgerSeq_)
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
627  state_ = SHAMapState::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
667 SHAMap::deepCompare(SHAMap& other) const
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->slice() != otherNodePeek->slice())
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
739 SHAMap::hasInnerNode(
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 
791 SHAMap::getProofPath(uint256 const& key) const
792 {
793  SharedPtrNodeStack stack;
794  walkTowardsKey(key, &stack);
795 
796  if (stack.empty())
797  {
798  JLOG(journal_.debug()) << "no path to " << key;
799  return {};
800  }
801 
802  if (auto const& node = stack.top().first; !node || node->isInner() ||
803  std::static_pointer_cast<SHAMapLeafNode>(node)->peekItem()->key() !=
804  key)
805  {
806  JLOG(journal_.debug()) << "no path to " << key;
807  return {};
808  }
809 
810  std::vector<Blob> path;
811  path.reserve(stack.size());
812  while (!stack.empty())
813  {
814  Serializer s;
815  stack.top().first->serializeForWire(s);
816  path.emplace_back(std::move(s.modData()));
817  stack.pop();
818  }
819 
820  JLOG(journal_.debug()) << "getPath for key " << key << ", path length "
821  << path.size();
822  return path;
823 }
824 
825 bool
826 SHAMap::verifyProofPath(
827  uint256 const& rootHash,
828  uint256 const& key,
829  std::vector<Blob> const& path)
830 {
831  if (path.empty() || path.size() > 65)
832  return false;
833 
834  SHAMapHash hash{rootHash};
835  try
836  {
837  for (auto rit = path.rbegin(); rit != path.rend(); ++rit)
838  {
839  auto const& blob = *rit;
840  auto node = SHAMapTreeNode::makeFromWire(makeSlice(blob));
841  if (!node)
842  return false;
843  node->updateHash();
844  if (node->getHash() != hash)
845  return false;
846 
847  auto depth = std::distance(path.rbegin(), rit);
848  if (node->isInner())
849  {
850  auto nodeId = SHAMapNodeID::createID(depth, key);
851  hash = static_cast<SHAMapInnerNode*>(node.get())
852  ->getChildHash(selectBranch(nodeId, key));
853  }
854  else
855  {
856  // should exhaust all the blobs now
857  return depth + 1 == path.size();
858  }
859  }
860  }
861  catch (std::exception const&)
862  {
863  // the data in the path may come from the network,
864  // exception could be thrown when parsing the data
865  return false;
866  }
867  return false;
868 }
869 
870 } // namespace ripple
ripple::SHAMap::MissingNodes
Definition: SHAMap.h:465
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:100
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:340
ripple::ListDisposition::pending
@ pending
List will be valid in the future.
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:240
ripple::SHAMapNodeID::getChildNodeID
SHAMapNodeID getChildNodeID(unsigned int m) const
Definition: SHAMapNodeID.cpp:74
ripple::SHAMap::MissingNodes::deferLock_
std::mutex deferLock_
Definition: SHAMap.h:505
ripple::ShardState::complete
@ complete
std::shared_ptr
STL class.
ripple::SHAMap::backed_
bool backed_
Definition: SHAMap.h:110
std::exception
STL class.
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::MissingNodes::stack_
std::stack< StackEntry, std::deque< StackEntry > > stack_
Definition: SHAMap.h:495
ripple::SHAMap::hasInnerNode
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
Definition: SHAMapSync.cpp:739
ripple::SHAMap::MissingNodes::deferred_
int deferred_
Definition: SHAMap.h:504
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:178
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
std::pair
std::vector
STL class.
std::stack::size
T size(T... args)
ripple::SHAMap::MissingNodes::maxDefer_
const int maxDefer_
Definition: SHAMap.h:475
ripple::SHAMap::MissingNodes::generation_
std::uint32_t generation_
Definition: SHAMap.h:476
std::stack
STL class.
ripple::SHAMap::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:561
std::stack::emplace
T emplace(T... args)
std::distance
T distance(T... args)
std::tuple
ripple::SHAMap::MissingNodes::finishedReads_
std::vector< DeferredNode > finishedReads_
Definition: SHAMap.h:507
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
Identifies a node inside a SHAMap.
Definition: SHAMapNodeID.h:33
ripple::SHAMap::MissingNodes::filter_
SHAMapSyncFilter * filter_
Definition: SHAMap.h:474
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:172
ripple::SHAMapLeafNode
Definition: SHAMapLeafNode.h:32
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:48
ripple::SHAMap::f_
Family & f_
Definition: SHAMap.h:98
std::tie
T tie(T... args)
std::vector::push_back
T push_back(T... args)
ripple::SHAMapInnerNode::isEmptyBranch
bool isEmptyBranch(int m) const
Definition: SHAMapInnerNode.h:195
ripple::base_uint< 256 >
ripple::SHAMap::MissingNodes::resumes_
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
Definition: SHAMap.h:511
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.cpp:353
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:39
ripple::SHAMap::MissingNodes::max_
int max_
Definition: SHAMap.h:473
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:201
ripple::SHAMapSyncFilter::gotNode
virtual void gotNode(bool fromFilter, SHAMapHash const &nodeHash, std::uint32_t ledgerSeq, Blob &&nodeData, SHAMapNodeType type) const =0
std::unique_lock
STL class.
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:134
ripple::SHAMap::descendThrow
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:283
ripple::SHAMap::MissingNodes::missingHashes_
std::set< SHAMapHash > missingHashes_
Definition: SHAMap.h:480
ripple::SHAMapNodeID::getDepth
unsigned int getDepth() const
Definition: SHAMapNodeID.h:58
ripple::SHAMapInnerNode::getBranchCount
int getBranchCount() const
Definition: SHAMapInnerNode.cpp:264
std::uint32_t
std::condition_variable::wait
T wait(T... args)
std::condition_variable::notify_one
T notify_one(T... args)
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::MissingNodes::deferCondVar_
std::condition_variable deferCondVar_
Definition: SHAMap.h:506
ripple::SHAMap::descendAsync
SHAMapTreeNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending, descendCallback &&) const
Definition: SHAMap.cpp:380
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
std::optional
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:258
ripple::SHAMapLeafNode::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem() const
Definition: SHAMapLeafNode.cpp:44
ripple::SHAMap::descend
SHAMapTreeNode * descend(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:306
ripple::SHAMap::ledgerSeq_
std::uint32_t ledgerSeq_
The sequence of the ledger that this map references, if any.
Definition: SHAMap.h:105
ripple::SHAMapSyncFilter
Definition: SHAMapSyncFilter.h:30
ripple::SHAMap::MissingNodes::missingNodes_
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
Definition: SHAMap.h:479
ripple::SHAMapNodeID::isRoot
bool isRoot() const
Definition: SHAMapNodeID.h:48
ripple::SHAMap::root_
std::shared_ptr< SHAMapTreeNode > root_
Definition: SHAMap.h:107