20#include <xrpld/shamap/SHAMapInnerNode.h>
21#include <xrpld/shamap/SHAMapTreeNode.h>
22#include <xrpld/shamap/detail/TaggedPointer.ipp>
24#include <xrpl/basics/IntrusivePointer.ipp>
25#include <xrpl/basics/Slice.h>
26#include <xrpl/basics/contract.h>
27#include <xrpl/basics/spinlock.h>
28#include <xrpl/protocol/HashPrefix.h>
29#include <xrpl/protocol/digest.h>
47 std::tie(std::ignore, std::ignore, children) =
50 [&](
auto branchNum,
auto indexNum) { children[indexNum].
reset(); });
85 auto p = intr_ptr::make_shared<SHAMapInnerNode>(
cowid, branchCount);
92 std::tie(std::ignore, cloneHashes, cloneChildren) =
93 p->hashesAndChildren_.getHashesAndChildren();
94 std::tie(std::ignore, thisHashes, thisChildren) =
99 int cloneChildIndex = 0;
101 cloneHashes[cloneChildIndex++] = thisHashes[indexNum];
107 cloneHashes[branchNum] = thisHashes[indexNum];
116 int cloneChildIndex = 0;
118 cloneChildren[cloneChildIndex++] = thisChildren[indexNum];
124 cloneChildren[branchNum] = thisChildren[indexNum];
139 Throw<std::runtime_error>(
"Invalid FI node");
141 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
145 auto hashes = ret->hashesAndChildren_.getHashes();
151 if (hashes[i].isNonZero())
152 ret->isBranch_ |= (1 << i);
155 ret->resizeChildArrays(ret->getBranchCount());
172 if (
auto const s = data.size();
174 Throw<std::runtime_error>(
"Invalid CI node");
178 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
180 auto hashes = ret->hashesAndChildren_.getHashes();
185 auto const pos = si.
get8();
188 Throw<std::runtime_error>(
"invalid CI node");
190 hashes[pos].as_uint256() = hash;
192 if (hashes[pos].isNonZero())
193 ret->isBranch_ |= (1 << pos);
196 ret->resizeChildArrays(ret->getBranchCount());
222 std::tie(std::ignore, hashes, children) =
225 if (
auto p = children[indexNum].
get())
226 hashes[indexNum] = p->getHash();
235 !
isEmpty(),
"ripple::SHAMapInnerNode::serializeForWire : is non-empty");
261 "ripple::SHAMapInnerNode::serializeWithPrefix : is non-empty");
288 "ripple::SHAMapInnerNode::setChild : valid branch input");
289 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::setChild : nonzero cowid");
292 "ripple::SHAMapInnerNode::setChild : valid child input");
294 auto const dstIsBranch = [&] {
301 auto const dstToAllocate =
popcnt16(dstIsBranch);
313 hashes[childIndex].zero();
314 children[childIndex] = std::move(child);
321 "ripple::SHAMapInnerNode::setChild : maximum branch count");
332 "ripple::SHAMapInnerNode::shareChild : valid branch input");
333 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::shareChild : nonzero cowid");
335 child,
"ripple::SHAMapInnerNode::shareChild : non-null child input");
338 "ripple::SHAMapInnerNode::shareChild : valid child input");
342 "ripple::SHAMapInnerNode::shareChild : non-empty branch input");
351 "ripple::SHAMapInnerNode::getChildPointer : valid branch input");
354 "ripple::SHAMapInnerNode::getChildPointer : non-empty branch input");
368 "ripple::SHAMapInnerNode::getChild : valid branch input");
371 "ripple::SHAMapInnerNode::getChild : non-empty branch input");
385 "ripple::SHAMapInnerNode::getChildHash : valid branch input");
389 return zeroSHAMapHash;
399 "ripple::SHAMapInnerNode::canonicalizeChild : valid branch input");
402 "ripple::SHAMapInnerNode::canonicalizeChild : valid node input");
405 "ripple::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
409 node->getHash() == hashes[childIndex],
410 "ripple::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
416 if (children[childIndex])
419 node = children[childIndex];
424 children[childIndex] = node;
432 [[maybe_unused]]
unsigned count = 0;
433 auto [numAllocated, hashes, children] =
439 for (
int i = 0; i < branchCount; ++i)
442 hashes[i].isNonZero(),
443 "ripple::SHAMapInnerNode::invariants : nonzero hash in branch");
444 if (children[i] !=
nullptr)
445 children[i]->invariants();
453 if (hashes[i].isNonZero())
457 "ripple::SHAMapInnerNode::invariants : valid branch when "
459 if (children[i] !=
nullptr)
460 children[i]->invariants();
467 "ripple::SHAMapInnerNode::invariants : valid branch when "
477 "ripple::SHAMapInnerNode::invariants : nonzero hash");
479 count >= 1,
"ripple::SHAMapInnerNode::invariants : minimum count");
483 "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.