1#include <xrpl/basics/random.h> 
    2#include <xrpl/shamap/SHAMap.h> 
    3#include <xrpl/shamap/SHAMapLeafNode.h> 
    4#include <xrpl/shamap/SHAMapSyncFilter.h> 
   10    std::function<
void(boost::intrusive_ptr<SHAMapItem const> 
const&
 
   11                           item)> 
const& leafFunction)
 const 
 
   28    if (!
root_->isInner())
 
   34    auto node = intr_ptr::static_pointer_cast<SHAMapInnerNode>(
root_);
 
   41            if (!node->isEmptyBranch(pos))
 
   45                if (!function(*child))
 
   53                    while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
 
   64                        intr_ptr::static_pointer_cast<SHAMapInnerNode>(child);
 
 
   92    if (
root_->getHash().isZero())
 
   95    if (have && (
root_->getHash() == have->
root_->getHash()))
 
  100        auto leaf = intr_ptr::static_pointer_cast<SHAMapLeafNode>(
root_);
 
  102            !have->
hasLeafNode(leaf->peekItem()->key(), leaf->getHash()))
 
  112    while (!stack.
empty())
 
  114        auto const [node, nodeID] = stack.
top();
 
  118        if (!function(*node))
 
  122        for (
int i = 0; i < 16; ++i)
 
  124            if (!node->isEmptyBranch(i))
 
  126                auto const& childHash = node->getChildHash(i);
 
  142                    if (!function(*next))
 
 
  163    while (currentChild < 16)
 
  165        int branch = (firstChild + currentChild++) % 16;
 
  186                [node, nodeID, branch, &mn](
 
  190                    std::unique_lock<std::mutex> lock{mn.deferLock_};
 
  192                        node, nodeID, branch, std::move(found));
 
  234        node->setFullBelowGen(mn.generation_);
 
  237            f_.getFullBelowCache()->insert(node->getHash().as_uint256());
 
 
  271        auto const& nodeHash = parent->getChildHash(branch);
 
  275            nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
 
  284                parentID.getChildNodeID(branch), nodeHash.as_uint256());
 
 
  302        root_->getHash().isNonZero(),
 
  303        "ripple::SHAMap::getMissingNodes : nonzero root hash");
 
  304    XRPL_ASSERT(max > 0, 
"ripple::SHAMap::getMissingNodes : valid max input");
 
  310        f_.getFullBelowCache()->getGeneration());
 
  312    if (!root_->isInner() ||
 
  313        intr_ptr::static_pointer_cast<SHAMapInnerNode>(root_)->isFullBelow(
 
  341            gmn_ProcessNodes(mn, pos);
 
  346            if ((node == 
nullptr) && !mn.
stack_.empty())
 
  349                bool was = fullBelow;  
 
  361                    fullBelow = fullBelow && was;  
 
  365                    "ripple::SHAMap::getMissingNodes : first non-null node");
 
  372            gmn_ProcessDeferredReads(mn);
 
  398                    "ripple::SHAMap::getMissingNodes : second non-null node");
 
  406    } 
while (node != 
nullptr);
 
 
  424    auto node = root_.get();
 
  431        if (inner->isEmptyBranch(branch))
 
  433        node = descendThrow(inner, branch);
 
  437    if (node == 
nullptr || wanted != nodeID)
 
  439        JLOG(journal_.info())
 
  440            << 
"peer requested node that is not in the map: " << wanted
 
  441            << 
" but found " << nodeID;
 
  447        JLOG(journal_.warn()) << 
"peer requests empty node";
 
  452    stack.
emplace(node, nodeID, depth);
 
  456    while (!stack.
empty())
 
  463        node->serializeForWire(s);
 
  473            if ((depth > 0) || (bc == 1))
 
  476                for (
int i = 0; i < 16; ++i)
 
  478                    if (!inner->isEmptyBranch(i))
 
  480                        auto const childNode = descendThrow(inner, i);
 
  483                        if (childNode->isInner() && ((depth > 1) || (bc == 1)))
 
  490                                (bc > 1) ? (depth - 1) : depth);
 
  492                        else if (childNode->isInner() || fatLeaves)
 
  496                            childNode->serializeForWire(s);
 
 
  512    root_->serializeForWire(s);
 
 
  518    Slice const& rootNode,
 
  522    if (root_->getHash().isNonZero())
 
  524        JLOG(journal_.trace()) << 
"got root node, already have one";
 
  526            root_->getHash() == hash,
 
  527            "ripple::SHAMap::addRootNode : valid hash input");
 
  528        return SHAMapAddNode::duplicate();
 
  531    XRPL_ASSERT(cowid_ >= 1, 
"ripple::SHAMap::addRootNode : valid cowid");
 
  532    auto node = SHAMapTreeNode::makeFromWire(rootNode);
 
  533    if (!node || node->getHash() != hash)
 
  534        return SHAMapAddNode::invalid();
 
  537        canonicalize(hash, node);
 
  547        root_->serializeWithPrefix(s);
 
  556    return SHAMapAddNode::useful();
 
 
  562    Slice const& rawNode,
 
  566        !node.
isRoot(), 
"ripple::SHAMap::addKnownNode : valid node input");
 
  570        JLOG(journal_.trace()) << 
"AddKnownNode while not synching";
 
  571        return SHAMapAddNode::duplicate();
 
  574    auto const generation = f_.getFullBelowCache()->getGeneration();
 
  576    auto currNode = root_.get();
 
  578    while (currNode->isInner() &&
 
  583        XRPL_ASSERT(branch >= 0, 
"ripple::SHAMap::addKnownNode : valid branch");
 
  585        if (inner->isEmptyBranch(branch))
 
  587            JLOG(journal_.warn()) << 
"Add known node for empty branch" << node;
 
  588            return SHAMapAddNode::invalid();
 
  591        auto childHash = inner->getChildHash(branch);
 
  592        if (f_.getFullBelowCache()->touch_if_exists(childHash.as_uint256()))
 
  594            return SHAMapAddNode::duplicate();
 
  597        auto prevNode = inner;
 
  599            descend(inner, currNodeID, branch, filter);
 
  601        if (currNode != 
nullptr)
 
  604        auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
 
  606        if (!newNode || childHash != newNode->getHash())
 
  608            JLOG(journal_.warn()) << 
"Corrupt node received";
 
  609            return SHAMapAddNode::invalid();
 
  617        if (newNode->isLeaf())
 
  619            auto const& actualKey =
 
  625            auto const expectedNodeID =
 
  626                SHAMapNodeID::createID(node.
getDepth(), actualKey);
 
  627            if (expectedNodeID.getNodeID() != node.
getNodeID())
 
  629                JLOG(journal_.debug())
 
  630                    << 
"Leaf node position mismatch: " 
  631                    << 
"expected=" << expectedNodeID.getNodeID()
 
  633                return SHAMapAddNode::invalid();
 
  640        if ((currNodeID.
getDepth() > leafDepth) ||
 
  641            (newNode->isInner() && currNodeID.
getDepth() == leafDepth))
 
  644            state_ = SHAMapState::Invalid;
 
  645            return SHAMapAddNode::useful();
 
  648        if (currNodeID != node)
 
  651            JLOG(journal_.warn()) << 
"unable to hook node " << node;
 
  652            JLOG(journal_.info()) << 
" stuck at " << currNodeID;
 
  653            JLOG(journal_.info()) << 
"got depth=" << node.
getDepth()
 
  654                                  << 
", walked to= " << currNodeID.
getDepth();
 
  655            return SHAMapAddNode::useful();
 
  659            canonicalize(childHash, newNode);
 
  661        newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
 
  666            newNode->serializeWithPrefix(s);
 
  675        return SHAMapAddNode::useful();
 
  678    JLOG(journal_.trace()) << 
"got node, already had it (late)";
 
  679    return SHAMapAddNode::duplicate();
 
 
  688    stack.
push({root_.get(), other.
root_.get()});
 
  690    while (!stack.
empty())
 
  692        auto const [node, otherNode] = stack.
top();
 
  695        if (!node || !otherNode)
 
  697            JLOG(journal_.info()) << 
"unable to fetch node";
 
  700        else if (otherNode->getHash() != node->getHash())
 
  702            JLOG(journal_.warn()) << 
"node hash mismatch";
 
  708            if (!otherNode->isLeaf())
 
  711            auto& otherNodePeek =
 
  713            if (nodePeek->key() != otherNodePeek->key())
 
  715            if (nodePeek->slice() != otherNodePeek->slice())
 
  718        else if (node->isInner())
 
  720            if (!otherNode->isInner())
 
  724            for (
int i = 0; i < 16; ++i)
 
  726                if (node_inner->isEmptyBranch(i))
 
  728                    if (!other_inner->isEmptyBranch(i))
 
  733                    if (other_inner->isEmptyBranch(i))
 
  736                    auto next = descend(node_inner, i);
 
  737                    auto otherNext = other.
descend(other_inner, i);
 
  738                    if (!next || !otherNext)
 
  740                        JLOG(journal_.warn()) << 
"unable to fetch inner node";
 
  743                    stack.
push({next, otherNext});
 
 
  759    auto node = root_.get();
 
  766        if (inner->isEmptyBranch(branch))
 
  769        node = descendThrow(inner, branch);
 
  773    return (node->isInner()) && (node->getHash() == targetNodeHash);
 
 
  781    auto node = root_.get();
 
  784    if (!node->isInner())  
 
  785        return node->getHash() == targetNodeHash;
 
  791        if (inner->isEmptyBranch(branch))
 
  794        if (inner->getChildHash(branch) ==
 
  798        node = descendThrow(inner, branch);
 
  800    } 
while (node->isInner());
 
 
  810    walkTowardsKey(key, &stack);
 
  814        JLOG(journal_.debug()) << 
"no path to " << key;
 
  818    if (
auto const& node = stack.
top().
first; !node || node->isInner() ||
 
  819        intr_ptr::static_pointer_cast<SHAMapLeafNode>(node)
 
  823        JLOG(journal_.debug()) << 
"no path to " << key;
 
  828    path.reserve(stack.
size());
 
  829    while (!stack.
empty())
 
  832        stack.
top().
first->serializeForWire(s);
 
  833        path.emplace_back(std::move(s.
modData()));
 
  837    JLOG(journal_.debug()) << 
"getPath for key " << key << 
", path length " 
 
  843SHAMap::verifyProofPath(
 
  848    if (path.empty() || path.size() > 65)
 
  854        for (
auto rit = path.rbegin(); rit != path.rend(); ++rit)
 
  856            auto const& blob = *rit;
 
  857            auto node = SHAMapTreeNode::makeFromWire(
makeSlice(blob));
 
  861            if (node->getHash() != hash)
 
  867                auto nodeId = SHAMapNodeID::createID(depth, key);
 
  874                return depth + 1 == path.size();
 
 
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
 
int getBranchCount() const
 
boost::intrusive_ptr< SHAMapItem const > const & peekItem() const
 
Identifies a node inside a SHAMap.
 
unsigned int getDepth() const
 
uint256 const & getNodeID() const
 
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.
 
SHAMapTreeNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending, descendCallback &&) const
 
void gmn_ProcessNodes(MissingNodes &, MissingNodes::StackEntry &node)
 
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
 
intr_ptr::SharedPtr< SHAMapTreeNode > root_
 
boost::intrusive_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
 
SHAMapTreeNode * descend(SHAMapInnerNode *, int branch) const
 
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
 
void visitNodes(std::function< bool(SHAMapTreeNode &)> const &function) const
Visit every node in this SHAMap.
 
bool hasLeafNode(uint256 const &tag, SHAMapHash const &hash) const
Does this map have this leaf node?
 
intr_ptr::SharedPtr< SHAMapTreeNode > descendNoStore(SHAMapInnerNode &, int branch) const
 
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.
 
void visitLeaves(std::function< void(boost::intrusive_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
 
A shared intrusive pointer class that supports weak pointers.
 
An immutable linear range of bytes.
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
 
@ 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)
 
unsigned int selectBranch(SHAMapNodeID const &id, uint256 const &hash)
Returns the branch that would contain the given hash.
 
@ innerNode
inner node in V1 tree
 
std::set< SHAMapHash > missingHashes_
 
std::stack< StackEntry, std::deque< StackEntry > > stack_
 
std::condition_variable deferCondVar_
 
std::uint32_t generation_
 
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
 
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
 
SHAMapSyncFilter * filter_
 
std::vector< DeferredNode > finishedReads_