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>
60 auto p = intr_ptr::make_shared<SHAMapInnerNode>(
cowid, branchCount);
67 std::tie(std::ignore, cloneHashes, cloneChildren) =
68 p->hashesAndChildren_.getHashesAndChildren();
73 int cloneChildIndex = 0;
75 cloneHashes[cloneChildIndex++] = thisHashes[indexNum];
81 [&](
auto branchNum,
auto indexNum) { cloneHashes[branchNum] = thisHashes[indexNum]; });
89 int cloneChildIndex = 0;
91 cloneChildren[cloneChildIndex++] = thisChildren[indexNum];
97 cloneChildren[branchNum] = thisChildren[indexNum];
109 Throw<std::runtime_error>(
"Invalid FI node");
111 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
115 auto hashes = ret->hashesAndChildren_.getHashes();
121 if (hashes[i].isNonZero())
122 ret->isBranch_ |= (1 << i);
125 ret->resizeChildArrays(ret->getBranchCount());
142 if (
auto const s = data.size(); (s % chunkSize != 0) || (s > chunkSize *
branchFactor))
143 Throw<std::runtime_error>(
"Invalid CI node");
147 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
149 auto hashes = ret->hashesAndChildren_.getHashes();
154 auto const pos = si.
get8();
157 Throw<std::runtime_error>(
"invalid CI node");
159 hashes[pos].as_uint256() = hash;
161 if (hashes[pos].isNonZero())
162 ret->isBranch_ |= (1 << pos);
165 ret->resizeChildArrays(ret->getBranchCount());
193 if (
auto p = children[indexNum].
get())
194 hashes[indexNum] = p->getHash();
202 XRPL_ASSERT(!
isEmpty(),
"xrpl::SHAMapInnerNode::serializeForWire : is non-empty");
225 XRPL_ASSERT(!
isEmpty(),
"xrpl::SHAMapInnerNode::serializeWithPrefix : is non-empty");
250 (m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::setChild : valid branch input");
251 XRPL_ASSERT(
cowid_,
"xrpl::SHAMapInnerNode::setChild : nonzero cowid");
252 XRPL_ASSERT(child.get() !=
this,
"xrpl::SHAMapInnerNode::setChild : valid child input");
254 auto const dstIsBranch = [&] {
261 auto const dstToAllocate =
popcnt16(dstIsBranch);
273 hashes[childIndex].zero();
274 children[childIndex] = std::move(child);
281 "xrpl::SHAMapInnerNode::setChild : maximum branch count");
289 (m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::shareChild : valid branch input");
290 XRPL_ASSERT(
cowid_,
"xrpl::SHAMapInnerNode::shareChild : nonzero cowid");
291 XRPL_ASSERT(child,
"xrpl::SHAMapInnerNode::shareChild : non-null child input");
292 XRPL_ASSERT(child.get() !=
this,
"xrpl::SHAMapInnerNode::shareChild : valid child input");
294 XRPL_ASSERT(!
isEmptyBranch(m),
"xrpl::SHAMapInnerNode::shareChild : non-empty branch input");
303 "xrpl::SHAMapInnerNode::getChildPointer : valid branch input");
305 !
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::getChildPointer : non-empty branch input");
319 "xrpl::SHAMapInnerNode::getChild : valid branch input");
320 XRPL_ASSERT(!
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::getChild : non-empty branch input");
333 (m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::getChildHash : valid branch input");
337 return zeroSHAMapHash;
345 "xrpl::SHAMapInnerNode::canonicalizeChild : valid branch input");
346 XRPL_ASSERT(node !=
nullptr,
"xrpl::SHAMapInnerNode::canonicalizeChild : valid node input");
349 "xrpl::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
353 node->getHash() == hashes[childIndex],
354 "xrpl::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
360 if (children[childIndex])
363 node = children[childIndex];
368 children[childIndex] = node;
376 [[maybe_unused]]
unsigned count = 0;
382 for (
int i = 0; i < branchCount; ++i)
385 hashes[i].isNonZero(),
386 "xrpl::SHAMapInnerNode::invariants : nonzero hash in branch");
387 if (children[i] !=
nullptr)
388 children[i]->invariants();
396 if (hashes[i].isNonZero())
400 "xrpl::SHAMapInnerNode::invariants : valid branch when "
402 if (children[i] !=
nullptr)
403 children[i]->invariants();
410 "xrpl::SHAMapInnerNode::invariants : valid branch when "
418 XRPL_ASSERT(
hash_.
isNonZero(),
"xrpl::SHAMapInnerNode::invariants : nonzero hash");
419 XRPL_ASSERT(count >= 1,
"xrpl::SHAMapInnerNode::invariants : minimum count");
423 "xrpl::SHAMapInnerNode::invariants : hash and count do match");
uint256 const & as_uint256() const
void serializeWithPrefix(Serializer &) const override
Serialize the node in a format appropriate for hashing.
void updateHash() override
Recalculate the hash of this node.
static intr_ptr::SharedPtr< SHAMapTreeNode > makeFullInner(Slice data, SHAMapHash const &hash, bool hashValid)
TaggedPointer hashesAndChildren_
Opaque type that contains the hashes array (array of type SHAMapHash) and the children array (array o...
static intr_ptr::SharedPtr< SHAMapTreeNode > makeCompressedInner(Slice data)
SHAMapHash const & getChildHash(int m) const
void updateHashDeep()
Recalculate the hash of all children and this node.
void iterNonEmptyChildIndexes(F &&f) const
Call the f callback for all non-empty branches.
SHAMapTreeNode * getChildPointer(int branch)
int getBranchCount() const
std::string getString(SHAMapNodeID const &) const override
SHAMapInnerNode(std::uint32_t cowid, std::uint8_t numAllocatedChildren=2)
void iterChildren(F &&f) const
Call the f callback for all 16 (branchFactor) branches - even if the branch is empty.
static constexpr unsigned int branchFactor
Each inner node has 16 children (the 'radix tree' part of the map)
void resizeChildArrays(std::uint8_t toAllocate)
Convert arrays stored in hashesAndChildren_ so they can store the requested number of children.
std::uint32_t fullBelowGen_
void partialDestructor() override
std::atomic< std::uint16_t > lock_
A bitlock for the children of this node, with one bit per child.
intr_ptr::SharedPtr< SHAMapTreeNode > canonicalizeChild(int branch, intr_ptr::SharedPtr< SHAMapTreeNode > node)
void shareChild(int m, intr_ptr::SharedPtr< SHAMapTreeNode > const &child)
intr_ptr::SharedPtr< SHAMapTreeNode > clone(std::uint32_t cowid) const override
Make a copy of this node, setting the owner.
intr_ptr::SharedPtr< SHAMapTreeNode > getChild(int branch)
void setChild(int m, intr_ptr::SharedPtr< SHAMapTreeNode > child)
void serializeForWire(Serializer &) const override
Serialize the node in a format appropriate for sending over the wire.
std::optional< int > getChildIndex(int i) const
Get the child's index inside the hashes or children array (stored in hashesAndChildren_.
void invariants(bool is_root=false) const override
bool isEmptyBranch(int m) const
Identifies a node inside a SHAMap.
std::uint32_t cowid_
Determines the owning SHAMap, if any.
virtual std::string getString(SHAMapNodeID const &) const
std::size_t empty() const noexcept
base_uint< Bits, Tag > getBitString()
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.
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).
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::uint8_t capacity() const
Get the number of elements allocated for each array.
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.
intr_ptr::SharedPtr< SHAMapTreeNode > * getChildren() const
Get the children array.
bool isDense() const
Check if the arrays have a dense format.
void iterNonEmptyChildIndexes(std::uint16_t isBranch, F &&f) const
Call the f callback for all non-empty branches.
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.
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
int popcnt16(std::uint16_t a)
static constexpr unsigned char const wireTypeCompressedInner
void hash_append(Hasher &h, Slice const &v)
@ innerNode
inner node in V1 tree
Returns the SHA512-Half digest of a message.