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) = p->hashesAndChildren_.getHashesAndChildren();
72 int cloneChildIndex = 0;
74 [&](
auto branchNum,
auto indexNum) { cloneHashes[cloneChildIndex++] = thisHashes[indexNum]; });
86 int cloneChildIndex = 0;
88 [&](
auto branchNum,
auto indexNum) { cloneChildren[cloneChildIndex++] = thisChildren[indexNum]; });
93 [&](
auto branchNum,
auto indexNum) { cloneChildren[branchNum] = thisChildren[indexNum]; });
104 Throw<std::runtime_error>(
"Invalid FI node");
106 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
110 auto hashes = ret->hashesAndChildren_.getHashes();
116 if (hashes[i].isNonZero())
117 ret->isBranch_ |= (1 << i);
120 ret->resizeChildArrays(ret->getBranchCount());
137 if (
auto const s = data.size(); (s % chunkSize != 0) || (s > chunkSize *
branchFactor))
138 Throw<std::runtime_error>(
"Invalid CI node");
142 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
144 auto hashes = ret->hashesAndChildren_.getHashes();
149 auto const pos = si.
get8();
152 Throw<std::runtime_error>(
"invalid CI node");
154 hashes[pos].as_uint256() = hash;
156 if (hashes[pos].isNonZero())
157 ret->isBranch_ |= (1 << pos);
160 ret->resizeChildArrays(ret->getBranchCount());
188 if (
auto p = children[indexNum].
get())
189 hashes[indexNum] = p->getHash();
197 XRPL_ASSERT(!
isEmpty(),
"xrpl::SHAMapInnerNode::serializeForWire : is non-empty");
220 XRPL_ASSERT(!
isEmpty(),
"xrpl::SHAMapInnerNode::serializeWithPrefix : is non-empty");
244 XRPL_ASSERT((m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::setChild : valid branch input");
245 XRPL_ASSERT(
cowid_,
"xrpl::SHAMapInnerNode::setChild : nonzero cowid");
246 XRPL_ASSERT(child.get() !=
this,
"xrpl::SHAMapInnerNode::setChild : valid child input");
248 auto const dstIsBranch = [&] {
255 auto const dstToAllocate =
popcnt16(dstIsBranch);
266 hashes[childIndex].zero();
267 children[childIndex] = std::move(child);
280 XRPL_ASSERT((m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::shareChild : valid branch input");
281 XRPL_ASSERT(
cowid_,
"xrpl::SHAMapInnerNode::shareChild : nonzero cowid");
282 XRPL_ASSERT(child,
"xrpl::SHAMapInnerNode::shareChild : non-null child input");
283 XRPL_ASSERT(child.get() !=
this,
"xrpl::SHAMapInnerNode::shareChild : valid child input");
285 XRPL_ASSERT(!
isEmptyBranch(m),
"xrpl::SHAMapInnerNode::shareChild : non-empty branch input");
292 XRPL_ASSERT(branch >= 0 && branch <
branchFactor,
"xrpl::SHAMapInnerNode::getChildPointer : valid branch input");
293 XRPL_ASSERT(!
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::getChildPointer : non-empty branch input");
305 XRPL_ASSERT(branch >= 0 && branch <
branchFactor,
"xrpl::SHAMapInnerNode::getChild : valid branch input");
306 XRPL_ASSERT(!
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::getChild : non-empty branch input");
318 XRPL_ASSERT((m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::getChildHash : valid branch input");
322 return zeroSHAMapHash;
328 XRPL_ASSERT(branch >= 0 && branch <
branchFactor,
"xrpl::SHAMapInnerNode::canonicalizeChild : valid branch input");
329 XRPL_ASSERT(node !=
nullptr,
"xrpl::SHAMapInnerNode::canonicalizeChild : valid node input");
330 XRPL_ASSERT(!
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
334 node->getHash() == hashes[childIndex],
335 "xrpl::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
341 if (children[childIndex])
344 node = children[childIndex];
349 children[childIndex] = node;
357 [[maybe_unused]]
unsigned count = 0;
363 for (
int i = 0; i < branchCount; ++i)
365 XRPL_ASSERT(hashes[i].isNonZero(),
"xrpl::SHAMapInnerNode::invariants : nonzero hash in branch");
366 if (children[i] !=
nullptr)
367 children[i]->invariants();
375 if (hashes[i].isNonZero())
379 "xrpl::SHAMapInnerNode::invariants : valid branch when "
381 if (children[i] !=
nullptr)
382 children[i]->invariants();
389 "xrpl::SHAMapInnerNode::invariants : valid branch when "
397 XRPL_ASSERT(
hash_.
isNonZero(),
"xrpl::SHAMapInnerNode::invariants : nonzero hash");
398 XRPL_ASSERT(count >= 1,
"xrpl::SHAMapInnerNode::invariants : minimum count");
402 "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.