#pragma once #include #include #include #include #include #include #include #include #include namespace xrpl { class SHAMapTreeNode; using SHAMapTreeNodePtr = intr_ptr::SharedPtr; // These are wire-protocol identifiers used during serialization to encode the // type of a node. They should not be arbitrarily be changed. static constexpr unsigned char const kWireTypeTransaction = 0; static constexpr unsigned char const kWireTypeAccountState = 1; static constexpr unsigned char const kWireTypeInner = 2; static constexpr unsigned char const kWireTypeCompressedInner = 3; static constexpr unsigned char const kWireTypeTransactionWithMeta = 4; // Lower bound on SHAMap leaf item payload size, in bytes. inline constexpr std::size_t kMinShaMapItemBytes = 12; enum class SHAMapNodeType { TnInner = 1, TnTransactionNm = 2, // transaction, no metadata TnTransactionMd = 3, // transaction, with metadata TnAccountState = 4 }; class SHAMapTreeNode : public IntrusiveRefCounts { protected: SHAMapHash hash_; /** * Determines the owning SHAMap, if any. Used for copy-on-write semantics. * * If this value is 0, the node is not dirty and does not need to be * flushed. It is eligible for sharing and may be included multiple * SHAMap instances. */ std::uint32_t cowid_; /** * Construct a node * * @param cowid The identifier of a SHAMap. For more, see #cowid_ * @param hash The hash associated with this node, if any. */ /** @{ */ explicit SHAMapTreeNode(std::uint32_t cowid) noexcept : cowid_(cowid) { } explicit SHAMapTreeNode(std::uint32_t cowid, SHAMapHash const& hash) noexcept : hash_(hash), cowid_(cowid) { } /** @} */ public: ~SHAMapTreeNode() noexcept override = default; SHAMapTreeNode(SHAMapTreeNode const&) = delete; SHAMapTreeNode& operator=(SHAMapTreeNode const&) = delete; // Needed to support weak intrusive pointers virtual void partialDestructor() {}; /** * @defgroup SHAMap Copy-on-Write Support * * By nature, a node may appear in multiple SHAMap instances. Rather * than actually duplicating these nodes, SHAMap opts to be memory * efficient and uses copy-on-write semantics for nodes. * * Only nodes that are not modified and don't need to be flushed back * can be shared. Once a node needs to be changed, it must first be * copied and the copy must marked as not shareable. * * Note that just because a node may not be *owned* by a given SHAMap * instance does not mean that the node is NOT a part of any SHAMap. It * only means that the node is not owned exclusively by any one SHAMap. * * For more on copy-on-write, check out: * https://en.wikipedia.org/wiki/Copy-on-write */ /** @{ */ /** * Returns the SHAMap that owns this node. * * @return the ID of the SHAMap that owns this node, or 0 if the * node is not owned by any SHAMap and is a candidate for sharing. */ std::uint32_t cowid() const { return cowid_; } /** * If this node is shared with another map, mark it as no longer shared. * * Only nodes that are not modified and do not need to be flushed back * should be marked as unshared. */ void unshare() { cowid_ = 0; } /** * Make a copy of this node, setting the owner. */ virtual SHAMapTreeNodePtr clone(std::uint32_t cowid) const = 0; /** @} */ /** * Recalculate the hash of this node. */ virtual void updateHash() = 0; /** * Return the hash of this node. */ SHAMapHash const& getHash() const { return hash_; } /** * Determines the type of node. */ virtual SHAMapNodeType getType() const = 0; /** * Determines if this is a leaf node. */ virtual bool isLeaf() const = 0; /** * Determines if this is an inner node. */ virtual bool isInner() const = 0; /** * Serialize the node in a format appropriate for sending over the wire */ virtual void serializeForWire(Serializer&) const = 0; /** * Serialize the node in a format appropriate for hashing */ virtual void serializeWithPrefix(Serializer&) const = 0; virtual std::string getString(SHAMapNodeID const&) const; virtual void invariants(bool isRoot = false) const = 0; static SHAMapTreeNodePtr makeFromPrefix(Slice rawNode, SHAMapHash const& hash); static SHAMapTreeNodePtr makeFromWire(Slice rawNode); private: static SHAMapTreeNodePtr makeTransaction(Slice data, SHAMapHash const& hash, bool hashValid); static SHAMapTreeNodePtr makeAccountState(Slice data, SHAMapHash const& hash, bool hashValid); static SHAMapTreeNodePtr makeTransactionWithMeta(Slice data, SHAMapHash const& hash, bool hashValid); }; } // namespace xrpl