20 #include <ripple/shamap/SHAMapInnerNode.h>
22 #include <ripple/basics/Log.h>
23 #include <ripple/basics/Slice.h>
24 #include <ripple/basics/contract.h>
25 #include <ripple/beast/core/LexicalCast.h>
26 #include <ripple/protocol/HashPrefix.h>
27 #include <ripple/protocol/digest.h>
28 #include <ripple/shamap/SHAMapTreeNode.h>
29 #include <ripple/shamap/impl/TaggedPointer.ipp>
31 #include <openssl/sha.h>
39 #include <immintrin.h>
66 assert(index >= 0 && index < 16);
85 std::memory_order_acquire,
86 std::memory_order_relaxed);
100 for (
int i = 0; i != 100; ++i)
162 auto p = std::make_shared<SHAMapInnerNode>(
cowid, branchCount);
169 std::tie(std::ignore, cloneHashes, cloneChildren) =
170 p->hashesAndChildren_.getHashesAndChildren();
171 std::tie(std::ignore, thisHashes, thisChildren) =
176 int cloneChildIndex = 0;
178 cloneHashes[cloneChildIndex++] = thisHashes[indexNum];
184 cloneHashes[branchNum] = thisHashes[indexNum];
193 int cloneChildIndex = 0;
195 cloneChildren[cloneChildIndex++] = thisChildren[indexNum];
201 cloneChildren[branchNum] = thisChildren[indexNum];
216 Throw<std::runtime_error>(
"Invalid FI node");
218 auto ret = std::make_shared<SHAMapInnerNode>(0,
branchFactor);
222 auto hashes = ret->hashesAndChildren_.getHashes();
228 if (hashes[i].isNonZero())
229 ret->isBranch_ |= (1 << i);
232 ret->resizeChildArrays(ret->getBranchCount());
249 if (
auto const s = data.size();
251 Throw<std::runtime_error>(
"Invalid CI node");
255 auto ret = std::make_shared<SHAMapInnerNode>(0,
branchFactor);
257 auto hashes = ret->hashesAndChildren_.getHashes();
262 auto const pos = si.
get8();
265 Throw<std::runtime_error>(
"invalid CI node");
267 hashes[pos].as_uint256() = hash;
269 if (hashes[pos].isNonZero())
270 ret->isBranch_ |= (1 << pos);
273 ret->resizeChildArrays(ret->getBranchCount());
299 std::tie(std::ignore, hashes, children) =
302 if (children[indexNum] !=
nullptr)
303 hashes[indexNum] = children[indexNum]->
getHash();
374 assert(child.get() !=
this);
376 auto const dstIsBranch = [&] {
383 auto const dstToAllocate = popcnt16(dstIsBranch);
395 hashes[childIndex].zero();
396 children[childIndex] = child;
411 assert(child.get() !=
this);
450 return zeroSHAMapHash;
463 assert(node->getHash() == hashes[childIndex]);
468 if (children[childIndex])
471 node = children[childIndex];
476 children[childIndex] = node;
485 auto [numAllocated, hashes, children] =
491 for (
int i = 0; i < branchCount; ++i)
493 assert(hashes[i].isNonZero());
494 if (children[i] !=
nullptr)
495 children[i]->invariants();
503 if (hashes[i].isNonZero())
506 if (children[i] !=
nullptr)
507 children[i]->invariants();
std::uint32_t cowid() const
Returns the SHAMap that owns this node.
void serializeWithPrefix(Serializer &) const override
Serialize the node in a format appropriate for hashing.
void setChild(int m, std::shared_ptr< SHAMapTreeNode > const &child)
SpinBitlock(std::atomic< std::uint16_t > &lock, int index)
std::shared_ptr< SHAMapTreeNode > clone(std::uint32_t cowid) const override
Make a copy of this node, setting the owner.
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).
TaggedPointer hashesAndChildren_
Opaque type that contains the hashes array (array of type SHAMapHash) and the children array (array o...
Returns the SHA512-Half digest of a message.
std::shared_ptr< SHAMapTreeNode > getChild(int branch)
An immutable linear range of bytes.
static std::shared_ptr< SHAMapTreeNode > makeFullInner(Slice data, SHAMapHash const &hash, bool hashValid)
std::shared_ptr< SHAMapTreeNode > canonicalizeChild(int branch, std::shared_ptr< SHAMapTreeNode > node)
std::uint32_t cowid_
Determines the owning SHAMap, if any.
int add8(unsigned char i)
void updateHash() override
Recalculate the hash of this node.
static constexpr unsigned int branchFactor
Each inner node has 16 children (the 'radix tree' part of the map)
void shareChild(int m, std::shared_ptr< SHAMapTreeNode > const &child)
static constexpr unsigned const char wireTypeInner
Identifies a node inside a SHAMap.
T compare_exchange_weak(T... args)
virtual std::string getString(SHAMapNodeID const &) const
void iterChildren(F &&f) const
Call the f callback for all 16 (branchFactor) branches - even if the branch is empty.
TaggedPointer is a combination of a pointer and a mask stored in the lowest two bits.
SpinBitlock(std::atomic< std::uint16_t > &lock)
bool isEmptyBranch(int m) const
void iterNonEmptyChildIndexes(F &&f) const
Call the f callback for all non-empty branches.
std::string getString(SHAMapNodeID const &) const override
@ innerNode
inner node in V1 tree
SHAMapHash const & getChildHash(int m) const
static constexpr std::size_t bytes
void resizeChildArrays(std::uint8_t toAllocate)
Convert arrays stored in hashesAndChildren_ so they can store the requested number of children.
std::size_t empty() const noexcept
SHAMapHash * getHashes() const
Get the hashes array.
bool isDense() const
Check if the arrays have a dense format.
std::optional< int > getChildIndex(int i) const
Get the child's index inside the hashes or children array (stored in hashesAndChildren_.
A specialized 16-way spinlock used to protect inner node branches.
void updateHashDeep()
Recalculate the hash of all children and this node.
SHAMapInnerNode(std::uint32_t cowid, std::uint8_t numAllocatedChildren=2)
std::atomic< std::uint16_t > & bits_
int getBranchCount() const
void iterNonEmptyChildIndexes(std::uint16_t isBranch, F &&f) const
Call the f callback for all non-empty branches.
SHAMapHash const & getHash() const
Return the hash of this node.
static constexpr unsigned const char wireTypeCompressedInner
base_uint< Bits, Tag > getBitString()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
void serializeForWire(Serializer &) const override
Serialize the node in a format appropriate for sending over the wire.
int addBitString(base_uint< Bits, Tag > const &v)
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.
std::shared_ptr< SHAMapTreeNode > * getChildren() const
Get the children array.
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
int add32(std::uint32_t i)
void iterChildren(std::uint16_t isBranch, F &&f) const
Call the f callback for all 16 (branchFactor) branches - even if the branch is empty.
static std::shared_ptr< SHAMapTreeNode > makeCompressedInner(Slice data)
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.
uint256 const & as_uint256() const
SHAMapTreeNode * getChildPointer(int branch)
std::uint8_t capacity() const
Get the number of elements allocated for each array.
void hash_append(Hasher &h, ValidatorBlobInfo const &blobInfo)
std::atomic< std::uint16_t > lock_
A bitlock for the children of this node, with one bit per child.
void invariants(bool is_root=false) const override
std::uint32_t fullBelowGen_