20#include <xrpl/basics/IntrusivePointer.ipp>
21#include <xrpl/basics/Slice.h>
22#include <xrpl/basics/contract.h>
23#include <xrpl/basics/spinlock.h>
24#include <xrpl/protocol/HashPrefix.h>
25#include <xrpl/protocol/digest.h>
26#include <xrpl/shamap/SHAMapInnerNode.h>
27#include <xrpl/shamap/SHAMapTreeNode.h>
28#include <xrpl/shamap/detail/TaggedPointer.ipp>
46 std::tie(std::ignore, std::ignore, children) =
49 [&](
auto branchNum,
auto indexNum) { children[indexNum].
reset(); });
84 auto p = intr_ptr::make_shared<SHAMapInnerNode>(
cowid, branchCount);
91 std::tie(std::ignore, cloneHashes, cloneChildren) =
92 p->hashesAndChildren_.getHashesAndChildren();
93 std::tie(std::ignore, thisHashes, thisChildren) =
98 int cloneChildIndex = 0;
100 cloneHashes[cloneChildIndex++] = thisHashes[indexNum];
106 cloneHashes[branchNum] = thisHashes[indexNum];
115 int cloneChildIndex = 0;
117 cloneChildren[cloneChildIndex++] = thisChildren[indexNum];
123 cloneChildren[branchNum] = thisChildren[indexNum];
138 Throw<std::runtime_error>(
"Invalid FI node");
140 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
144 auto hashes = ret->hashesAndChildren_.getHashes();
150 if (hashes[i].isNonZero())
151 ret->isBranch_ |= (1 << i);
154 ret->resizeChildArrays(ret->getBranchCount());
171 if (
auto const s = data.size();
173 Throw<std::runtime_error>(
"Invalid CI node");
177 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
179 auto hashes = ret->hashesAndChildren_.getHashes();
184 auto const pos = si.
get8();
187 Throw<std::runtime_error>(
"invalid CI node");
189 hashes[pos].as_uint256() = hash;
191 if (hashes[pos].isNonZero())
192 ret->isBranch_ |= (1 << pos);
195 ret->resizeChildArrays(ret->getBranchCount());
221 std::tie(std::ignore, hashes, children) =
224 if (
auto p = children[indexNum].
get())
225 hashes[indexNum] = p->getHash();
234 !
isEmpty(),
"ripple::SHAMapInnerNode::serializeForWire : is non-empty");
260 "ripple::SHAMapInnerNode::serializeWithPrefix : is non-empty");
287 "ripple::SHAMapInnerNode::setChild : valid branch input");
288 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::setChild : nonzero cowid");
291 "ripple::SHAMapInnerNode::setChild : valid child input");
293 auto const dstIsBranch = [&] {
300 auto const dstToAllocate =
popcnt16(dstIsBranch);
312 hashes[childIndex].zero();
313 children[childIndex] = std::move(child);
320 "ripple::SHAMapInnerNode::setChild : maximum branch count");
331 "ripple::SHAMapInnerNode::shareChild : valid branch input");
332 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::shareChild : nonzero cowid");
334 child,
"ripple::SHAMapInnerNode::shareChild : non-null child input");
337 "ripple::SHAMapInnerNode::shareChild : valid child input");
341 "ripple::SHAMapInnerNode::shareChild : non-empty branch input");
350 "ripple::SHAMapInnerNode::getChildPointer : valid branch input");
353 "ripple::SHAMapInnerNode::getChildPointer : non-empty branch input");
367 "ripple::SHAMapInnerNode::getChild : valid branch input");
370 "ripple::SHAMapInnerNode::getChild : non-empty branch input");
384 "ripple::SHAMapInnerNode::getChildHash : valid branch input");
388 return zeroSHAMapHash;
398 "ripple::SHAMapInnerNode::canonicalizeChild : valid branch input");
401 "ripple::SHAMapInnerNode::canonicalizeChild : valid node input");
404 "ripple::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
408 node->getHash() == hashes[childIndex],
409 "ripple::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
415 if (children[childIndex])
418 node = children[childIndex];
423 children[childIndex] = node;
431 [[maybe_unused]]
unsigned count = 0;
432 auto [numAllocated, hashes, children] =
438 for (
int i = 0; i < branchCount; ++i)
441 hashes[i].isNonZero(),
442 "ripple::SHAMapInnerNode::invariants : nonzero hash in branch");
443 if (children[i] !=
nullptr)
444 children[i]->invariants();
452 if (hashes[i].isNonZero())
456 "ripple::SHAMapInnerNode::invariants : valid branch when "
458 if (children[i] !=
nullptr)
459 children[i]->invariants();
466 "ripple::SHAMapInnerNode::invariants : valid branch when "
476 "ripple::SHAMapInnerNode::invariants : nonzero hash");
478 count >= 1,
"ripple::SHAMapInnerNode::invariants : minimum count");
482 "ripple::SHAMapInnerNode::invariants : hash and count do match");
uint256 const & as_uint256() const
std::uint32_t fullBelowGen_
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)
void setChild(int m, intr_ptr::SharedPtr< SHAMapTreeNode > child)
static intr_ptr::SharedPtr< SHAMapTreeNode > makeCompressedInner(Slice data)
intr_ptr::SharedPtr< 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)
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.
intr_ptr::SharedPtr< SHAMapTreeNode > getChild(int branch)
void partialDestructor() override
void shareChild(int m, intr_ptr::SharedPtr< SHAMapTreeNode > const &child)
SHAMapHash const & getChildHash(int m) const
void invariants(bool is_root=false) const override
std::string getString(SHAMapNodeID const &) const override
intr_ptr::SharedPtr< SHAMapTreeNode > canonicalizeChild(int branch, intr_ptr::SharedPtr< SHAMapTreeNode > node)
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.
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.
static intr_ptr::SharedPtr< SHAMapTreeNode > makeFullInner(Slice data, SHAMapHash const &hash, bool hashValid)
Identifies a node inside a SHAMap.
virtual std::string getString(SHAMapNodeID const &) const
std::uint32_t cowid_
Determines the owning SHAMap, if any.
base_uint< Bits, Tag > getBitString()
std::size_t empty() const noexcept
int addBitString(base_uint< Bits, Tag > const &v)
int add8(unsigned char i)
A shared intrusive pointer class that supports weak pointers.
void reset()
Set the pointer to null, decrement the strong count, and run the appropriate release action.
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).
std::tuple< std::uint8_t, SHAMapHash *, intr_ptr::SharedPtr< SHAMapTreeNode > * > getHashesAndChildren() const
Get the number of elements in each array and a pointer to the start of each array.
SHAMapHash * getHashes() const
Get the hashes 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.
bool isDense() const
Check if the arrays have a dense format.
intr_ptr::SharedPtr< SHAMapTreeNode > * getChildren() const
Get the children array.
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)
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
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.