#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ripple { STLedgerEntry::STLedgerEntry(Keylet const& k) : STObject(sfLedgerEntry), key_(k.key), type_(k.type) { auto const format = LedgerFormats::getInstance().findByType(type_); if (format == nullptr) Throw( "Attempt to create a SLE of unknown type " + std::to_string(safe_cast(k.type))); set(format->getSOTemplate()); setFieldU16(sfLedgerEntryType, static_cast(type_)); } STLedgerEntry::STLedgerEntry(SerialIter& sit, uint256 const& index) : STObject(sfLedgerEntry), key_(index) { set(sit); setSLEType(); } STLedgerEntry::STLedgerEntry(STObject const& object, uint256 const& index) : STObject(object), key_(index) { setSLEType(); } void STLedgerEntry::setSLEType() { auto format = LedgerFormats::getInstance().findByType( safe_cast(getFieldU16(sfLedgerEntryType))); if (format == nullptr) Throw("invalid ledger entry type"); type_ = format->getType(); applyTemplate(format->getSOTemplate()); // May throw } std::string STLedgerEntry::getFullText() const { auto const format = LedgerFormats::getInstance().findByType(type_); if (format == nullptr) Throw("invalid ledger entry type"); std::string ret = "\""; ret += to_string(key_); ret += "\" = { "; ret += format->getName(); ret += ", "; ret += STObject::getFullText(); ret += "}"; return ret; } STBase* STLedgerEntry::copy(std::size_t n, void* buf) const { return emplace(n, buf, *this); } STBase* STLedgerEntry::move(std::size_t n, void* buf) { return emplace(n, buf, std::move(*this)); } SerializedTypeID STLedgerEntry::getSType() const { return STI_LEDGERENTRY; } std::string STLedgerEntry::getText() const { return str( boost::format("{ %s, %s }") % to_string(key_) % STObject::getText()); } Json::Value STLedgerEntry::getJson(JsonOptions options) const { Json::Value ret(STObject::getJson(options)); ret[jss::index] = to_string(key_); if (getType() == ltMPTOKEN_ISSUANCE) ret[jss::mpt_issuance_id] = to_string( makeMptID(getFieldU32(sfSequence), getAccountID(sfIssuer))); return ret; } bool STLedgerEntry::isThreadedType(Rules const& rules) const { static constexpr std::array newPreviousTxnIDTypes = { ltDIR_NODE, ltAMENDMENTS, ltFEE_SETTINGS, ltNEGATIVE_UNL, ltAMM}; // Exclude PrevTxnID/PrevTxnLgrSeq if the fixPreviousTxnID amendment is not // enabled and the ledger object type is in the above set bool const excludePrevTxnID = !rules.enabled(fixPreviousTxnID) && std::count( newPreviousTxnIDTypes.cbegin(), newPreviousTxnIDTypes.cend(), type_); return !excludePrevTxnID && getFieldIndex(sfPreviousTxnID) != -1; } bool STLedgerEntry::thread( uint256 const& txID, std::uint32_t ledgerSeq, uint256& prevTxID, std::uint32_t& prevLedgerID) { uint256 oldPrevTxID = getFieldH256(sfPreviousTxnID); JLOG(debugLog().info()) << "Thread Tx:" << txID << " prev:" << oldPrevTxID; if (oldPrevTxID == txID) { // this transaction is already threaded XRPL_ASSERT( getFieldU32(sfPreviousTxnLgrSeq) == ledgerSeq, "ripple::STLedgerEntry::thread : ledger sequence match"); return false; } prevTxID = oldPrevTxID; prevLedgerID = getFieldU32(sfPreviousTxnLgrSeq); setFieldH256(sfPreviousTxnID, txID); setFieldU32(sfPreviousTxnLgrSeq, ledgerSeq); return true; } } // namespace ripple