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
23#include <xrpl/basics/random.h>
24
25namespace ripple {
26
27void
29 std::function<void(boost::intrusive_ptr<SHAMapItem const> const&
30 item)> const& leafFunction) const
31{
32 visitNodes([&leafFunction](SHAMapTreeNode& node) {
33 if (!node.isInner())
34 leafFunction(static_cast<SHAMapLeafNode&>(node).peekItem());
35 return true;
36 });
37}
38
39void
40SHAMap::visitNodes(std::function<bool(SHAMapTreeNode&)> const& function) const
41{
42 if (!root_)
43 return;
44
45 function(*root_);
46
47 if (!root_->isInner())
48 return;
49
52
53 auto node = std::static_pointer_cast<SHAMapInnerNode>(root_);
54 int pos = 0;
55
56 while (true)
57 {
58 while (pos < 16)
59 {
60 if (!node->isEmptyBranch(pos))
61 {
63 descendNoStore(node, pos);
64 if (!function(*child))
65 return;
66
67 if (child->isLeaf())
68 ++pos;
69 else
70 {
71 // If there are no more children, don't push this node
72 while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
73 ++pos;
74
75 if (pos != 15)
76 {
77 // save next position to resume at
78 stack.push(std::make_pair(pos + 1, std::move(node)));
79 }
80
81 // descend to the child's first position
82 node = std::static_pointer_cast<SHAMapInnerNode>(child);
83 pos = 0;
84 }
85 }
86 else
87 {
88 ++pos; // move to next position
89 }
90 }
91
92 if (stack.empty())
93 break;
94
95 std::tie(pos, node) = stack.top();
96 stack.pop();
97 }
98}
99
100void
102 SHAMap const* have,
103 std::function<bool(SHAMapTreeNode const&)> const& function) const
104{
105 // Visit every node in this SHAMap that is not present
106 // in the specified SHAMap
107 if (!root_)
108 return;
109
110 if (root_->getHash().isZero())
111 return;
112
113 if (have && (root_->getHash() == have->root_->getHash()))
114 return;
115
116 if (root_->isLeaf())
117 {
118 auto leaf = std::static_pointer_cast<SHAMapLeafNode>(root_);
119 if (!have ||
120 !have->hasLeafNode(leaf->peekItem()->key(), leaf->getHash()))
121 function(*root_);
122 return;
123 }
124 // contains unexplored non-matching inner node entries
127
128 stack.push({static_cast<SHAMapInnerNode*>(root_.get()), SHAMapNodeID{}});
129
130 while (!stack.empty())
131 {
132 auto const [node, nodeID] = stack.top();
133 stack.pop();
134
135 // 1) Add this node to the pack
136 if (!function(*node))
137 return;
138
139 // 2) push non-matching child inner nodes
140 for (int i = 0; i < 16; ++i)
141 {
142 if (!node->isEmptyBranch(i))
143 {
144 auto const& childHash = node->getChildHash(i);
145 SHAMapNodeID childID = nodeID.getChildNodeID(i);
146 auto next = descendThrow(node, i);
147
148 if (next->isInner())
149 {
150 if (!have || !have->hasInnerNode(childID, childHash))
151 stack.push(
152 {static_cast<SHAMapInnerNode*>(next), childID});
153 }
154 else if (
155 !have ||
156 !have->hasLeafNode(
157 static_cast<SHAMapLeafNode*>(next)->peekItem()->key(),
158 childHash))
159 {
160 if (!function(*next))
161 return;
162 }
163 }
164 }
165 }
166}
167
168// Starting at the position referred to by the specfied
169// StackEntry, process that node and its first resident
170// children, descending the SHAMap until we complete the
171// processing of a node.
172void
174{
175 SHAMapInnerNode*& node = std::get<0>(se);
176 SHAMapNodeID& nodeID = std::get<1>(se);
177 int& firstChild = std::get<2>(se);
178 int& currentChild = std::get<3>(se);
179 bool& fullBelow = std::get<4>(se);
180
181 while (currentChild < 16)
182 {
183 int branch = (firstChild + currentChild++) % 16;
184 if (node->isEmptyBranch(branch))
185 continue;
186
187 auto const& childHash = node->getChildHash(branch);
188
189 if (mn.missingHashes_.count(childHash) != 0)
190 {
191 // we already know this child node is missing
192 fullBelow = false;
193 }
194 else if (
195 !backed_ ||
196 !f_.getFullBelowCache()->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()->insert(node->getHash().as_uint256());
255 }
256 }
257
258 node = nullptr;
259}
260
261// Wait for deferred reads to finish and
262// process their results
263void
264SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn)
265{
266 // Process all deferred reads
267 int complete = 0;
268 while (complete != mn.deferred_)
269 {
273 int,
275 deferredNode;
276 {
278
279 while (mn.finishedReads_.size() <= complete)
280 mn.deferCondVar_.wait(lock);
281 deferredNode = std::move(mn.finishedReads_[complete++]);
282 }
283
284 auto parent = std::get<0>(deferredNode);
285 auto const& parentID = std::get<1>(deferredNode);
286 auto branch = std::get<2>(deferredNode);
287 auto nodePtr = std::get<3>(deferredNode);
288 auto const& nodeHash = parent->getChildHash(branch);
289
290 if (nodePtr)
291 { // Got the node
292 nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
293
294 // When we finish this stack, we need to restart
295 // with the parent of this node
296 mn.resumes_[parent] = parentID;
297 }
298 else if ((mn.max_ > 0) && (mn.missingHashes_.insert(nodeHash).second))
299 {
300 mn.missingNodes_.emplace_back(
301 parentID.getChildNodeID(branch), nodeHash.as_uint256());
302 --mn.max_;
303 }
304 }
305
306 mn.finishedReads_.clear();
307 mn.finishedReads_.reserve(mn.maxDefer_);
308 mn.deferred_ = 0;
309}
310
316SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter)
317{
318 XRPL_ASSERT(
319 root_->getHash().isNonZero(),
320 "ripple::SHAMap::getMissingNodes : nonzero root hash");
321 XRPL_ASSERT(max > 0, "ripple::SHAMap::getMissingNodes : valid max input");
322
323 MissingNodes mn(
324 max,
325 filter,
326 512, // number of async reads per pass
327 f_.getFullBelowCache()->getGeneration());
328
329 if (!root_->isInner() ||
330 std::static_pointer_cast<SHAMapInnerNode>(root_)->isFullBelow(
331 mn.generation_))
332 {
333 clearSynching();
334 return std::move(mn.missingNodes_);
335 }
336
337 // Start at the root.
338 // The firstChild value is selected randomly so if multiple threads
339 // are traversing the map, each thread will start at a different
340 // (randomly selected) inner node. This increases the likelihood
341 // that the two threads will produce different request sets (which is
342 // more efficient than sending identical requests).
344 static_cast<SHAMapInnerNode*>(root_.get()),
345 SHAMapNodeID(),
346 rand_int(255),
347 0,
348 true};
349 auto& node = std::get<0>(pos);
350 auto& nextChild = std::get<3>(pos);
351 auto& fullBelow = std::get<4>(pos);
352
353 // Traverse the map without blocking
354 do
355 {
356 while ((node != nullptr) && (mn.deferred_ <= mn.maxDefer_))
357 {
358 gmn_ProcessNodes(mn, pos);
359
360 if (mn.max_ <= 0)
361 break;
362
363 if ((node == nullptr) && !mn.stack_.empty())
364 {
365 // Pick up where we left off with this node's parent
366 bool was = fullBelow; // was full below
367
368 pos = mn.stack_.top();
369 mn.stack_.pop();
370 if (nextChild == 0)
371 {
372 // This is a node we are processing for the first time
373 fullBelow = true;
374 }
375 else
376 {
377 // This is a node we are continuing to process
378 fullBelow = fullBelow && was; // was and still is
379 }
380 XRPL_ASSERT(
381 node,
382 "ripple::SHAMap::getMissingNodes : first non-null node");
383 }
384 }
385
386 // We have either emptied the stack or
387 // posted as many deferred reads as we can
388 if (mn.deferred_)
389 gmn_ProcessDeferredReads(mn);
390
391 if (mn.max_ <= 0)
392 return std::move(mn.missingNodes_);
393
394 if (node == nullptr)
395 { // We weren't in the middle of processing a node
396
397 if (mn.stack_.empty() && !mn.resumes_.empty())
398 {
399 // Recheck nodes we could not finish before
400 for (auto const& [innerNode, nodeId] : mn.resumes_)
401 if (!innerNode->isFullBelow(mn.generation_))
402 mn.stack_.push(std::make_tuple(
403 innerNode, nodeId, rand_int(255), 0, true));
404
405 mn.resumes_.clear();
406 }
407
408 if (!mn.stack_.empty())
409 {
410 // Resume at the top of the stack
411 pos = mn.stack_.top();
412 mn.stack_.pop();
413 XRPL_ASSERT(
414 node,
415 "ripple::SHAMap::getMissingNodes : second non-null node");
416 }
417 }
418
419 // node will only still be nullptr if
420 // we finished the current node, the stack is empty
421 // and we have no nodes to resume
422
423 } while (node != nullptr);
424
425 if (mn.missingNodes_.empty())
426 clearSynching();
427
428 return std::move(mn.missingNodes_);
429}
430
431bool
432SHAMap::getNodeFat(
433 SHAMapNodeID const& wanted,
435 bool fatLeaves,
436 std::uint32_t depth) const
437{
438 // Gets a node and some of its children
439 // to a specified depth
440
441 auto node = root_.get();
442 SHAMapNodeID nodeID;
443
444 while (node && node->isInner() && (nodeID.getDepth() < wanted.getDepth()))
445 {
446 int branch = selectBranch(nodeID, wanted.getNodeID());
447 auto inner = static_cast<SHAMapInnerNode*>(node);
448 if (inner->isEmptyBranch(branch))
449 return false;
450 node = descendThrow(inner, branch);
451 nodeID = nodeID.getChildNodeID(branch);
452 }
453
454 if (node == nullptr || wanted != nodeID)
455 {
456 JLOG(journal_.info())
457 << "peer requested node that is not in the map: " << wanted
458 << " but found " << nodeID;
459 return false;
460 }
461
462 if (node->isInner() && static_cast<SHAMapInnerNode*>(node)->isEmpty())
463 {
464 JLOG(journal_.warn()) << "peer requests empty node";
465 return false;
466 }
467
469 stack.emplace(node, nodeID, depth);
470
471 Serializer s(8192);
472
473 while (!stack.empty())
474 {
475 std::tie(node, nodeID, depth) = stack.top();
476 stack.pop();
477
478 // Add this node to the reply
479 s.erase();
480 node->serializeForWire(s);
481 data.emplace_back(std::make_pair(nodeID, s.getData()));
482
483 if (node->isInner())
484 {
485 // We descend inner nodes with only a single child
486 // without decrementing the depth
487 auto inner = static_cast<SHAMapInnerNode*>(node);
488 int bc = inner->getBranchCount();
489
490 if ((depth > 0) || (bc == 1))
491 {
492 // We need to process this node's children
493 for (int i = 0; i < 16; ++i)
494 {
495 if (!inner->isEmptyBranch(i))
496 {
497 auto const childNode = descendThrow(inner, i);
498 auto const childID = nodeID.getChildNodeID(i);
499
500 if (childNode->isInner() && ((depth > 1) || (bc == 1)))
501 {
502 // If there's more than one child, reduce the depth
503 // If only one child, follow the chain
504 stack.emplace(
505 childNode,
506 childID,
507 (bc > 1) ? (depth - 1) : depth);
508 }
509 else if (childNode->isInner() || fatLeaves)
510 {
511 // Just include this node
512 s.erase();
513 childNode->serializeForWire(s);
514 data.emplace_back(
515 std::make_pair(childID, s.getData()));
516 }
517 }
518 }
519 }
520 }
521 }
522
523 return true;
524}
525
526void
527SHAMap::serializeRoot(Serializer& s) const
528{
529 root_->serializeForWire(s);
530}
531
533SHAMap::addRootNode(
534 SHAMapHash const& hash,
535 Slice const& rootNode,
536 SHAMapSyncFilter* filter)
537{
538 // we already have a root_ node
539 if (root_->getHash().isNonZero())
540 {
541 JLOG(journal_.trace()) << "got root node, already have one";
542 XRPL_ASSERT(
543 root_->getHash() == hash,
544 "ripple::SHAMap::addRootNode : valid hash input");
545 return SHAMapAddNode::duplicate();
546 }
547
548 XRPL_ASSERT(cowid_ >= 1, "ripple::SHAMap::addRootNode : valid cowid");
549 auto node = SHAMapTreeNode::makeFromWire(rootNode);
550 if (!node || node->getHash() != hash)
551 return SHAMapAddNode::invalid();
552
553 if (backed_)
554 canonicalize(hash, node);
555
556 root_ = node;
557
558 if (root_->isLeaf())
559 clearSynching();
560
561 if (filter)
562 {
563 Serializer s;
564 root_->serializeWithPrefix(s);
565 filter->gotNode(
566 false,
567 root_->getHash(),
568 ledgerSeq_,
569 std::move(s.modData()),
570 root_->getType());
571 }
572
573 return SHAMapAddNode::useful();
574}
575
577SHAMap::addKnownNode(
578 const SHAMapNodeID& node,
579 Slice const& rawNode,
580 SHAMapSyncFilter* filter)
581{
582 XRPL_ASSERT(
583 !node.isRoot(), "ripple::SHAMap::addKnownNode : valid node input");
584
585 if (!isSynching())
586 {
587 JLOG(journal_.trace()) << "AddKnownNode while not synching";
588 return SHAMapAddNode::duplicate();
589 }
590
591 auto const generation = f_.getFullBelowCache()->getGeneration();
592 SHAMapNodeID iNodeID;
593 auto iNode = root_.get();
594
595 while (iNode->isInner() &&
596 !static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
597 (iNodeID.getDepth() < node.getDepth()))
598 {
599 int branch = selectBranch(iNodeID, node.getNodeID());
600 XRPL_ASSERT(branch >= 0, "ripple::SHAMap::addKnownNode : valid branch");
601 auto inner = static_cast<SHAMapInnerNode*>(iNode);
602 if (inner->isEmptyBranch(branch))
603 {
604 JLOG(journal_.warn()) << "Add known node for empty branch" << node;
605 return SHAMapAddNode::invalid();
606 }
607
608 auto childHash = inner->getChildHash(branch);
609 if (f_.getFullBelowCache()->touch_if_exists(childHash.as_uint256()))
610 {
611 return SHAMapAddNode::duplicate();
612 }
613
614 auto prevNode = inner;
615 std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
616
617 if (iNode == nullptr)
618 {
619 auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
620
621 if (!newNode || childHash != newNode->getHash())
622 {
623 JLOG(journal_.warn()) << "Corrupt node received";
624 return SHAMapAddNode::invalid();
625 }
626
627 // Inner nodes must be at a level strictly less than 64
628 // but leaf nodes (while notionally at level 64) can be
629 // at any depth up to and including 64:
630 if ((iNodeID.getDepth() > leafDepth) ||
631 (newNode->isInner() && iNodeID.getDepth() == leafDepth))
632 {
633 // Map is provably invalid
634 state_ = SHAMapState::Invalid;
635 return SHAMapAddNode::useful();
636 }
637
638 if (iNodeID != node)
639 {
640 // Either this node is broken or we didn't request it (yet)
641 JLOG(journal_.warn()) << "unable to hook node " << node;
642 JLOG(journal_.info()) << " stuck at " << iNodeID;
643 JLOG(journal_.info()) << "got depth=" << node.getDepth()
644 << ", walked to= " << iNodeID.getDepth();
645 return SHAMapAddNode::useful();
646 }
647
648 if (backed_)
649 canonicalize(childHash, newNode);
650
651 newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
652
653 if (filter)
654 {
655 Serializer s;
656 newNode->serializeWithPrefix(s);
657 filter->gotNode(
658 false,
659 childHash,
660 ledgerSeq_,
661 std::move(s.modData()),
662 newNode->getType());
663 }
664
665 return SHAMapAddNode::useful();
666 }
667 }
668
669 JLOG(journal_.trace()) << "got node, already had it (late)";
670 return SHAMapAddNode::duplicate();
671}
672
673bool
674SHAMap::deepCompare(SHAMap& other) const
675{
676 // Intended for debug/test only
678
679 stack.push({root_.get(), other.root_.get()});
680
681 while (!stack.empty())
682 {
683 auto const [node, otherNode] = stack.top();
684 stack.pop();
685
686 if (!node || !otherNode)
687 {
688 JLOG(journal_.info()) << "unable to fetch node";
689 return false;
690 }
691 else if (otherNode->getHash() != node->getHash())
692 {
693 JLOG(journal_.warn()) << "node hash mismatch";
694 return false;
695 }
696
697 if (node->isLeaf())
698 {
699 if (!otherNode->isLeaf())
700 return false;
701 auto& nodePeek = static_cast<SHAMapLeafNode*>(node)->peekItem();
702 auto& otherNodePeek =
703 static_cast<SHAMapLeafNode*>(otherNode)->peekItem();
704 if (nodePeek->key() != otherNodePeek->key())
705 return false;
706 if (nodePeek->slice() != otherNodePeek->slice())
707 return false;
708 }
709 else if (node->isInner())
710 {
711 if (!otherNode->isInner())
712 return false;
713 auto node_inner = static_cast<SHAMapInnerNode*>(node);
714 auto other_inner = static_cast<SHAMapInnerNode*>(otherNode);
715 for (int i = 0; i < 16; ++i)
716 {
717 if (node_inner->isEmptyBranch(i))
718 {
719 if (!other_inner->isEmptyBranch(i))
720 return false;
721 }
722 else
723 {
724 if (other_inner->isEmptyBranch(i))
725 return false;
726
727 auto next = descend(node_inner, i);
728 auto otherNext = other.descend(other_inner, i);
729 if (!next || !otherNext)
730 {
731 JLOG(journal_.warn()) << "unable to fetch inner node";
732 return false;
733 }
734 stack.push({next, otherNext});
735 }
736 }
737 }
738 }
739
740 return true;
741}
742
745bool
746SHAMap::hasInnerNode(
747 SHAMapNodeID const& targetNodeID,
748 SHAMapHash const& targetNodeHash) const
749{
750 auto node = root_.get();
751 SHAMapNodeID nodeID;
752
753 while (node->isInner() && (nodeID.getDepth() < targetNodeID.getDepth()))
754 {
755 int branch = selectBranch(nodeID, targetNodeID.getNodeID());
756 auto inner = static_cast<SHAMapInnerNode*>(node);
757 if (inner->isEmptyBranch(branch))
758 return false;
759
760 node = descendThrow(inner, branch);
761 nodeID = nodeID.getChildNodeID(branch);
762 }
763
764 return (node->isInner()) && (node->getHash() == targetNodeHash);
765}
766
769bool
770SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
771{
772 auto node = root_.get();
773 SHAMapNodeID nodeID;
774
775 if (!node->isInner()) // only one leaf node in the tree
776 return node->getHash() == targetNodeHash;
777
778 do
779 {
780 int branch = selectBranch(nodeID, tag);
781 auto inner = static_cast<SHAMapInnerNode*>(node);
782 if (inner->isEmptyBranch(branch))
783 return false; // Dead end, node must not be here
784
785 if (inner->getChildHash(branch) ==
786 targetNodeHash) // Matching leaf, no need to retrieve it
787 return true;
788
789 node = descendThrow(inner, branch);
790 nodeID = nodeID.getChildNodeID(branch);
791 } while (node->isInner());
792
793 return false; // If this was a matching leaf, we would have caught it
794 // already
795}
796
798SHAMap::getProofPath(uint256 const& key) const
799{
800 SharedPtrNodeStack stack;
801 walkTowardsKey(key, &stack);
802
803 if (stack.empty())
804 {
805 JLOG(journal_.debug()) << "no path to " << key;
806 return {};
807 }
808
809 if (auto const& node = stack.top().first; !node || node->isInner() ||
810 std::static_pointer_cast<SHAMapLeafNode>(node)->peekItem()->key() !=
811 key)
812 {
813 JLOG(journal_.debug()) << "no path to " << key;
814 return {};
815 }
816
818 path.reserve(stack.size());
819 while (!stack.empty())
820 {
821 Serializer s;
822 stack.top().first->serializeForWire(s);
823 path.emplace_back(std::move(s.modData()));
824 stack.pop();
825 }
826
827 JLOG(journal_.debug()) << "getPath for key " << key << ", path length "
828 << path.size();
829 return path;
830}
831
832bool
833SHAMap::verifyProofPath(
834 uint256 const& rootHash,
835 uint256 const& key,
836 std::vector<Blob> const& path)
837{
838 if (path.empty() || path.size() > 65)
839 return false;
840
841 SHAMapHash hash{rootHash};
842 try
843 {
844 for (auto rit = path.rbegin(); rit != path.rend(); ++rit)
845 {
846 auto const& blob = *rit;
847 auto node = SHAMapTreeNode::makeFromWire(makeSlice(blob));
848 if (!node)
849 return false;
850 node->updateHash();
851 if (node->getHash() != hash)
852 return false;
853
854 auto depth = std::distance(path.rbegin(), rit);
855 if (node->isInner())
856 {
857 auto nodeId = SHAMapNodeID::createID(depth, key);
858 hash = static_cast<SHAMapInnerNode*>(node.get())
859 ->getChildHash(selectBranch(nodeId, key));
860 }
861 else
862 {
863 // should exhaust all the blobs now
864 return depth + 1 == path.size();
865 }
866 }
867 }
868 catch (std::exception const&)
869 {
870 // the data in the path may come from the network,
871 // exception could be thrown when parsing the data
872 return false;
873 }
874 return false;
875}
876
877} // 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:95
SHAMapTreeNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending, descendCallback &&) const
Definition: SHAMap.cpp:396
bool backed_
Definition: SHAMap.h:109
void gmn_ProcessNodes(MissingNodes &, MissingNodes::StackEntry &node)
Definition: SHAMapSync.cpp:173
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:294
boost::intrusive_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:618
Family & f_
Definition: SHAMap.h:97
SHAMapTreeNode * descend(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:317
std::shared_ptr< SHAMapTreeNode > root_
Definition: SHAMap.h:106
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
Definition: SHAMapSync.cpp:746
std::shared_ptr< SHAMapTreeNode > descendNoStore(std::shared_ptr< SHAMapInnerNode > const &, int branch) const
Definition: SHAMap.cpp:351
void visitNodes(std::function< bool(SHAMapTreeNode &)> const &function) const
Visit every node in this SHAMap.
Definition: SHAMapSync.cpp:40
bool hasLeafNode(uint256 const &tag, SHAMapHash const &hash) const
Does this map have this leaf node?
Definition: SHAMapSync.cpp:770
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:101
void visitLeaves(std::function< void(boost::intrusive_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
Definition: SHAMapSync.cpp:28
Blob getData() const
Definition: Serializer.h:208
An immutable linear range of bytes.
Definition: Slice.h:46
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:244
@ 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:524
std::stack< StackEntry, std::deque< StackEntry > > stack_
Definition: SHAMap.h:539
std::condition_variable deferCondVar_
Definition: SHAMap.h:550
std::uint32_t generation_
Definition: SHAMap.h:520
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
Definition: SHAMap.h:523
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
Definition: SHAMap.h:555
SHAMapSyncFilter * filter_
Definition: SHAMap.h:518
std::vector< DeferredNode > finishedReads_
Definition: SHAMap.h:551
T tie(T... args)
T top(T... args)