1#include <xrpl/shamap/SHAMapInnerNode.h>
3#include <xrpl/basics/IntrusivePointer.h>
4#include <xrpl/basics/IntrusivePointer.ipp>
5#include <xrpl/basics/SHAMapHash.h>
6#include <xrpl/basics/Slice.h>
7#include <xrpl/basics/base_uint.h>
8#include <xrpl/basics/contract.h>
9#include <xrpl/basics/spinlock.h>
10#include <xrpl/beast/utility/instrumentation.h>
11#include <xrpl/protocol/HashPrefix.h>
12#include <xrpl/protocol/Serializer.h>
13#include <xrpl/protocol/digest.h>
14#include <xrpl/shamap/SHAMapNodeID.h>
15#include <xrpl/shamap/SHAMapTreeNode.h>
16#include <xrpl/shamap/detail/TaggedPointer.h>
17#include <xrpl/shamap/detail/TaggedPointer.ipp>
86 std::tie(std::ignore, cloneHashes, cloneChildren) =
87 p->hashesAndChildren_.getHashesAndChildren();
92 int cloneChildIndex = 0;
94 cloneHashes[cloneChildIndex++] = thisHashes[indexNum];
100 [&](
auto branchNum,
auto indexNum) { cloneHashes[branchNum] = thisHashes[indexNum]; });
108 int cloneChildIndex = 0;
110 cloneChildren[cloneChildIndex++] = thisChildren[indexNum];
116 cloneChildren[branchNum] = thisChildren[indexNum];
134 auto hashes = ret->hashesAndChildren_.getHashes();
140 if (hashes[i].isNonZero())
141 ret->isBranch_ |= (1 << i);
144 ret->resizeChildArrays(ret->getBranchCount());
165 if (
auto const s = data.size(); (s % kChunkSize != 0) || (s > kChunkSize *
kBranchFactor))
172 auto hashes = ret->hashesAndChildren_.getHashes();
177 auto const pos = si.
get8();
182 hashes[pos].asUInt256() = hash;
184 if (hashes[pos].isNonZero())
185 ret->isBranch_ |= (1 << pos);
188 ret->resizeChildArrays(ret->getBranchCount());
216 if (
auto p = children[indexNum].
get())
217 hashes[indexNum] = p->getHash();
225 XRPL_ASSERT(!
isEmpty(),
"xrpl::SHAMapInnerNode::serializeForWire : is non-empty");
248 XRPL_ASSERT(!
isEmpty(),
"xrpl::SHAMapInnerNode::serializeWithPrefix : is non-empty");
273 (m >= 0) && (m <
kBranchFactor),
"xrpl::SHAMapInnerNode::setChild : valid branch input");
274 XRPL_ASSERT(
cowid_,
"xrpl::SHAMapInnerNode::setChild : nonzero cowid");
275 XRPL_ASSERT(child.get() !=
this,
"xrpl::SHAMapInnerNode::setChild : valid child input");
277 auto const dstIsBranch = [&] {
286 auto const dstToAllocate =
popcnt16(dstIsBranch);
296 auto const childIndex =
299 hashes[childIndex].zero();
300 children[childIndex] = std::move(child);
307 "xrpl::SHAMapInnerNode::setChild : maximum branch count");
315 (m >= 0) && (m <
kBranchFactor),
"xrpl::SHAMapInnerNode::shareChild : valid branch input");
316 XRPL_ASSERT(
cowid_,
"xrpl::SHAMapInnerNode::shareChild : nonzero cowid");
317 XRPL_ASSERT(child,
"xrpl::SHAMapInnerNode::shareChild : non-null child input");
318 XRPL_ASSERT(child.get() !=
this,
"xrpl::SHAMapInnerNode::shareChild : valid child input");
320 XRPL_ASSERT(!
isEmptyBranch(m),
"xrpl::SHAMapInnerNode::shareChild : non-empty branch input");
330 "xrpl::SHAMapInnerNode::getChildPointer : valid branch input");
332 !
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::getChildPointer : non-empty branch input");
347 "xrpl::SHAMapInnerNode::getChild : valid branch input");
348 XRPL_ASSERT(!
isEmptyBranch(branch),
"xrpl::SHAMapInnerNode::getChild : non-empty branch input");
363 "xrpl::SHAMapInnerNode::getChildHash : valid branch input");
367 return kZeroShaMapHash;
375 "xrpl::SHAMapInnerNode::canonicalizeChild : valid branch input");
376 XRPL_ASSERT(node !=
nullptr,
"xrpl::SHAMapInnerNode::canonicalizeChild : valid node input");
379 "xrpl::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
380 auto const childIndex =
384 node->getHash() == hashes[childIndex],
385 "xrpl::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
391 if (children[childIndex])
394 node = children[childIndex];
399 children[childIndex] = node;
407 [[maybe_unused]]
unsigned count = 0;
413 for (
int i = 0; i < branchCount; ++i)
416 hashes[i].isNonZero(),
417 "xrpl::SHAMapInnerNode::invariants : nonzero hash in branch");
418 if (children[i] !=
nullptr)
419 children[i]->invariants();
427 if (hashes[i].isNonZero())
431 "xrpl::SHAMapInnerNode::invariants : valid branch when "
433 if (children[i] !=
nullptr)
434 children[i]->invariants();
441 "xrpl::SHAMapInnerNode::invariants : valid branch when "
449 XRPL_ASSERT(
hash_.isNonZero(),
"xrpl::SHAMapInnerNode::invariants : nonzero hash");
450 XRPL_ASSERT(count >= 1,
"xrpl::SHAMapInnerNode::invariants : minimum count");
453 (count == 0) ?
hash_.isZero() :
hash_.isNonZero(),
454 "xrpl::SHAMapInnerNode::invariants : hash and count do match");
static constexpr std::size_t kBytes
Classes to handle arrays of spinlocks packed into a single atomic integer:
uint256 const & asUInt256() const
void serializeWithPrefix(Serializer &) const override
Serialize the node in a format appropriate for hashing.
void updateHash() override
Recalculate the hash of this node.
TaggedPointer hashesAndChildren_
Opaque type that contains the hashes array (array of type SHAMapHash) and the children array (array o...
static constexpr unsigned int kBranchFactor
Each inner node has 16 children (the 'radix tree' part of the map).
SHAMapHash const & getChildHash(int m) const
~SHAMapInnerNode() override
void updateHashDeep()
Recalculate the hash of all children and this node.
void shareChild(int m, SHAMapTreeNodePtr const &child)
void iterNonEmptyChildIndexes(F &&f) const
Call the f callback for all non-empty branches.
SHAMapTreeNodePtr clone(std::uint32_t cowid) const override
Make a copy of this node, setting the owner.
SHAMapTreeNodePtr getChild(int branch)
SHAMapTreeNodePtr canonicalizeChild(int branch, SHAMapTreeNodePtr node)
SHAMapTreeNode * getChildPointer(int branch)
int getBranchCount() const
static SHAMapTreeNodePtr makeCompressedInner(Slice data)
std::string getString(SHAMapNodeID const &) const override
SHAMapInnerNode(std::uint32_t cowid, std::uint8_t numAllocatedChildren=2)
void setChild(int m, SHAMapTreeNodePtr child)
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 invariants(bool isRoot=false) const override
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.
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_.
static SHAMapTreeNodePtr makeFullInner(Slice data, SHAMapHash const &hash, bool hashValid)
bool isEmptyBranch(int m) const
Identifies a node inside a SHAMap.
std::uint32_t cowid_
Determines the owning SHAMap, if any.
SHAMapTreeNode(std::uint32_t cowid) noexcept
Construct a node.
virtual std::string getString(SHAMapNodeID const &) const
BaseUInt< Bits, Tag > getBitString()
bool empty() const noexcept
int addBitString(BaseUInt< Bits, Tag > const &v)
int add8(unsigned char i)
void reset()
Set the pointer to null, decrement the strong count, and run the appropriate release action.
An immutable linear range of bytes.
A spinlock implemented on top of an atomic integer.
TaggedPointer is a combination of a pointer and a mask stored in the lowest two bits.
std::uint32_t cowid() const
Returns the SHAMap that owns this node.
std::enable_if_t< IsContiguouslyHashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
SharedPtr< T > makeShared(A &&... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
intr_ptr::SharedPtr< SHAMapTreeNode > SHAMapTreeNodePtr
detail::BasicSha512HalfHasher< false > sha512_half_hasher
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 kWireTypeCompressedInner
std::string to_string(BaseUInt< Bits, Tag > const &a)
int popcnt16(std::uint16_t a)
void hash_append(Hasher &h, Slice const &v)
@ InnerNode
inner node in V1 tree
static constexpr unsigned char const kWireTypeInner
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)