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.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,
429  std::vector<SHAMapNodeID>& nodeIDs,
430  std::vector<Blob>& rawNodes,
431  bool fatLeaves,
432  std::uint32_t depth) const
433 {
434  // Gets a node and some of its children
435  // to a specified depth
436 
437  auto node = root_.get();
438  SHAMapNodeID nodeID;
439 
440  while (node && node->isInner() && (nodeID.getDepth() < wanted.getDepth()))
441  {
442  int branch = selectBranch(nodeID, wanted.getNodeID());
443  auto inner = static_cast<SHAMapInnerNode*>(node);
444  if (inner->isEmptyBranch(branch))
445  return false;
446 
447  node = descendThrow(inner, branch);
448  nodeID = nodeID.getChildNodeID(branch);
449  }
450 
451  if (node == nullptr || wanted != nodeID)
452  {
453  JLOG(journal_.warn()) << "peer requested node that is not in the map:\n"
454  << wanted << " but found\n"
455  << nodeID;
456  return false;
457  }
458 
459  if (node->isInner() && static_cast<SHAMapInnerNode*>(node)->isEmpty())
460  {
461  JLOG(journal_.warn()) << "peer requests empty node";
462  return false;
463  }
464 
466  stack.emplace(node, nodeID, depth);
467 
468  while (!stack.empty())
469  {
470  std::tie(node, nodeID, depth) = stack.top();
471  stack.pop();
472 
473  {
474  // Add this node to the reply
475  Serializer s;
476  node->serializeForWire(s);
477  nodeIDs.push_back(nodeID);
478  rawNodes.push_back(std::move(s.modData()));
479  }
480 
481  if (node->isInner())
482  {
483  // We descend inner nodes with only a single child
484  // without decrementing the depth
485  auto inner = static_cast<SHAMapInnerNode*>(node);
486  int bc = inner->getBranchCount();
487  if ((depth > 0) || (bc == 1))
488  {
489  // We need to process this node's children
490  for (int i = 0; i < 16; ++i)
491  {
492  if (!inner->isEmptyBranch(i))
493  {
494  auto const childNode = descendThrow(inner, i);
495  SHAMapNodeID const childID = nodeID.getChildNodeID(i);
496 
497  if (childNode->isInner() && ((depth > 1) || (bc == 1)))
498  {
499  // If there's more than one child, reduce the depth
500  // If only one child, follow the chain
501  stack.emplace(
502  childNode,
503  childID,
504  (bc > 1) ? (depth - 1) : depth);
505  }
506  else if (childNode->isInner() || fatLeaves)
507  {
508  // Just include this node
509  Serializer ns;
510  childNode->serializeForWire(ns);
511  nodeIDs.push_back(childID);
512  rawNodes.push_back(std::move(ns.modData()));
513  }
514  }
515  }
516  }
517  }
518  }
519 
520  return true;
521 }
522 
523 void
524 SHAMap::serializeRoot(Serializer& s) const
525 {
526  root_->serializeForWire(s);
527 }
528 
530 SHAMap::addRootNode(
531  SHAMapHash const& hash,
532  Slice const& rootNode,
533  SHAMapSyncFilter* filter)
534 {
535  // we already have a root_ node
536  if (root_->getHash().isNonZero())
537  {
538  JLOG(journal_.trace()) << "got root node, already have one";
539  assert(root_->getHash() == hash);
540  return SHAMapAddNode::duplicate();
541  }
542 
543  assert(cowid_ >= 1);
544  auto node = SHAMapTreeNode::makeFromWire(rootNode);
545  if (!node || node->getHash() != hash)
546  return SHAMapAddNode::invalid();
547 
548  if (backed_)
549  canonicalize(hash, node);
550 
551  root_ = node;
552 
553  if (root_->isLeaf())
554  clearSynching();
555 
556  if (filter)
557  {
558  Serializer s;
559  root_->serializeWithPrefix(s);
560  filter->gotNode(
561  false,
562  root_->getHash(),
563  ledgerSeq_,
564  std::move(s.modData()),
565  root_->getType());
566  }
567 
568  return SHAMapAddNode::useful();
569 }
570 
572 SHAMap::addKnownNode(
573  const SHAMapNodeID& node,
574  Slice const& rawNode,
575  SHAMapSyncFilter* filter)
576 {
577  assert(!node.isRoot());
578 
579  if (!isSynching())
580  {
581  JLOG(journal_.trace()) << "AddKnownNode while not synching";
582  return SHAMapAddNode::duplicate();
583  }
584 
585  auto const generation = f_.getFullBelowCache(ledgerSeq_)->getGeneration();
586  auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
587  SHAMapNodeID iNodeID;
588  auto iNode = root_.get();
589 
590  while (iNode->isInner() &&
591  !static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
592  (iNodeID.getDepth() < node.getDepth()))
593  {
594  int branch = selectBranch(iNodeID, node.getNodeID());
595  assert(branch >= 0);
596  auto inner = static_cast<SHAMapInnerNode*>(iNode);
597  if (inner->isEmptyBranch(branch))
598  {
599  JLOG(journal_.warn()) << "Add known node for empty branch" << node;
600  return SHAMapAddNode::invalid();
601  }
602 
603  auto childHash = inner->getChildHash(branch);
604  if (f_.getFullBelowCache(ledgerSeq_)
605  ->touch_if_exists(childHash.as_uint256()))
606  {
607  return SHAMapAddNode::duplicate();
608  }
609 
610  auto prevNode = inner;
611  std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
612 
613  if (iNode == nullptr)
614  {
615  if (!newNode || childHash != newNode->getHash())
616  {
617  JLOG(journal_.warn()) << "Corrupt node received";
618  return SHAMapAddNode::invalid();
619  }
620 
621  // Inner nodes must be at a level strictly less than 64
622  // but leaf nodes (while notionally at level 64) can be
623  // at any depth up to and including 64:
624  if ((iNodeID.getDepth() > leafDepth) ||
625  (newNode->isInner() && iNodeID.getDepth() == leafDepth))
626  {
627  // Map is provably invalid
628  state_ = SHAMapState::Invalid;
629  return SHAMapAddNode::useful();
630  }
631 
632  if (iNodeID != node)
633  {
634  // Either this node is broken or we didn't request it (yet)
635  JLOG(journal_.warn()) << "unable to hook node " << node;
636  JLOG(journal_.info()) << " stuck at " << iNodeID;
637  JLOG(journal_.info()) << "got depth=" << node.getDepth()
638  << ", walked to= " << iNodeID.getDepth();
639  return SHAMapAddNode::useful();
640  }
641 
642  if (backed_)
643  canonicalize(childHash, newNode);
644 
645  newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
646 
647  if (filter)
648  {
649  Serializer s;
650  newNode->serializeWithPrefix(s);
651  filter->gotNode(
652  false,
653  childHash,
654  ledgerSeq_,
655  std::move(s.modData()),
656  newNode->getType());
657  }
658 
659  return SHAMapAddNode::useful();
660  }
661  }
662 
663  JLOG(journal_.trace()) << "got node, already had it (late)";
664  return SHAMapAddNode::duplicate();
665 }
666 
667 bool
668 SHAMap::deepCompare(SHAMap& other) const
669 {
670  // Intended for debug/test only
672 
673  stack.push({root_.get(), other.root_.get()});
674 
675  while (!stack.empty())
676  {
677  auto const [node, otherNode] = stack.top();
678  stack.pop();
679 
680  if (!node || !otherNode)
681  {
682  JLOG(journal_.info()) << "unable to fetch node";
683  return false;
684  }
685  else if (otherNode->getHash() != node->getHash())
686  {
687  JLOG(journal_.warn()) << "node hash mismatch";
688  return false;
689  }
690 
691  if (node->isLeaf())
692  {
693  if (!otherNode->isLeaf())
694  return false;
695  auto& nodePeek = static_cast<SHAMapLeafNode*>(node)->peekItem();
696  auto& otherNodePeek =
697  static_cast<SHAMapLeafNode*>(otherNode)->peekItem();
698  if (nodePeek->key() != otherNodePeek->key())
699  return false;
700  if (nodePeek->slice() != otherNodePeek->slice())
701  return false;
702  }
703  else if (node->isInner())
704  {
705  if (!otherNode->isInner())
706  return false;
707  auto node_inner = static_cast<SHAMapInnerNode*>(node);
708  auto other_inner = static_cast<SHAMapInnerNode*>(otherNode);
709  for (int i = 0; i < 16; ++i)
710  {
711  if (node_inner->isEmptyBranch(i))
712  {
713  if (!other_inner->isEmptyBranch(i))
714  return false;
715  }
716  else
717  {
718  if (other_inner->isEmptyBranch(i))
719  return false;
720 
721  auto next = descend(node_inner, i);
722  auto otherNext = other.descend(other_inner, i);
723  if (!next || !otherNext)
724  {
725  JLOG(journal_.warn()) << "unable to fetch inner node";
726  return false;
727  }
728  stack.push({next, otherNext});
729  }
730  }
731  }
732  }
733 
734  return true;
735 }
736 
739 bool
740 SHAMap::hasInnerNode(
741  SHAMapNodeID const& targetNodeID,
742  SHAMapHash const& targetNodeHash) const
743 {
744  auto node = root_.get();
745  SHAMapNodeID nodeID;
746 
747  while (node->isInner() && (nodeID.getDepth() < targetNodeID.getDepth()))
748  {
749  int branch = selectBranch(nodeID, targetNodeID.getNodeID());
750  auto inner = static_cast<SHAMapInnerNode*>(node);
751  if (inner->isEmptyBranch(branch))
752  return false;
753 
754  node = descendThrow(inner, branch);
755  nodeID = nodeID.getChildNodeID(branch);
756  }
757 
758  return (node->isInner()) && (node->getHash() == targetNodeHash);
759 }
760 
763 bool
764 SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
765 {
766  auto node = root_.get();
767  SHAMapNodeID nodeID;
768 
769  if (!node->isInner()) // only one leaf node in the tree
770  return node->getHash() == targetNodeHash;
771 
772  do
773  {
774  int branch = selectBranch(nodeID, tag);
775  auto inner = static_cast<SHAMapInnerNode*>(node);
776  if (inner->isEmptyBranch(branch))
777  return false; // Dead end, node must not be here
778 
779  if (inner->getChildHash(branch) ==
780  targetNodeHash) // Matching leaf, no need to retrieve it
781  return true;
782 
783  node = descendThrow(inner, branch);
784  nodeID = nodeID.getChildNodeID(branch);
785  } while (node->isInner());
786 
787  return false; // If this was a matching leaf, we would have caught it
788  // already
789 }
790 
792 SHAMap::getProofPath(uint256 const& key) const
793 {
794  SharedPtrNodeStack stack;
795  walkTowardsKey(key, &stack);
796 
797  if (stack.empty())
798  {
799  JLOG(journal_.debug()) << "no path to " << key;
800  return {};
801  }
802 
803  if (auto const& node = stack.top().first; !node || node->isInner() ||
804  std::static_pointer_cast<SHAMapLeafNode>(node)->peekItem()->key() !=
805  key)
806  {
807  JLOG(journal_.debug()) << "no path to " << key;
808  return {};
809  }
810 
811  std::vector<Blob> path;
812  path.reserve(stack.size());
813  while (!stack.empty())
814  {
815  Serializer s;
816  stack.top().first->serializeForWire(s);
817  path.emplace_back(std::move(s.modData()));
818  stack.pop();
819  }
820 
821  JLOG(journal_.debug()) << "getPath for key " << key << ", path length "
822  << path.size();
823  return path;
824 }
825 
826 bool
827 SHAMap::verifyProofPath(
828  uint256 const& rootHash,
829  uint256 const& key,
830  std::vector<Blob> const& path)
831 {
832  if (path.empty() || path.size() > 65)
833  return false;
834 
835  SHAMapHash hash{rootHash};
836  try
837  {
838  for (auto rit = path.rbegin(); rit != path.rend(); ++rit)
839  {
840  auto const& blob = *rit;
841  auto node = SHAMapTreeNode::makeFromWire(makeSlice(blob));
842  if (!node)
843  return false;
844  node->updateHash();
845  if (node->getHash() != hash)
846  return false;
847 
848  auto depth = std::distance(path.rbegin(), rit);
849  if (node->isInner())
850  {
851  auto nodeId = SHAMapNodeID::createID(depth, key);
852  hash = static_cast<SHAMapInnerNode*>(node.get())
853  ->getChildHash(selectBranch(nodeId, key));
854  }
855  else
856  {
857  // should exhaust all the blobs now
858  return depth + 1 == path.size();
859  }
860  }
861  }
862  catch (std::exception const&)
863  {
864  // the data in the path may come from the network,
865  // exception could be thrown when parsing the data
866  return false;
867  }
868  return false;
869 }
870 
871 } // namespace ripple
ripple::SHAMap::MissingNodes
Definition: SHAMap.h:496
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:536
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:526
ripple::SHAMap::hasInnerNode
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
Definition: SHAMapSync.cpp:740
ripple::SHAMap::MissingNodes::deferred_
int deferred_
Definition: SHAMap.h:535
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:506
ripple::SHAMap::MissingNodes::generation_
std::uint32_t generation_
Definition: SHAMap.h:507
std::stack
STL class.
ripple::SHAMap::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:586
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:538
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:505
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)
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:542
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:359
ripple::SHAMap::hasLeafNode
bool hasLeafNode(uint256 const &tag, SHAMapHash const &hash) const
Does this map have this leaf node?
Definition: SHAMapSync.cpp:764
ripple::SHAMapInnerNode
Definition: SHAMapInnerNode.h:39
ripple::SHAMap::MissingNodes::max_
int max_
Definition: SHAMap.h:504
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:53
ripple::SHAMap::descendThrow
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:283
ripple::SHAMap::MissingNodes::missingHashes_
std::set< SHAMapHash > missingHashes_
Definition: SHAMap.h:511
ripple::SHAMapNodeID::getDepth
unsigned int getDepth() const
Definition: SHAMapNodeID.h:58
ripple::SHAMapInnerNode::getBranchCount
int getBranchCount() const
Definition: SHAMapInnerNode.cpp:270
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:537
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:264
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:510
ripple::SHAMapNodeID::isRoot
bool isRoot() const
Definition: SHAMapNodeID.h:48
ripple::SHAMap::root_
std::shared_ptr< SHAMapTreeNode > root_
Definition: SHAMap.h:107