1#include <xrpl/basics/IntrusivePointer.ipp>
2#include <xrpl/basics/Slice.h>
3#include <xrpl/basics/contract.h>
4#include <xrpl/basics/spinlock.h>
5#include <xrpl/protocol/HashPrefix.h>
6#include <xrpl/protocol/digest.h>
7#include <xrpl/shamap/SHAMapInnerNode.h>
8#include <xrpl/shamap/SHAMapTreeNode.h>
9#include <xrpl/shamap/detail/TaggedPointer.ipp>
27 std::tie(std::ignore, std::ignore, children) =
30 [&](
auto branchNum,
auto indexNum) { children[indexNum].
reset(); });
65 auto p = intr_ptr::make_shared<SHAMapInnerNode>(
cowid, branchCount);
72 std::tie(std::ignore, cloneHashes, cloneChildren) =
73 p->hashesAndChildren_.getHashesAndChildren();
74 std::tie(std::ignore, thisHashes, thisChildren) =
79 int cloneChildIndex = 0;
81 cloneHashes[cloneChildIndex++] = thisHashes[indexNum];
87 cloneHashes[branchNum] = thisHashes[indexNum];
96 int cloneChildIndex = 0;
98 cloneChildren[cloneChildIndex++] = thisChildren[indexNum];
104 cloneChildren[branchNum] = thisChildren[indexNum];
119 Throw<std::runtime_error>(
"Invalid FI node");
121 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
125 auto hashes = ret->hashesAndChildren_.getHashes();
131 if (hashes[i].isNonZero())
132 ret->isBranch_ |= (1 << i);
135 ret->resizeChildArrays(ret->getBranchCount());
152 if (
auto const s = data.size();
154 Throw<std::runtime_error>(
"Invalid CI node");
158 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
160 auto hashes = ret->hashesAndChildren_.getHashes();
165 auto const pos = si.
get8();
168 Throw<std::runtime_error>(
"invalid CI node");
170 hashes[pos].as_uint256() = hash;
172 if (hashes[pos].isNonZero())
173 ret->isBranch_ |= (1 << pos);
176 ret->resizeChildArrays(ret->getBranchCount());
202 std::tie(std::ignore, hashes, children) =
205 if (
auto p = children[indexNum].
get())
206 hashes[indexNum] = p->getHash();
215 !
isEmpty(),
"ripple::SHAMapInnerNode::serializeForWire : is non-empty");
241 "ripple::SHAMapInnerNode::serializeWithPrefix : is non-empty");
268 "ripple::SHAMapInnerNode::setChild : valid branch input");
269 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::setChild : nonzero cowid");
272 "ripple::SHAMapInnerNode::setChild : valid child input");
274 auto const dstIsBranch = [&] {
281 auto const dstToAllocate =
popcnt16(dstIsBranch);
293 hashes[childIndex].zero();
294 children[childIndex] = std::move(child);
301 "ripple::SHAMapInnerNode::setChild : maximum branch count");
312 "ripple::SHAMapInnerNode::shareChild : valid branch input");
313 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::shareChild : nonzero cowid");
315 child,
"ripple::SHAMapInnerNode::shareChild : non-null child input");
318 "ripple::SHAMapInnerNode::shareChild : valid child input");
322 "ripple::SHAMapInnerNode::shareChild : non-empty branch input");
331 "ripple::SHAMapInnerNode::getChildPointer : valid branch input");
334 "ripple::SHAMapInnerNode::getChildPointer : non-empty branch input");
348 "ripple::SHAMapInnerNode::getChild : valid branch input");
351 "ripple::SHAMapInnerNode::getChild : non-empty branch input");
365 "ripple::SHAMapInnerNode::getChildHash : valid branch input");
369 return zeroSHAMapHash;
379 "ripple::SHAMapInnerNode::canonicalizeChild : valid branch input");
382 "ripple::SHAMapInnerNode::canonicalizeChild : valid node input");
385 "ripple::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
389 node->getHash() == hashes[childIndex],
390 "ripple::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
396 if (children[childIndex])
399 node = children[childIndex];
404 children[childIndex] = node;
412 [[maybe_unused]]
unsigned count = 0;
413 auto [numAllocated, hashes, children] =
419 for (
int i = 0; i < branchCount; ++i)
422 hashes[i].isNonZero(),
423 "ripple::SHAMapInnerNode::invariants : nonzero hash in branch");
424 if (children[i] !=
nullptr)
425 children[i]->invariants();
433 if (hashes[i].isNonZero())
437 "ripple::SHAMapInnerNode::invariants : valid branch when "
439 if (children[i] !=
nullptr)
440 children[i]->invariants();
447 "ripple::SHAMapInnerNode::invariants : valid branch when "
457 "ripple::SHAMapInnerNode::invariants : nonzero hash");
459 count >= 1,
"ripple::SHAMapInnerNode::invariants : minimum count");
463 "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.