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(boost::intrusive_ptr<SHAMapItem const> const&
29  item)> const& 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 (true)
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&)> 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.finishedReads_.reserve(mn.maxDefer_);
309  mn.deferred_ = 0;
310 }
311 
317 SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter)
318 {
319  assert(root_->getHash().isNonZero());
320  assert(max > 0);
321 
322  MissingNodes mn(
323  max,
324  filter,
325  512, // number of async reads per pass
326  f_.getFullBelowCache(ledgerSeq_)->getGeneration());
327 
328  if (!root_->isInner() ||
329  std::static_pointer_cast<SHAMapInnerNode>(root_)->isFullBelow(
330  mn.generation_))
331  {
332  clearSynching();
333  return std::move(mn.missingNodes_);
334  }
335 
336  // Start at the root.
337  // The firstChild value is selected randomly so if multiple threads
338  // are traversing the map, each thread will start at a different
339  // (randomly selected) inner node. This increases the likelihood
340  // that the two threads will produce different request sets (which is
341  // more efficient than sending identical requests).
343  static_cast<SHAMapInnerNode*>(root_.get()),
344  SHAMapNodeID(),
345  rand_int(255),
346  0,
347  true};
348  auto& node = std::get<0>(pos);
349  auto& nextChild = std::get<3>(pos);
350  auto& fullBelow = std::get<4>(pos);
351 
352  // Traverse the map without blocking
353  do
354  {
355  while ((node != nullptr) && (mn.deferred_ <= mn.maxDefer_))
356  {
357  gmn_ProcessNodes(mn, pos);
358 
359  if (mn.max_ <= 0)
360  break;
361 
362  if ((node == nullptr) && !mn.stack_.empty())
363  {
364  // Pick up where we left off with this node's parent
365  bool was = fullBelow; // was full below
366 
367  pos = mn.stack_.top();
368  mn.stack_.pop();
369  if (nextChild == 0)
370  {
371  // This is a node we are processing for the first time
372  fullBelow = true;
373  }
374  else
375  {
376  // This is a node we are continuing to process
377  fullBelow = fullBelow && was; // was and still is
378  }
379  assert(node);
380  }
381  }
382 
383  // We have either emptied the stack or
384  // posted as many deferred reads as we can
385  if (mn.deferred_)
386  gmn_ProcessDeferredReads(mn);
387 
388  if (mn.max_ <= 0)
389  return std::move(mn.missingNodes_);
390 
391  if (node == nullptr)
392  { // We weren't in the middle of processing a node
393 
394  if (mn.stack_.empty() && !mn.resumes_.empty())
395  {
396  // Recheck nodes we could not finish before
397  for (auto const& [innerNode, nodeId] : mn.resumes_)
398  if (!innerNode->isFullBelow(mn.generation_))
399  mn.stack_.push(std::make_tuple(
400  innerNode, nodeId, rand_int(255), 0, true));
401 
402  mn.resumes_.clear();
403  }
404 
405  if (!mn.stack_.empty())
406  {
407  // Resume at the top of the stack
408  pos = mn.stack_.top();
409  mn.stack_.pop();
410  assert(node != nullptr);
411  }
412  }
413 
414  // node will only still be nullptr if
415  // we finished the current node, the stack is empty
416  // and we have no nodes to resume
417 
418  } while (node != nullptr);
419 
420  if (mn.missingNodes_.empty())
421  clearSynching();
422 
423  return std::move(mn.missingNodes_);
424 }
425 
426 bool
427 SHAMap::getNodeFat(
428  SHAMapNodeID const& wanted,
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  node = descendThrow(inner, branch);
446  nodeID = nodeID.getChildNodeID(branch);
447  }
448 
449  if (node == nullptr || wanted != nodeID)
450  {
451  JLOG(journal_.info())
452  << "peer requested node that is not in the map: " << wanted
453  << " but found " << nodeID;
454  return false;
455  }
456 
457  if (node->isInner() && static_cast<SHAMapInnerNode*>(node)->isEmpty())
458  {
459  JLOG(journal_.warn()) << "peer requests empty node";
460  return false;
461  }
462 
464  stack.emplace(node, nodeID, depth);
465 
466  Serializer s(8192);
467 
468  while (!stack.empty())
469  {
470  std::tie(node, nodeID, depth) = stack.top();
471  stack.pop();
472 
473  // Add this node to the reply
474  s.erase();
475  node->serializeForWire(s);
476  data.emplace_back(std::make_pair(nodeID, s.getData()));
477 
478  if (node->isInner())
479  {
480  // We descend inner nodes with only a single child
481  // without decrementing the depth
482  auto inner = static_cast<SHAMapInnerNode*>(node);
483  int bc = inner->getBranchCount();
484 
485  if ((depth > 0) || (bc == 1))
486  {
487  // We need to process this node's children
488  for (int i = 0; i < 16; ++i)
489  {
490  if (!inner->isEmptyBranch(i))
491  {
492  auto const childNode = descendThrow(inner, i);
493  auto const childID = nodeID.getChildNodeID(i);
494 
495  if (childNode->isInner() && ((depth > 1) || (bc == 1)))
496  {
497  // If there's more than one child, reduce the depth
498  // If only one child, follow the chain
499  stack.emplace(
500  childNode,
501  childID,
502  (bc > 1) ? (depth - 1) : depth);
503  }
504  else if (childNode->isInner() || fatLeaves)
505  {
506  // Just include this node
507  s.erase();
508  childNode->serializeForWire(s);
509  data.emplace_back(
510  std::make_pair(childID, s.getData()));
511  }
512  }
513  }
514  }
515  }
516  }
517 
518  return true;
519 }
520 
521 void
522 SHAMap::serializeRoot(Serializer& s) const
523 {
524  root_->serializeForWire(s);
525 }
526 
528 SHAMap::addRootNode(
529  SHAMapHash const& hash,
530  Slice const& rootNode,
531  SHAMapSyncFilter* filter)
532 {
533  // we already have a root_ node
534  if (root_->getHash().isNonZero())
535  {
536  JLOG(journal_.trace()) << "got root node, already have one";
537  assert(root_->getHash() == hash);
538  return SHAMapAddNode::duplicate();
539  }
540 
541  assert(cowid_ >= 1);
542  auto node = SHAMapTreeNode::makeFromWire(rootNode);
543  if (!node || node->getHash() != hash)
544  return SHAMapAddNode::invalid();
545 
546  if (backed_)
547  canonicalize(hash, node);
548 
549  root_ = node;
550 
551  if (root_->isLeaf())
552  clearSynching();
553 
554  if (filter)
555  {
556  Serializer s;
557  root_->serializeWithPrefix(s);
558  filter->gotNode(
559  false,
560  root_->getHash(),
561  ledgerSeq_,
562  std::move(s.modData()),
563  root_->getType());
564  }
565 
566  return SHAMapAddNode::useful();
567 }
568 
570 SHAMap::addKnownNode(
571  const SHAMapNodeID& node,
572  Slice const& rawNode,
573  SHAMapSyncFilter* filter)
574 {
575  assert(!node.isRoot());
576 
577  if (!isSynching())
578  {
579  JLOG(journal_.trace()) << "AddKnownNode while not synching";
580  return SHAMapAddNode::duplicate();
581  }
582 
583  auto const generation = f_.getFullBelowCache(ledgerSeq_)->getGeneration();
584  SHAMapNodeID iNodeID;
585  auto iNode = root_.get();
586 
587  while (iNode->isInner() &&
588  !static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
589  (iNodeID.getDepth() < node.getDepth()))
590  {
591  int branch = selectBranch(iNodeID, node.getNodeID());
592  assert(branch >= 0);
593  auto inner = static_cast<SHAMapInnerNode*>(iNode);
594  if (inner->isEmptyBranch(branch))
595  {
596  JLOG(journal_.warn()) << "Add known node for empty branch" << node;
597  return SHAMapAddNode::invalid();
598  }
599 
600  auto childHash = inner->getChildHash(branch);
601  if (f_.getFullBelowCache(ledgerSeq_)
602  ->touch_if_exists(childHash.as_uint256()))
603  {
604  return SHAMapAddNode::duplicate();
605  }
606 
607  auto prevNode = inner;
608  std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
609 
610  if (iNode == nullptr)
611  {
612  auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
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:510
ripple::SHAMapAddNode
Definition: SHAMapAddNode.h:28
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:346
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:241
ripple::SHAMapNodeID::getChildNodeID
SHAMapNodeID getChildNodeID(unsigned int m) const
Definition: SHAMapNodeID.cpp:74
ripple::SHAMap::MissingNodes::deferLock_
std::mutex deferLock_
Definition: SHAMap.h:550
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:540
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:549
ripple::SHAMap::peekItem
boost::intrusive_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:592
ripple::SHAMapLeafNode::peekItem
boost::intrusive_ptr< SHAMapItem const > const & peekItem() const
Definition: SHAMapLeafNode.cpp:44
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:178
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
ripple::Serializer::erase
void erase()
Definition: Serializer.h:209
std::pair
std::vector
STL class.
std::stack::size
T size(T... args)
ripple::SHAMap::MissingNodes::maxDefer_
const int maxDefer_
Definition: SHAMap.h:520
ripple::SHAMap::MissingNodes::generation_
std::uint32_t generation_
Definition: SHAMap.h:521
std::stack
STL class.
std::stack::emplace
T emplace(T... args)
std::distance
T distance(T... args)
std::tuple
ripple::SHAMap::visitDifferences
void visitDifferences(SHAMap const *have, std::function< bool(SHAMapTreeNode const &)> const &) const
Visit every node in this SHAMap that is not present in the specified SHAMap.
Definition: SHAMapSync.cpp:100
ripple::SHAMap::MissingNodes::finishedReads_
std::vector< DeferredNode > finishedReads_
Definition: SHAMap.h:552
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:519
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: SHAMapHash.h:32
ripple::SHAMap::f_
Family & f_
Definition: SHAMap.h:98
std::tie
T tie(T... args)
ripple::SHAMapInnerNode::isEmptyBranch
bool isEmptyBranch(int m) const
Definition: SHAMapInnerNode.h:198
ripple::base_uint< 256 >
ripple::SHAMap::MissingNodes::resumes_
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
Definition: SHAMap.h:556
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:361
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:41
ripple::SHAMap::MissingNodes::max_
int max_
Definition: SHAMap.h:518
ripple::SHAMapInnerNode::isFullBelow
bool isFullBelow(std::uint32_t generation) const
Definition: SHAMapInnerNode.h:204
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:53
ripple::SHAMap::descendThrow
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:289
ripple::SHAMap::MissingNodes::missingHashes_
std::set< SHAMapHash > missingHashes_
Definition: SHAMap.h:525
ripple::SHAMapNodeID::getDepth
unsigned int getDepth() const
Definition: SHAMapNodeID.h:58
ripple::SHAMapInnerNode::getBranchCount
int getBranchCount() const
Definition: SHAMapInnerNode.cpp:266
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:551
ripple::SHAMap::descendAsync
SHAMapTreeNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending, descendCallback &&) const
Definition: SHAMap.cpp:386
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::Serializer::getData
Blob getData() const
Definition: Serializer.h:173
ripple::SHAMapNodeID::getNodeID
uint256 const & getNodeID() const
Definition: SHAMapNodeID.h:64
ripple::SHAMapInnerNode::isEmpty
bool isEmpty() const
Definition: SHAMapInnerNode.cpp:260
ripple::SHAMap::descend
SHAMapTreeNode * descend(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:312
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:524
ripple::SHAMapNodeID::isRoot
bool isRoot() const
Definition: SHAMapNodeID.h:48
ripple::SHAMap::root_
std::shared_ptr< SHAMapTreeNode > root_
Definition: SHAMap.h:107
ripple::SHAMap::visitLeaves
void visitLeaves(std::function< void(boost::intrusive_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
Definition: SHAMapSync.cpp:27