20 #include <ripple/basics/random.h>
21 #include <ripple/shamap/SHAMap.h>
22 #include <ripple/shamap/SHAMapSyncFilter.h>
28 std::function<
void(boost::intrusive_ptr<SHAMapItem const>
const&
29 item)>
const& leafFunction)
const
46 if (!
root_->isInner())
52 auto node = std::static_pointer_cast<SHAMapInnerNode>(
root_);
59 if (!node->isEmptyBranch(pos))
63 if (!
function(*child))
71 while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
81 node = std::static_pointer_cast<SHAMapInnerNode>(child);
109 if (
root_->getHash().isZero())
112 if (have && (
root_->getHash() == have->
root_->getHash()))
117 auto leaf = std::static_pointer_cast<SHAMapLeafNode>(
root_);
119 !have->
hasLeafNode(leaf->peekItem()->key(), leaf->getHash()))
129 while (!stack.
empty())
131 auto const [node, nodeID] = stack.
top();
135 if (!
function(*node))
139 for (
int i = 0; i < 16; ++i)
141 if (!node->isEmptyBranch(i))
143 auto const& childHash = node->getChildHash(i);
159 if (!
function(*next))
176 int& firstChild = std::get<2>(se);
177 int& currentChild = std::get<3>(se);
178 bool& fullBelow = std::get<4>(se);
180 while (currentChild < 16)
182 int branch = (firstChild + currentChild++) % 16;
196 ->touch_if_exists(childHash.as_uint256()))
204 [node, nodeID, branch, &mn](
207 std::unique_lock<std::mutex> lock{mn.deferLock_};
209 node, nodeID, branch, std::move(found));
251 node->setFullBelowGen(mn.generation_);
254 f_.getFullBelowCache(ledgerSeq_)
255 ->insert(node->getHash().as_uint256());
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);
293 nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
302 parentID.getChildNodeID(branch), nodeHash.as_uint256());
319 assert(root_->getHash().isNonZero());
326 f_.getFullBelowCache(ledgerSeq_)->getGeneration());
328 if (!root_->isInner() ||
329 std::static_pointer_cast<SHAMapInnerNode>(root_)->isFullBelow(
348 auto& node = std::get<0>(pos);
349 auto& nextChild = std::get<3>(pos);
350 auto& fullBelow = std::get<4>(pos);
357 gmn_ProcessNodes(mn, pos);
362 if ((node ==
nullptr) && !mn.
stack_.empty())
365 bool was = fullBelow;
377 fullBelow = fullBelow && was;
386 gmn_ProcessDeferredReads(mn);
410 assert(node !=
nullptr);
418 }
while (node !=
nullptr);
436 auto node = root_.get();
443 if (inner->isEmptyBranch(branch))
445 node = descendThrow(inner, branch);
449 if (node ==
nullptr || wanted != nodeID)
451 JLOG(journal_.info())
452 <<
"peer requested node that is not in the map: " << wanted
453 <<
" but found " << nodeID;
459 JLOG(journal_.warn()) <<
"peer requests empty node";
464 stack.
emplace(node, nodeID, depth);
468 while (!stack.
empty())
475 node->serializeForWire(s);
485 if ((depth > 0) || (bc == 1))
488 for (
int i = 0; i < 16; ++i)
490 if (!inner->isEmptyBranch(i))
492 auto const childNode = descendThrow(inner, i);
495 if (childNode->isInner() && ((depth > 1) || (bc == 1)))
502 (bc > 1) ? (depth - 1) : depth);
504 else if (childNode->isInner() || fatLeaves)
508 childNode->serializeForWire(s);
524 root_->serializeForWire(s);
530 Slice const& rootNode,
534 if (root_->getHash().isNonZero())
536 JLOG(journal_.trace()) <<
"got root node, already have one";
537 assert(root_->getHash() == hash);
538 return SHAMapAddNode::duplicate();
542 auto node = SHAMapTreeNode::makeFromWire(rootNode);
543 if (!node || node->getHash() != hash)
544 return SHAMapAddNode::invalid();
547 canonicalize(hash, node);
557 root_->serializeWithPrefix(s);
566 return SHAMapAddNode::useful();
570 SHAMap::addKnownNode(
572 Slice const& rawNode,
579 JLOG(journal_.trace()) <<
"AddKnownNode while not synching";
580 return SHAMapAddNode::duplicate();
583 auto const generation = f_.getFullBelowCache(ledgerSeq_)->getGeneration();
585 auto iNode = root_.get();
587 while (iNode->isInner() &&
594 if (inner->isEmptyBranch(branch))
596 JLOG(journal_.warn()) <<
"Add known node for empty branch" << node;
597 return SHAMapAddNode::invalid();
600 auto childHash = inner->getChildHash(branch);
601 if (f_.getFullBelowCache(ledgerSeq_)
602 ->touch_if_exists(childHash.as_uint256()))
604 return SHAMapAddNode::duplicate();
607 auto prevNode = inner;
608 std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
610 if (iNode ==
nullptr)
612 auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
614 if (!newNode || childHash != newNode->getHash())
616 JLOG(journal_.warn()) <<
"Corrupt node received";
617 return SHAMapAddNode::invalid();
623 if ((iNodeID.
getDepth() > leafDepth) ||
624 (newNode->isInner() && iNodeID.
getDepth() == leafDepth))
627 state_ = SHAMapState::Invalid;
628 return SHAMapAddNode::useful();
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();
642 canonicalize(childHash, newNode);
644 newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
649 newNode->serializeWithPrefix(s);
658 return SHAMapAddNode::useful();
662 JLOG(journal_.trace()) <<
"got node, already had it (late)";
663 return SHAMapAddNode::duplicate();
672 stack.
push({root_.get(), other.
root_.get()});
674 while (!stack.
empty())
676 auto const [node, otherNode] = stack.
top();
679 if (!node || !otherNode)
681 JLOG(journal_.info()) <<
"unable to fetch node";
684 else if (otherNode->getHash() != node->getHash())
686 JLOG(journal_.warn()) <<
"node hash mismatch";
692 if (!otherNode->isLeaf())
695 auto& otherNodePeek =
697 if (nodePeek->key() != otherNodePeek->key())
699 if (nodePeek->slice() != otherNodePeek->slice())
702 else if (node->isInner())
704 if (!otherNode->isInner())
708 for (
int i = 0; i < 16; ++i)
710 if (node_inner->isEmptyBranch(i))
712 if (!other_inner->isEmptyBranch(i))
717 if (other_inner->isEmptyBranch(i))
720 auto next = descend(node_inner, i);
721 auto otherNext = other.
descend(other_inner, i);
722 if (!next || !otherNext)
724 JLOG(journal_.warn()) <<
"unable to fetch inner node";
727 stack.
push({next, otherNext});
739 SHAMap::hasInnerNode(
743 auto node = root_.get();
750 if (inner->isEmptyBranch(branch))
753 node = descendThrow(inner, branch);
757 return (node->isInner()) && (node->getHash() == targetNodeHash);
765 auto node = root_.get();
768 if (!node->isInner())
769 return node->getHash() == targetNodeHash;
775 if (inner->isEmptyBranch(branch))
778 if (inner->getChildHash(branch) ==
782 node = descendThrow(inner, branch);
784 }
while (node->isInner());
791 SHAMap::getProofPath(
uint256 const& key)
const
794 walkTowardsKey(key, &stack);
798 JLOG(journal_.debug()) <<
"no path to " << key;
802 if (
auto const& node = stack.
top().
first; !node || node->isInner() ||
803 std::static_pointer_cast<SHAMapLeafNode>(node)->peekItem()->key() !=
806 JLOG(journal_.debug()) <<
"no path to " << key;
811 path.reserve(stack.
size());
812 while (!stack.
empty())
815 stack.
top().
first->serializeForWire(s);
816 path.emplace_back(std::move(s.
modData()));
820 JLOG(journal_.debug()) <<
"getPath for key " << key <<
", path length "
826 SHAMap::verifyProofPath(
831 if (path.empty() || path.size() > 65)
837 for (
auto rit = path.rbegin(); rit != path.rend(); ++rit)
839 auto const& blob = *rit;
840 auto node = SHAMapTreeNode::makeFromWire(
makeSlice(blob));
844 if (node->getHash() != hash)
850 auto nodeId = SHAMapNodeID::createID(depth, key);
857 return depth + 1 == path.size();