20#include <xrpld/shamap/SHAMapInnerNode.h>
21#include <xrpld/shamap/SHAMapTreeNode.h>
22#include <xrpld/shamap/detail/TaggedPointer.ipp>
23#include <xrpl/basics/Slice.h>
24#include <xrpl/basics/contract.h>
25#include <xrpl/basics/spinlock.h>
26#include <xrpl/protocol/HashPrefix.h>
27#include <xrpl/protocol/digest.h>
75 auto p = std::make_shared<SHAMapInnerNode>(
cowid, branchCount);
82 std::tie(std::ignore, cloneHashes, cloneChildren) =
83 p->hashesAndChildren_.getHashesAndChildren();
84 std::tie(std::ignore, thisHashes, thisChildren) =
89 int cloneChildIndex = 0;
91 cloneHashes[cloneChildIndex++] = thisHashes[indexNum];
97 cloneHashes[branchNum] = thisHashes[indexNum];
106 int cloneChildIndex = 0;
108 cloneChildren[cloneChildIndex++] = thisChildren[indexNum];
114 cloneChildren[branchNum] = thisChildren[indexNum];
129 Throw<std::runtime_error>(
"Invalid FI node");
131 auto ret = std::make_shared<SHAMapInnerNode>(0,
branchFactor);
135 auto hashes = ret->hashesAndChildren_.getHashes();
141 if (hashes[i].isNonZero())
142 ret->isBranch_ |= (1 << i);
145 ret->resizeChildArrays(ret->getBranchCount());
162 if (
auto const s = data.size();
164 Throw<std::runtime_error>(
"Invalid CI node");
168 auto ret = std::make_shared<SHAMapInnerNode>(0,
branchFactor);
170 auto hashes = ret->hashesAndChildren_.getHashes();
175 auto const pos = si.
get8();
178 Throw<std::runtime_error>(
"invalid CI node");
180 hashes[pos].as_uint256() = hash;
182 if (hashes[pos].isNonZero())
183 ret->isBranch_ |= (1 << pos);
186 ret->resizeChildArrays(ret->getBranchCount());
212 std::tie(std::ignore, hashes, children) =
215 if (children[indexNum] !=
nullptr)
216 hashes[indexNum] = children[indexNum]->
getHash();
225 !
isEmpty(),
"ripple::SHAMapInnerNode::serializeForWire : is non-empty");
251 "ripple::SHAMapInnerNode::serializeWithPrefix : is non-empty");
278 "ripple::SHAMapInnerNode::setChild : valid branch input");
279 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::setChild : nonzero cowid");
282 "ripple::SHAMapInnerNode::setChild : valid child input");
284 auto const dstIsBranch = [&] {
291 auto const dstToAllocate =
popcnt16(dstIsBranch);
303 hashes[childIndex].zero();
304 children[childIndex] = std::move(child);
311 "ripple::SHAMapInnerNode::setChild : maximum branch count");
320 "ripple::SHAMapInnerNode::shareChild : valid branch input");
321 XRPL_ASSERT(
cowid_,
"ripple::SHAMapInnerNode::shareChild : nonzero cowid");
323 child,
"ripple::SHAMapInnerNode::shareChild : non-null child input");
326 "ripple::SHAMapInnerNode::shareChild : valid child input");
330 "ripple::SHAMapInnerNode::shareChild : non-empty branch input");
339 "ripple::SHAMapInnerNode::getChildPointer : valid branch input");
342 "ripple::SHAMapInnerNode::getChildPointer : non-empty branch input");
356 "ripple::SHAMapInnerNode::getChild : valid branch input");
359 "ripple::SHAMapInnerNode::getChild : non-empty branch input");
373 "ripple::SHAMapInnerNode::getChildHash : valid branch input");
377 return zeroSHAMapHash;
387 "ripple::SHAMapInnerNode::canonicalizeChild : valid branch input");
390 "ripple::SHAMapInnerNode::canonicalizeChild : valid node input");
393 "ripple::SHAMapInnerNode::canonicalizeChild : non-empty branch input");
397 node->getHash() == hashes[childIndex],
398 "ripple::SHAMapInnerNode::canonicalizeChild : node and branch inputs "
404 if (children[childIndex])
407 node = children[childIndex];
412 children[childIndex] = node;
420 [[maybe_unused]]
unsigned count = 0;
421 auto [numAllocated, hashes, children] =
427 for (
int i = 0; i < branchCount; ++i)
430 hashes[i].isNonZero(),
431 "ripple::SHAMapInnerNode::invariants : nonzero hash in branch");
432 if (children[i] !=
nullptr)
433 children[i]->invariants();
441 if (hashes[i].isNonZero())
445 "ripple::SHAMapInnerNode::invariants : valid branch when "
447 if (children[i] !=
nullptr)
448 children[i]->invariants();
455 "ripple::SHAMapInnerNode::invariants : valid branch when "
465 "ripple::SHAMapInnerNode::invariants : nonzero hash");
467 count >= 1,
"ripple::SHAMapInnerNode::invariants : minimum count");
471 "ripple::SHAMapInnerNode::invariants : hash and count do match");
uint256 const & as_uint256() const
std::uint32_t fullBelowGen_
void shareChild(int m, std::shared_ptr< SHAMapTreeNode > const &child)
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)
std::shared_ptr< 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)
std::shared_ptr< SHAMapTreeNode > getChild(int branch)
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.
static std::shared_ptr< SHAMapTreeNode > makeCompressedInner(Slice data)
void setChild(int m, std::shared_ptr< SHAMapTreeNode > child)
SHAMapHash const & getChildHash(int m) const
void invariants(bool is_root=false) const override
std::string getString(SHAMapNodeID const &) const override
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.
std::shared_ptr< SHAMapTreeNode > canonicalizeChild(int branch, std::shared_ptr< SHAMapTreeNode > node)
static std::shared_ptr< SHAMapTreeNode > makeFullInner(Slice data, SHAMapHash const &hash, bool hashValid)
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.
Identifies a node inside a SHAMap.
virtual std::string getString(SHAMapNodeID const &) const
std::uint32_t cowid_
Determines the owning SHAMap, if any.
SHAMapHash const & getHash() const
Return the hash of this node.
base_uint< Bits, Tag > getBitString()
std::size_t empty() const noexcept
int addBitString(base_uint< Bits, Tag > const &v)
int add8(unsigned char i)
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).
SHAMapHash * getHashes() const
Get the hashes array.
std::shared_ptr< SHAMapTreeNode > * getChildren() const
Get the children 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.
std::tuple< std::uint8_t, SHAMapHash *, std::shared_ptr< SHAMapTreeNode > * > getHashesAndChildren() const
Get the number of elements in each array and a pointer to the start of each array.
bool isDense() const
Check if the arrays have a dense format.
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)
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.