20#include <xrpld/shamap/SHAMapInnerNode.h>
22#include <xrpld/shamap/SHAMapTreeNode.h>
23#include <xrpld/shamap/detail/TaggedPointer.ipp>
24#include <xrpl/basics/Log.h>
25#include <xrpl/basics/Slice.h>
26#include <xrpl/basics/contract.h>
27#include <xrpl/basics/spinlock.h>
28#include <xrpl/beast/core/LexicalCast.h>
29#include <xrpl/protocol/HashPrefix.h>
30#include <xrpl/protocol/digest.h>
79 auto p = std::make_shared<SHAMapInnerNode>(
cowid, branchCount);
86 std::tie(std::ignore, cloneHashes, cloneChildren) =
87 p->hashesAndChildren_.getHashesAndChildren();
88 std::tie(std::ignore, thisHashes, thisChildren) =
93 int cloneChildIndex = 0;
95 cloneHashes[cloneChildIndex++] = thisHashes[indexNum];
101 cloneHashes[branchNum] = thisHashes[indexNum];
110 int cloneChildIndex = 0;
112 cloneChildren[cloneChildIndex++] = thisChildren[indexNum];
118 cloneChildren[branchNum] = thisChildren[indexNum];
133 Throw<std::runtime_error>(
"Invalid FI node");
135 auto ret = std::make_shared<SHAMapInnerNode>(0,
branchFactor);
139 auto hashes = ret->hashesAndChildren_.getHashes();
145 if (hashes[i].isNonZero())
146 ret->isBranch_ |= (1 << i);
149 ret->resizeChildArrays(ret->getBranchCount());
166 if (
auto const s = data.size();
168 Throw<std::runtime_error>(
"Invalid CI node");
172 auto ret = std::make_shared<SHAMapInnerNode>(0,
branchFactor);
174 auto hashes = ret->hashesAndChildren_.getHashes();
179 auto const pos = si.
get8();
182 Throw<std::runtime_error>(
"invalid CI node");
184 hashes[pos].as_uint256() = hash;
186 if (hashes[pos].isNonZero())
187 ret->isBranch_ |= (1 << pos);
190 ret->resizeChildArrays(ret->getBranchCount());
216 std::tie(std::ignore, hashes, children) =
219 if (children[indexNum] !=
nullptr)
220 hashes[indexNum] = children[indexNum]->
getHash();
229 !
isEmpty(),
"ripple::SHAMapInnerNode::serializeForWire : is non-empty");
255 "ripple::SHAMapInnerNode::serializeWithPrefix : is non-empty");
282 "ripple::SHAMapInnerNode::setChild : valid branch input");
283 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::setChild : nonzero cowid");
286 "ripple::SHAMapInnerNode::setChild : valid child input");
288 auto const dstIsBranch = [&] {
295 auto const dstToAllocate =
popcnt16(dstIsBranch);
307 hashes[childIndex].zero();
308 children[childIndex] = std::move(child);
315 "ripple::SHAMapInnerNode::setChild : maximum branch count");
324 "ripple::SHAMapInnerNode::shareChild : valid branch input");
325 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::shareChild : nonzero cowid");
327 child,
"ripple::SHAMapInnerNode::shareChild : non-null child input");
330 "ripple::SHAMapInnerNode::shareChild : valid child input");
334 "ripple::SHAMapInnerNode::shareChild : non-empty branch input");
343 "ripple::SHAMapInnerNode::getChildPointer : valid branch input");
346 "ripple::SHAMapInnerNode::getChildPointer : non-empty branch input");
360 "ripple::SHAMapInnerNode::getChild : valid branch input");
363 "ripple::SHAMapInnerNode::getChild : non-empty branch input");
377 "ripple::SHAMapInnerNode::getChildHash : valid branch input");
381 return zeroSHAMapHash;
391 "ripple::SHAMapInnerNode::canonicalizeChild : valid branch input");
394 "ripple::SHAMapInnerNode::canonicalizeChild : valid node input");
397 "ripple::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
401 node->getHash() == hashes[childIndex],
402 "ripple::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
408 if (children[childIndex])
411 node = children[childIndex];
416 children[childIndex] = node;
424 [[maybe_unused]]
unsigned count = 0;
425 auto [numAllocated, hashes, children] =
431 for (
int i = 0; i < branchCount; ++i)
434 hashes[i].isNonZero(),
435 "ripple::SHAMapInnerNode::invariants : nonzero hash in branch");
436 if (children[i] !=
nullptr)
437 children[i]->invariants();
445 if (hashes[i].isNonZero())
449 "ripple::SHAMapInnerNode::invariants : valid branch when "
451 if (children[i] !=
nullptr)
452 children[i]->invariants();
459 "ripple::SHAMapInnerNode::invariants : valid branch when "
469 "ripple::SHAMapInnerNode::invariants : nonzero hash");
471 count >= 1,
"ripple::SHAMapInnerNode::invariants : minimum count");
475 "ripple::SHAMapInnerNode::invariants : hash and count do match");
uint256 const & as_uint256() const
std::uint32_t fullBelowGen_
void shareChild(int m, std::shared_ptr< SHAMapTreeNode > const &child)
std::optional< int > getChildIndex(int i) const
Get the child's index inside the hashes or children array (stored in hashesAndChildren_.
SHAMapInnerNode(std::uint32_t cowid, std::uint8_t numAllocatedChildren=2)
std::shared_ptr< SHAMapTreeNode > clone(std::uint32_t cowid) const override
Make a copy of this node, setting the owner.
static constexpr unsigned int branchFactor
Each inner node has 16 children (the 'radix tree' part of the map)
std::shared_ptr< SHAMapTreeNode > getChild(int branch)
bool isEmptyBranch(int m) const
void iterNonEmptyChildIndexes(F &&f) const
Call the f callback for all non-empty branches.
void serializeWithPrefix(Serializer &) const override
Serialize the node in a format appropriate for hashing.
void iterChildren(F &&f) const
Call the f callback for all 16 (branchFactor) branches - even if the branch is empty.
void resizeChildArrays(std::uint8_t toAllocate)
Convert arrays stored in hashesAndChildren_ so they can store the requested number of children.
void updateHash() override
Recalculate the hash of this node.
static std::shared_ptr< SHAMapTreeNode > makeCompressedInner(Slice data)
void setChild(int m, std::shared_ptr< SHAMapTreeNode > child)
SHAMapHash const & getChildHash(int m) const
void invariants(bool is_root=false) const override
std::string getString(SHAMapNodeID const &) const override
TaggedPointer hashesAndChildren_
Opaque type that contains the hashes array (array of type SHAMapHash) and the children array (array o...
void serializeForWire(Serializer &) const override
Serialize the node in a format appropriate for sending over the wire.
std::shared_ptr< SHAMapTreeNode > canonicalizeChild(int branch, std::shared_ptr< SHAMapTreeNode > node)
static std::shared_ptr< SHAMapTreeNode > makeFullInner(Slice data, SHAMapHash const &hash, bool hashValid)
void updateHashDeep()
Recalculate the hash of all children and this node.
int getBranchCount() const
SHAMapTreeNode * getChildPointer(int branch)
std::atomic< std::uint16_t > lock_
A bitlock for the children of this node, with one bit per child.
Identifies a node inside a SHAMap.
virtual std::string getString(SHAMapNodeID const &) const
std::uint32_t cowid_
Determines the owning SHAMap, if any.
SHAMapHash const & getHash() const
Return the hash of this node.
base_uint< Bits, Tag > getBitString()
std::size_t empty() const noexcept
int addBitString(base_uint< Bits, Tag > const &v)
int add8(unsigned char i)
An immutable linear range of bytes.
TaggedPointer is a combination of a pointer and a mask stored in the lowest two bits.
void iterNonEmptyChildIndexes(std::uint16_t isBranch, F &&f) const
Call the f callback for all non-empty branches.
std::optional< int > getChildIndex(std::uint16_t isBranch, int i) const
Get the child's index inside the hashes or children array (which may or may not be sparse).
SHAMapHash * getHashes() const
Get the hashes array.
std::shared_ptr< SHAMapTreeNode > * getChildren() const
Get the children array.
std::uint8_t capacity() const
Get the number of elements allocated for each array.
void iterChildren(std::uint16_t isBranch, F &&f) const
Call the f callback for all 16 (branchFactor) branches - even if the branch is empty.
std::tuple< std::uint8_t, SHAMapHash *, std::shared_ptr< SHAMapTreeNode > * > getHashesAndChildren() const
Get the number of elements in each array and a pointer to the start of each array.
bool isDense() const
Check if the arrays have a dense format.
static std::size_t constexpr bytes
Classes to handle arrays of spinlocks packed into a single atomic integer:
A spinlock implemented on top of an atomic integer.
std::uint32_t cowid() const
Returns the SHAMap that owns this node.
std::enable_if_t< is_contiguously_hashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
void hash_append(Hasher &h, Slice const &v)
static constexpr unsigned char const wireTypeCompressedInner
std::string to_string(base_uint< Bits, Tag > const &a)
static constexpr unsigned char const wireTypeInner
@ innerNode
inner node in V1 tree
int popcnt16(std::uint16_t a)
Returns the SHA512-Half digest of a message.