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);
64 SHAMapHash *cloneHashes =
nullptr, *thisHashes =
nullptr;
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());
146 if (
auto const s = data.size(); (s % chunkSize != 0) || (s > chunkSize *
branchFactor))
147 Throw<std::runtime_error>(
"Invalid CI node");
151 auto ret = intr_ptr::make_shared<SHAMapInnerNode>(0,
branchFactor);
153 auto hashes = ret->hashesAndChildren_.getHashes();
158 auto const pos = si.
get8();
161 Throw<std::runtime_error>(
"invalid CI node");
163 hashes[pos].as_uint256() = hash;
165 if (hashes[pos].isNonZero())
166 ret->isBranch_ |= (1 << pos);
169 ret->resizeChildArrays(ret->getBranchCount());
197 if (
auto p = children[indexNum].
get())
198 hashes[indexNum] = p->getHash();
206 XRPL_ASSERT(!
isEmpty(),
"xrpl::SHAMapInnerNode::serializeForWire : is non-empty");
229 XRPL_ASSERT(!
isEmpty(),
"xrpl::SHAMapInnerNode::serializeWithPrefix : is non-empty");
254 (m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::setChild : valid branch input");
255 XRPL_ASSERT(
cowid_,
"xrpl::SHAMapInnerNode::setChild : nonzero cowid");
256 XRPL_ASSERT(child.get() !=
this,
"xrpl::SHAMapInnerNode::setChild : valid child input");
258 auto const dstIsBranch = [&] {
267 auto const dstToAllocate =
popcnt16(dstIsBranch);
279 hashes[childIndex].zero();
280 children[childIndex] = std::move(child);
287 "xrpl::SHAMapInnerNode::setChild : maximum branch count");
295 (m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::shareChild : valid branch input");
296 XRPL_ASSERT(
cowid_,
"xrpl::SHAMapInnerNode::shareChild : nonzero cowid");
297 XRPL_ASSERT(child,
"xrpl::SHAMapInnerNode::shareChild : non-null child input");
298 XRPL_ASSERT(child.get() !=
this,
"xrpl::SHAMapInnerNode::shareChild : valid child input");
300 XRPL_ASSERT(!
isEmptyBranch(m),
"xrpl::SHAMapInnerNode::shareChild : non-empty branch input");
309 "xrpl::SHAMapInnerNode::getChildPointer : valid branch input");
311 !
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::getChildPointer : non-empty branch input");
325 "xrpl::SHAMapInnerNode::getChild : valid branch input");
326 XRPL_ASSERT(!
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::getChild : non-empty branch input");
339 (m >= 0) && (m <
branchFactor),
"xrpl::SHAMapInnerNode::getChildHash : valid branch input");
343 return zeroSHAMapHash;
351 "xrpl::SHAMapInnerNode::canonicalizeChild : valid branch input");
352 XRPL_ASSERT(node !=
nullptr,
"xrpl::SHAMapInnerNode::canonicalizeChild : valid node input");
355 "xrpl::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
359 node->getHash() == hashes[childIndex],
360 "xrpl::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
366 if (children[childIndex])
369 node = children[childIndex];
374 children[childIndex] = node;
382 [[maybe_unused]]
unsigned count = 0;
388 for (
int i = 0; i < branchCount; ++i)
391 hashes[i].isNonZero(),
392 "xrpl::SHAMapInnerNode::invariants : nonzero hash in branch");
393 if (children[i] !=
nullptr)
394 children[i]->invariants();
402 if (hashes[i].isNonZero())
406 "xrpl::SHAMapInnerNode::invariants : valid branch when "
408 if (children[i] !=
nullptr)
409 children[i]->invariants();
416 "xrpl::SHAMapInnerNode::invariants : valid branch when "
424 XRPL_ASSERT(
hash_.
isNonZero(),
"xrpl::SHAMapInnerNode::invariants : nonzero hash");
425 XRPL_ASSERT(count >= 1,
"xrpl::SHAMapInnerNode::invariants : minimum count");
429 "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
bool 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.