#include #include // IWYU pragma: keep #include // IWYU pragma: keep #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { intr_ptr::SharedPtr SHAMapTreeNode::makeTransaction(Slice data, SHAMapHash const& hash, bool hashValid) { if (data.size() < kMIN_SHA_MAP_ITEM_BYTES) { Throw( "Short TXN node: " + std::to_string(data.size()) + " bytes (minimum " + std::to_string(kMIN_SHA_MAP_ITEM_BYTES) + " required)"); } auto item = makeShamapitem(sha512Half(HashPrefix::TransactionId, data), data); if (hashValid) return intr_ptr::makeShared(std::move(item), 0, hash); return intr_ptr::makeShared(std::move(item), 0); } intr_ptr::SharedPtr SHAMapTreeNode::makeTransactionWithMeta(Slice data, SHAMapHash const& hash, bool hashValid) { Serializer s(data.data(), data.size()); uint256 tag; if (s.size() < tag.kBYTES) { Throw( "Short TXN+MD node: " + std::to_string(s.size()) + " bytes (minimum " + std::to_string(tag.kBYTES) + " required for tag)"); } // FIXME: improve this interface so that the above check isn't needed if (!s.getBitString(tag, s.size() - tag.kBYTES)) { Throw( "Short TXN+MD node: failed to read tag at offset " + std::to_string(s.size() - tag.kBYTES)); } s.chop(tag.kBYTES); if (s.size() < kMIN_SHA_MAP_ITEM_BYTES) { Throw( "Short TXN+MD node: " + std::to_string(s.size()) + " bytes after tag removal (minimum " + std::to_string(kMIN_SHA_MAP_ITEM_BYTES) + " required)"); } auto item = makeShamapitem(tag, s.slice()); if (hashValid) return intr_ptr::makeShared(std::move(item), 0, hash); return intr_ptr::makeShared(std::move(item), 0); } intr_ptr::SharedPtr SHAMapTreeNode::makeAccountState(Slice data, SHAMapHash const& hash, bool hashValid) { Serializer s(data.data(), data.size()); uint256 tag; if (s.size() < tag.kBYTES) { Throw( "Short AS node: " + std::to_string(s.size()) + " bytes (minimum " + std::to_string(tag.kBYTES) + " required for tag)"); } // FIXME: improve this interface so that the above check isn't needed if (!s.getBitString(tag, s.size() - tag.kBYTES)) { Throw( "Short AS node: failed to read tag at offset " + std::to_string(s.size() - tag.kBYTES)); } s.chop(tag.kBYTES); if (tag.isZero()) Throw("Invalid AS node"); if (s.size() < kMIN_SHA_MAP_ITEM_BYTES) { Throw( "Short AS node: " + std::to_string(s.size()) + " bytes after tag removal (minimum " + std::to_string(kMIN_SHA_MAP_ITEM_BYTES) + " required)"); } auto item = makeShamapitem(tag, s.slice()); if (hashValid) return intr_ptr::makeShared(std::move(item), 0, hash); return intr_ptr::makeShared(std::move(item), 0); } intr_ptr::SharedPtr SHAMapTreeNode::makeFromWire(Slice rawNode) { if (rawNode.empty()) return {}; auto const type = rawNode[rawNode.size() - 1]; rawNode.removeSuffix(1); bool const hashValid = false; SHAMapHash const hash; if (type == kWIRE_TYPE_TRANSACTION) return makeTransaction(rawNode, hash, hashValid); if (type == kWIRE_TYPE_ACCOUNT_STATE) return makeAccountState(rawNode, hash, hashValid); if (type == kWIRE_TYPE_INNER) return SHAMapInnerNode::makeFullInner(rawNode, hash, hashValid); if (type == kWIRE_TYPE_COMPRESSED_INNER) return SHAMapInnerNode::makeCompressedInner(rawNode); if (type == kWIRE_TYPE_TRANSACTION_WITH_META) return makeTransactionWithMeta(rawNode, hash, hashValid); Throw("wire: Unknown type (" + std::to_string(type) + ")"); } intr_ptr::SharedPtr SHAMapTreeNode::makeFromPrefix(Slice rawNode, SHAMapHash const& hash) { if (rawNode.size() < 4) Throw("prefix: short node"); // FIXME: Use SerialIter::get32? // Extract the prefix auto const type = safeCast( (safeCast(rawNode[0]) << 24) + (safeCast(rawNode[1]) << 16) + (safeCast(rawNode[2]) << 8) + (safeCast(rawNode[3]))); rawNode.removePrefix(4); bool const hashValid = true; if (type == HashPrefix::TransactionId) return makeTransaction(rawNode, hash, hashValid); if (type == HashPrefix::LeafNode) return makeAccountState(rawNode, hash, hashValid); if (type == HashPrefix::InnerNode) return SHAMapInnerNode::makeFullInner(rawNode, hash, hashValid); if (type == HashPrefix::TxNode) return makeTransactionWithMeta(rawNode, hash, hashValid); Throw( "prefix: unknown type (" + std::to_string(safeCast>(type)) + ")"); } std::string SHAMapTreeNode::getString(SHAMapNodeID const& id) const { return to_string(id); } } // namespace xrpl