rippled
Loading...
Searching...
No Matches
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 <xrpld/shamap/SHAMap.h>
21#include <xrpld/shamap/SHAMapSyncFilter.h>
22#include <xrpl/basics/random.h>
23
24namespace ripple {
25
26void
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
38void
39SHAMap::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
99void
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.
171void
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_ ||
195 !f_.getFullBelowCache()->touch_if_exists(childHash.as_uint256()))
196 {
197 bool pending = false;
198 auto d = descendAsync(
199 node,
200 branch,
201 mn.filter_,
202 pending,
203 [node, nodeID, branch, &mn](
205 // a read completed asynchronously
206 std::unique_lock<std::mutex> lock{mn.deferLock_};
207 mn.finishedReads_.emplace_back(
208 node, nodeID, branch, std::move(found));
210 });
211
212 if (pending)
213 {
214 fullBelow = false;
215 ++mn.deferred_;
216 }
217 else if (!d)
218 {
219 // node is not in database
220
221 fullBelow = false; // for now, not known full below
222 mn.missingHashes_.insert(childHash);
223 mn.missingNodes_.emplace_back(
224 nodeID.getChildNodeID(branch), childHash.as_uint256());
225
226 if (--mn.max_ <= 0)
227 return;
228 }
229 else if (
230 d->isInner() &&
231 !static_cast<SHAMapInnerNode*>(d)->isFullBelow(mn.generation_))
232 {
233 mn.stack_.push(se);
234
235 // Switch to processing the child node
236 node = static_cast<SHAMapInnerNode*>(d);
237 nodeID = nodeID.getChildNodeID(branch);
238 firstChild = rand_int(255);
239 currentChild = 0;
240 fullBelow = true;
241 }
242 }
243 }
244
245 // We have finished processing an inner node
246 // and thus (for now) all its children
247
248 if (fullBelow)
249 { // No partial node encountered below this node
250 node->setFullBelowGen(mn.generation_);
251 if (backed_)
252 {
253 f_.getFullBelowCache()->insert(node->getHash().as_uint256());
254 }
255 }
256
257 node = nullptr;
258}
259
260// Wait for deferred reads to finish and
261// process their results
262void
263SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn)
264{
265 // Process all deferred reads
266 int complete = 0;
267 while (complete != mn.deferred_)
268 {
272 int,
274 deferredNode;
275 {
277
278 while (mn.finishedReads_.size() <= complete)
279 mn.deferCondVar_.wait(lock);
280 deferredNode = std::move(mn.finishedReads_[complete++]);
281 }
282
283 auto parent = std::get<0>(deferredNode);
284 auto const& parentID = std::get<1>(deferredNode);
285 auto branch = std::get<2>(deferredNode);
286 auto nodePtr = std::get<3>(deferredNode);
287 auto const& nodeHash = parent->getChildHash(branch);
288
289 if (nodePtr)
290 { // Got the node
291 nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
292
293 // When we finish this stack, we need to restart
294 // with the parent of this node
295 mn.resumes_[parent] = parentID;
296 }
297 else if ((mn.max_ > 0) && (mn.missingHashes_.insert(nodeHash).second))
298 {
299 mn.missingNodes_.emplace_back(
300 parentID.getChildNodeID(branch), nodeHash.as_uint256());
301 --mn.max_;
302 }
303 }
304
305 mn.finishedReads_.clear();
306 mn.finishedReads_.reserve(mn.maxDefer_);
307 mn.deferred_ = 0;
308}
309
315SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter)
316{
317 XRPL_ASSERT(
318 root_->getHash().isNonZero(),
319 "ripple::SHAMap::getMissingNodes : nonzero root hash");
320 XRPL_ASSERT(max > 0, "ripple::SHAMap::getMissingNodes : valid max input");
321
322 MissingNodes mn(
323 max,
324 filter,
325 512, // number of async reads per pass
326 f_.getFullBelowCache()->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 XRPL_ASSERT(
380 node,
381 "ripple::SHAMap::getMissingNodes : first non-null node");
382 }
383 }
384
385 // We have either emptied the stack or
386 // posted as many deferred reads as we can
387 if (mn.deferred_)
388 gmn_ProcessDeferredReads(mn);
389
390 if (mn.max_ <= 0)
391 return std::move(mn.missingNodes_);
392
393 if (node == nullptr)
394 { // We weren't in the middle of processing a node
395
396 if (mn.stack_.empty() && !mn.resumes_.empty())
397 {
398 // Recheck nodes we could not finish before
399 for (auto const& [innerNode, nodeId] : mn.resumes_)
400 if (!innerNode->isFullBelow(mn.generation_))
401 mn.stack_.push(std::make_tuple(
402 innerNode, nodeId, rand_int(255), 0, true));
403
404 mn.resumes_.clear();
405 }
406
407 if (!mn.stack_.empty())
408 {
409 // Resume at the top of the stack
410 pos = mn.stack_.top();
411 mn.stack_.pop();
412 XRPL_ASSERT(
413 node,
414 "ripple::SHAMap::getMissingNodes : second non-null node");
415 }
416 }
417
418 // node will only still be nullptr if
419 // we finished the current node, the stack is empty
420 // and we have no nodes to resume
421
422 } while (node != nullptr);
423
424 if (mn.missingNodes_.empty())
425 clearSynching();
426
427 return std::move(mn.missingNodes_);
428}
429
430bool
431SHAMap::getNodeFat(
432 SHAMapNodeID const& wanted,
434 bool fatLeaves,
435 std::uint32_t depth) const
436{
437 // Gets a node and some of its children
438 // to a specified depth
439
440 auto node = root_.get();
441 SHAMapNodeID nodeID;
442
443 while (node && node->isInner() && (nodeID.getDepth() < wanted.getDepth()))
444 {
445 int branch = selectBranch(nodeID, wanted.getNodeID());
446 auto inner = static_cast<SHAMapInnerNode*>(node);
447 if (inner->isEmptyBranch(branch))
448 return false;
449 node = descendThrow(inner, branch);
450 nodeID = nodeID.getChildNodeID(branch);
451 }
452
453 if (node == nullptr || wanted != nodeID)
454 {
455 JLOG(journal_.info())
456 << "peer requested node that is not in the map: " << wanted
457 << " but found " << nodeID;
458 return false;
459 }
460
461 if (node->isInner() && static_cast<SHAMapInnerNode*>(node)->isEmpty())
462 {
463 JLOG(journal_.warn()) << "peer requests empty node";
464 return false;
465 }
466
468 stack.emplace(node, nodeID, depth);
469
470 Serializer s(8192);
471
472 while (!stack.empty())
473 {
474 std::tie(node, nodeID, depth) = stack.top();
475 stack.pop();
476
477 // Add this node to the reply
478 s.erase();
479 node->serializeForWire(s);
480 data.emplace_back(std::make_pair(nodeID, s.getData()));
481
482 if (node->isInner())
483 {
484 // We descend inner nodes with only a single child
485 // without decrementing the depth
486 auto inner = static_cast<SHAMapInnerNode*>(node);
487 int bc = inner->getBranchCount();
488
489 if ((depth > 0) || (bc == 1))
490 {
491 // We need to process this node's children
492 for (int i = 0; i < 16; ++i)
493 {
494 if (!inner->isEmptyBranch(i))
495 {
496 auto const childNode = descendThrow(inner, i);
497 auto const childID = nodeID.getChildNodeID(i);
498
499 if (childNode->isInner() && ((depth > 1) || (bc == 1)))
500 {
501 // If there's more than one child, reduce the depth
502 // If only one child, follow the chain
503 stack.emplace(
504 childNode,
505 childID,
506 (bc > 1) ? (depth - 1) : depth);
507 }
508 else if (childNode->isInner() || fatLeaves)
509 {
510 // Just include this node
511 s.erase();
512 childNode->serializeForWire(s);
513 data.emplace_back(
514 std::make_pair(childID, s.getData()));
515 }
516 }
517 }
518 }
519 }
520 }
521
522 return true;
523}
524
525void
526SHAMap::serializeRoot(Serializer& s) const
527{
528 root_->serializeForWire(s);
529}
530
532SHAMap::addRootNode(
533 SHAMapHash const& hash,
534 Slice const& rootNode,
535 SHAMapSyncFilter* filter)
536{
537 // we already have a root_ node
538 if (root_->getHash().isNonZero())
539 {
540 JLOG(journal_.trace()) << "got root node, already have one";
541 XRPL_ASSERT(
542 root_->getHash() == hash,
543 "ripple::SHAMap::addRootNode : valid hash input");
544 return SHAMapAddNode::duplicate();
545 }
546
547 XRPL_ASSERT(cowid_ >= 1, "ripple::SHAMap::addRootNode : valid cowid");
548 auto node = SHAMapTreeNode::makeFromWire(rootNode);
549 if (!node || node->getHash() != hash)
550 return SHAMapAddNode::invalid();
551
552 if (backed_)
553 canonicalize(hash, node);
554
555 root_ = node;
556
557 if (root_->isLeaf())
558 clearSynching();
559
560 if (filter)
561 {
562 Serializer s;
563 root_->serializeWithPrefix(s);
564 filter->gotNode(
565 false,
566 root_->getHash(),
567 ledgerSeq_,
568 std::move(s.modData()),
569 root_->getType());
570 }
571
572 return SHAMapAddNode::useful();
573}
574
576SHAMap::addKnownNode(
577 const SHAMapNodeID& node,
578 Slice const& rawNode,
579 SHAMapSyncFilter* filter)
580{
581 XRPL_ASSERT(
582 !node.isRoot(), "ripple::SHAMap::addKnownNode : valid node input");
583
584 if (!isSynching())
585 {
586 JLOG(journal_.trace()) << "AddKnownNode while not synching";
587 return SHAMapAddNode::duplicate();
588 }
589
590 auto const generation = f_.getFullBelowCache()->getGeneration();
591 SHAMapNodeID iNodeID;
592 auto iNode = root_.get();
593
594 while (iNode->isInner() &&
595 !static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
596 (iNodeID.getDepth() < node.getDepth()))
597 {
598 int branch = selectBranch(iNodeID, node.getNodeID());
599 XRPL_ASSERT(branch >= 0, "ripple::SHAMap::addKnownNode : valid branch");
600 auto inner = static_cast<SHAMapInnerNode*>(iNode);
601 if (inner->isEmptyBranch(branch))
602 {
603 JLOG(journal_.warn()) << "Add known node for empty branch" << node;
604 return SHAMapAddNode::invalid();
605 }
606
607 auto childHash = inner->getChildHash(branch);
608 if (f_.getFullBelowCache()->touch_if_exists(childHash.as_uint256()))
609 {
610 return SHAMapAddNode::duplicate();
611 }
612
613 auto prevNode = inner;
614 std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
615
616 if (iNode == nullptr)
617 {
618 auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
619
620 if (!newNode || childHash != newNode->getHash())
621 {
622 JLOG(journal_.warn()) << "Corrupt node received";
623 return SHAMapAddNode::invalid();
624 }
625
626 // Inner nodes must be at a level strictly less than 64
627 // but leaf nodes (while notionally at level 64) can be
628 // at any depth up to and including 64:
629 if ((iNodeID.getDepth() > leafDepth) ||
630 (newNode->isInner() && iNodeID.getDepth() == leafDepth))
631 {
632 // Map is provably invalid
633 state_ = SHAMapState::Invalid;
634 return SHAMapAddNode::useful();
635 }
636
637 if (iNodeID != node)
638 {
639 // Either this node is broken or we didn't request it (yet)
640 JLOG(journal_.warn()) << "unable to hook node " << node;
641 JLOG(journal_.info()) << " stuck at " << iNodeID;
642 JLOG(journal_.info()) << "got depth=" << node.getDepth()
643 << ", walked to= " << iNodeID.getDepth();
644 return SHAMapAddNode::useful();
645 }
646
647 if (backed_)
648 canonicalize(childHash, newNode);
649
650 newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
651
652 if (filter)
653 {
654 Serializer s;
655 newNode->serializeWithPrefix(s);
656 filter->gotNode(
657 false,
658 childHash,
659 ledgerSeq_,
660 std::move(s.modData()),
661 newNode->getType());
662 }
663
664 return SHAMapAddNode::useful();
665 }
666 }
667
668 JLOG(journal_.trace()) << "got node, already had it (late)";
669 return SHAMapAddNode::duplicate();
670}
671
672bool
673SHAMap::deepCompare(SHAMap& other) const
674{
675 // Intended for debug/test only
677
678 stack.push({root_.get(), other.root_.get()});
679
680 while (!stack.empty())
681 {
682 auto const [node, otherNode] = stack.top();
683 stack.pop();
684
685 if (!node || !otherNode)
686 {
687 JLOG(journal_.info()) << "unable to fetch node";
688 return false;
689 }
690 else if (otherNode->getHash() != node->getHash())
691 {
692 JLOG(journal_.warn()) << "node hash mismatch";
693 return false;
694 }
695
696 if (node->isLeaf())
697 {
698 if (!otherNode->isLeaf())
699 return false;
700 auto& nodePeek = static_cast<SHAMapLeafNode*>(node)->peekItem();
701 auto& otherNodePeek =
702 static_cast<SHAMapLeafNode*>(otherNode)->peekItem();
703 if (nodePeek->key() != otherNodePeek->key())
704 return false;
705 if (nodePeek->slice() != otherNodePeek->slice())
706 return false;
707 }
708 else if (node->isInner())
709 {
710 if (!otherNode->isInner())
711 return false;
712 auto node_inner = static_cast<SHAMapInnerNode*>(node);
713 auto other_inner = static_cast<SHAMapInnerNode*>(otherNode);
714 for (int i = 0; i < 16; ++i)
715 {
716 if (node_inner->isEmptyBranch(i))
717 {
718 if (!other_inner->isEmptyBranch(i))
719 return false;
720 }
721 else
722 {
723 if (other_inner->isEmptyBranch(i))
724 return false;
725
726 auto next = descend(node_inner, i);
727 auto otherNext = other.descend(other_inner, i);
728 if (!next || !otherNext)
729 {
730 JLOG(journal_.warn()) << "unable to fetch inner node";
731 return false;
732 }
733 stack.push({next, otherNext});
734 }
735 }
736 }
737 }
738
739 return true;
740}
741
744bool
745SHAMap::hasInnerNode(
746 SHAMapNodeID const& targetNodeID,
747 SHAMapHash const& targetNodeHash) const
748{
749 auto node = root_.get();
750 SHAMapNodeID nodeID;
751
752 while (node->isInner() && (nodeID.getDepth() < targetNodeID.getDepth()))
753 {
754 int branch = selectBranch(nodeID, targetNodeID.getNodeID());
755 auto inner = static_cast<SHAMapInnerNode*>(node);
756 if (inner->isEmptyBranch(branch))
757 return false;
758
759 node = descendThrow(inner, branch);
760 nodeID = nodeID.getChildNodeID(branch);
761 }
762
763 return (node->isInner()) && (node->getHash() == targetNodeHash);
764}
765
768bool
769SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
770{
771 auto node = root_.get();
772 SHAMapNodeID nodeID;
773
774 if (!node->isInner()) // only one leaf node in the tree
775 return node->getHash() == targetNodeHash;
776
777 do
778 {
779 int branch = selectBranch(nodeID, tag);
780 auto inner = static_cast<SHAMapInnerNode*>(node);
781 if (inner->isEmptyBranch(branch))
782 return false; // Dead end, node must not be here
783
784 if (inner->getChildHash(branch) ==
785 targetNodeHash) // Matching leaf, no need to retrieve it
786 return true;
787
788 node = descendThrow(inner, branch);
789 nodeID = nodeID.getChildNodeID(branch);
790 } while (node->isInner());
791
792 return false; // If this was a matching leaf, we would have caught it
793 // already
794}
795
797SHAMap::getProofPath(uint256 const& key) const
798{
799 SharedPtrNodeStack stack;
800 walkTowardsKey(key, &stack);
801
802 if (stack.empty())
803 {
804 JLOG(journal_.debug()) << "no path to " << key;
805 return {};
806 }
807
808 if (auto const& node = stack.top().first; !node || node->isInner() ||
809 std::static_pointer_cast<SHAMapLeafNode>(node)->peekItem()->key() !=
810 key)
811 {
812 JLOG(journal_.debug()) << "no path to " << key;
813 return {};
814 }
815
817 path.reserve(stack.size());
818 while (!stack.empty())
819 {
820 Serializer s;
821 stack.top().first->serializeForWire(s);
822 path.emplace_back(std::move(s.modData()));
823 stack.pop();
824 }
825
826 JLOG(journal_.debug()) << "getPath for key " << key << ", path length "
827 << path.size();
828 return path;
829}
830
831bool
832SHAMap::verifyProofPath(
833 uint256 const& rootHash,
834 uint256 const& key,
835 std::vector<Blob> const& path)
836{
837 if (path.empty() || path.size() > 65)
838 return false;
839
840 SHAMapHash hash{rootHash};
841 try
842 {
843 for (auto rit = path.rbegin(); rit != path.rend(); ++rit)
844 {
845 auto const& blob = *rit;
846 auto node = SHAMapTreeNode::makeFromWire(makeSlice(blob));
847 if (!node)
848 return false;
849 node->updateHash();
850 if (node->getHash() != hash)
851 return false;
852
853 auto depth = std::distance(path.rbegin(), rit);
854 if (node->isInner())
855 {
856 auto nodeId = SHAMapNodeID::createID(depth, key);
857 hash = static_cast<SHAMapInnerNode*>(node.get())
858 ->getChildHash(selectBranch(nodeId, key));
859 }
860 else
861 {
862 // should exhaust all the blobs now
863 return depth + 1 == path.size();
864 }
865 }
866 }
867 catch (std::exception const&)
868 {
869 // the data in the path may come from the network,
870 // exception could be thrown when parsing the data
871 return false;
872 }
873 return false;
874}
875
876} // namespace ripple
virtual std::shared_ptr< FullBelowCache > getFullBelowCache()=0
Return a pointer to the Family Full Below Cache.
bool isFullBelow(std::uint32_t generation) const
bool isEmptyBranch(int m) const
SHAMapHash const & getChildHash(int m) const
boost::intrusive_ptr< SHAMapItem const > const & peekItem() const
Identifies a node inside a SHAMap.
Definition: SHAMapNodeID.h:34
unsigned int getDepth() const
Definition: SHAMapNodeID.h:58
uint256 const & getNodeID() const
Definition: SHAMapNodeID.h:64
bool isRoot() const
Definition: SHAMapNodeID.h:48
SHAMapNodeID getChildNodeID(unsigned int m) const
virtual void gotNode(bool fromFilter, SHAMapHash const &nodeHash, std::uint32_t ledgerSeq, Blob &&nodeData, SHAMapNodeType type) const =0
virtual bool isInner() const =0
Determines if this is an inner node.
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:96
SHAMapTreeNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending, descendCallback &&) const
Definition: SHAMap.cpp:395
bool backed_
Definition: SHAMap.h:110
void gmn_ProcessNodes(MissingNodes &, MissingNodes::StackEntry &node)
Definition: SHAMapSync.cpp:172
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:293
boost::intrusive_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:617
Family & f_
Definition: SHAMap.h:98
SHAMapTreeNode * descend(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:316
std::shared_ptr< SHAMapTreeNode > root_
Definition: SHAMap.h:107
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
Definition: SHAMapSync.cpp:745
std::shared_ptr< SHAMapTreeNode > descendNoStore(std::shared_ptr< SHAMapInnerNode > const &, int branch) const
Definition: SHAMap.cpp:350
void visitNodes(std::function< bool(SHAMapTreeNode &)> const &function) const
Visit every node in this SHAMap.
Definition: SHAMapSync.cpp:39
bool hasLeafNode(uint256 const &tag, SHAMapHash const &hash) const
Does this map have this leaf node?
Definition: SHAMapSync.cpp:769
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
void visitLeaves(std::function< void(boost::intrusive_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
Definition: SHAMapSync.cpp:27
Blob getData() const
Definition: Serializer.h:207
An immutable linear range of bytes.
Definition: Slice.h:45
T distance(T... args)
T emplace(T... args)
T empty(T... args)
T make_pair(T... args)
T make_tuple(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
unsigned int selectBranch(SHAMapNodeID const &id, uint256 const &hash)
Returns the branch that would contain the given hash.
@ pending
List will be valid in the future.
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.
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:243
@ innerNode
inner node in V1 tree
T pop(T... args)
T push(T... args)
T size(T... args)
std::set< SHAMapHash > missingHashes_
Definition: SHAMap.h:525
std::stack< StackEntry, std::deque< StackEntry > > stack_
Definition: SHAMap.h:540
std::condition_variable deferCondVar_
Definition: SHAMap.h:551
std::uint32_t generation_
Definition: SHAMap.h:521
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
Definition: SHAMap.h:524
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
Definition: SHAMap.h:556
SHAMapSyncFilter * filter_
Definition: SHAMap.h:519
std::vector< DeferredNode > finishedReads_
Definition: SHAMap.h:552
T tie(T... args)
T top(T... args)