From babaac9305c2fee0238c7cd65094fbbcc039408d Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 5 Jun 2015 07:25:45 -0700 Subject: [PATCH] Refactor Ledger and support classes: This performs a deep refactor on the Ledger class and its supporting classes, in preparation for the move to shared_ptr in places where the SLE is immutable and we are currently using shared_ptr. Member functions are converted to free functions, the SLECache is an explicit parameter, one line convenience functions are removed to streamline the interface. Some callers are changed to use instead of SLECache: * Moved to its own header file RippleState: * Remove unused functions * Store the SLE as const * Simplify callers AccountState: * Remove unused members * Simplify existing members Ledger: * Replace writeBack with insert and update * Remove unused functions * Remove LedgerStateParams * Move getLastFullLedger to Application * add entryCacheI, exists, fetch, erase * Use boost::optional where it makes sense * Make member functions free functions Free functions: * fetch: cache-aware SLE retrieval * forEachItem, forEachItemAfter * (various) --- Builds/VisualStudio2013/RippleD.vcxproj | 2 + .../VisualStudio2013/RippleD.vcxproj.filters | 3 + Builds/VisualStudio2013/ripple.sln | 2 +- src/ripple/app/ledger/AcceptedLedger.cpp | 2 +- src/ripple/app/ledger/Ledger.cpp | 942 ++++++++---------- src/ripple/app/ledger/Ledger.h | 400 ++++---- src/ripple/app/ledger/LedgerEntrySet.cpp | 133 ++- src/ripple/app/ledger/LedgerEntrySet.h | 16 +- src/ripple/app/ledger/LedgerToJson.h | 10 +- src/ripple/app/ledger/SLECache.h | 37 + src/ripple/app/ledger/impl/LedgerCleaner.cpp | 8 +- src/ripple/app/ledger/impl/LedgerMaster.cpp | 143 +-- src/ripple/app/ledger/tests/common_ledger.cpp | 17 +- src/ripple/app/main/Application.cpp | 60 +- src/ripple/app/main/Application.h | 4 +- src/ripple/app/misc/AccountState.cpp | 29 +- src/ripple/app/misc/AccountState.h | 59 +- src/ripple/app/misc/NetworkOPs.cpp | 32 +- src/ripple/app/misc/NetworkOPs.h | 8 - src/ripple/app/paths/PathRequest.cpp | 13 +- src/ripple/app/paths/Pathfinder.cpp | 18 +- src/ripple/app/paths/RippleState.cpp | 32 +- src/ripple/app/paths/RippleState.h | 59 +- src/ripple/app/tests/Env.cpp | 7 +- src/ripple/app/tests/Env.h | 7 +- src/ripple/app/tests/JTx.cpp | 5 +- src/ripple/app/tx/impl/LocalTxs.cpp | 12 +- src/ripple/app/tx/impl/TransactionEngine.cpp | 16 +- src/ripple/app/tx/tests/MultiSign.test.cpp | 10 +- src/ripple/app/tx/tests/common_transactor.cpp | 36 +- src/ripple/app/tx/tests/common_transactor.h | 6 +- src/ripple/basics/base_uint.h | 10 +- src/ripple/protocol/STLedgerEntry.h | 22 +- src/ripple/protocol/impl/STLedgerEntry.cpp | 58 +- src/ripple/rpc/handlers/AccountInfo.cpp | 7 +- src/ripple/rpc/handlers/AccountLines.cpp | 19 +- src/ripple/rpc/handlers/AccountObjects.cpp | 3 +- src/ripple/rpc/handlers/AccountOffers.cpp | 14 +- src/ripple/rpc/handlers/LedgerEntry.cpp | 4 +- src/ripple/rpc/handlers/LedgerRequest.cpp | 28 +- src/ripple/rpc/handlers/NoRippleCheck.cpp | 13 +- src/ripple/rpc/impl/Accounts.cpp | 4 +- src/ripple/rpc/impl/GetAccountObjects.cpp | 16 +- src/ripple/rpc/impl/TransactionSign.cpp | 19 +- src/ripple/shamap/SHAMapItem.h | 8 + 45 files changed, 1224 insertions(+), 1129 deletions(-) create mode 100644 src/ripple/app/ledger/SLECache.h diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index d9b722a90b..7df5c47eaf 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -1480,6 +1480,8 @@ + + True True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index e40bf286de..5965585a70 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -2205,6 +2205,9 @@ ripple\app\ledger + + ripple\app\ledger + ripple\app\ledger\tests diff --git a/Builds/VisualStudio2013/ripple.sln b/Builds/VisualStudio2013/ripple.sln index a05e9d4844..9e43cd3024 100644 --- a/Builds/VisualStudio2013/ripple.sln +++ b/Builds/VisualStudio2013/ripple.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Express 2013 for Windows Desktop VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RippleD", "RippleD.vcxproj", "{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}" +Project("{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}") = "RippleD", "RippleD.vcxproj", "{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/ripple/app/ledger/AcceptedLedger.cpp b/src/ripple/app/ledger/AcceptedLedger.cpp index df289988bf..13a8291cf9 100644 --- a/src/ripple/app/ledger/AcceptedLedger.cpp +++ b/src/ripple/app/ledger/AcceptedLedger.cpp @@ -45,7 +45,7 @@ AcceptedLedger::AcceptedLedger (Ledger::ref ledger) : mLedger (ledger) AcceptedLedger::pointer AcceptedLedger::makeAcceptedLedger (Ledger::ref ledger) { - AcceptedLedger::pointer ret = s_cache.fetch (ledger->getHash ()); + AcceptedLedger::pointer ret = s_cache.fetch (ledger->getHash()); if (ret) return ret; diff --git a/src/ripple/app/ledger/Ledger.cpp b/src/ripple/app/ledger/Ledger.cpp index 74568a8a04..c7fba64843 100644 --- a/src/ripple/app/ledger/Ledger.cpp +++ b/src/ripple/app/ledger/Ledger.cpp @@ -47,12 +47,33 @@ #include #include #include +#include namespace ripple { +/* Create the "genesis" account root. + The genesis account root contains all the XRP + that will ever exist in the system. + @param id The AccountID of the account root + @param drops The number of drops to start with +*/ +static +std::shared_ptr +makeGenesisAccount (Account const& id, + std::uint64_t drops) +{ + std::shared_ptr sle = + std::make_shared(ltACCOUNT_ROOT, + getAccountRootIndex(id)); + sle->setFieldAccount (sfAccount, id); + sle->setFieldAmount (sfBalance, drops); + sle->setFieldU32 (sfSequence, 1); + return sle; +} + Ledger::Ledger (RippleAddress const& masterID, std::uint64_t startAmount) : mTotCoins (startAmount) - , mLedgerSeq (1) // First Ledger + , seq_ (1) // First Ledger , mCloseTime (0) , mParentCloseTime (0) , mCloseResolution (ledgerDefaultTimeResolution) @@ -63,18 +84,12 @@ Ledger::Ledger (RippleAddress const& masterID, std::uint64_t startAmount) , mAccountStateMap (std::make_shared (SHAMapType::STATE, getApp().family(), deprecatedLogs().journal("SHAMap"))) { - // special case: put coins in root account - auto startAccount = std::make_shared (masterID); - auto& sle = startAccount->peekSLE (); - sle.setFieldAmount (sfBalance, startAmount); - sle.setFieldU32 (sfSequence, 1); - + auto const sle = makeGenesisAccount( + masterID.getAccountID(), startAmount); WriteLog (lsTRACE, Ledger) - << "root account: " << startAccount->peekSLE ().getJson (0); - - writeBack (lepCREATE, startAccount->getSLE ()); - - mAccountStateMap->flushDirty (hotACCOUNT_NODE, mLedgerSeq); + << "root account: " << sle->getJson(0); + insert(*sle); + mAccountStateMap->flushDirty (hotACCOUNT_NODE, seq_); } Ledger::Ledger (uint256 const& parentHash, @@ -91,7 +106,7 @@ Ledger::Ledger (uint256 const& parentHash, , mTransHash (transHash) , mAccountHash (accountHash) , mTotCoins (totCoins) - , mLedgerSeq (ledgerSeq) + , seq_ (ledgerSeq) , mCloseTime (closeTime) , mParentCloseTime (parentCloseTime) , mCloseResolution (closeResolution) @@ -125,11 +140,11 @@ Ledger::Ledger (uint256 const& parentHash, } // Create a new ledger that's a snapshot of this one -Ledger::Ledger (Ledger& ledger, +Ledger::Ledger (Ledger const& ledger, bool isMutable) : mParentHash (ledger.mParentHash) , mTotCoins (ledger.mTotCoins) - , mLedgerSeq (ledger.mLedgerSeq) + , seq_ (ledger.seq_) , mCloseTime (ledger.mCloseTime) , mParentCloseTime (ledger.mParentCloseTime) , mCloseResolution (ledger.mCloseResolution) @@ -148,7 +163,7 @@ Ledger::Ledger (Ledger& ledger, Ledger::Ledger (bool /* dummy */, Ledger& prevLedger) : mTotCoins (prevLedger.mTotCoins) - , mLedgerSeq (prevLedger.mLedgerSeq + 1) + , seq_ (prevLedger.seq_ + 1) , mParentCloseTime (prevLedger.mCloseTime) , mCloseResolution (prevLedger.mCloseResolution) , mCloseFlags (0) @@ -164,7 +179,7 @@ Ledger::Ledger (bool /* dummy */, assert (mParentHash.isNonZero ()); mCloseResolution = getNextLedgerTimeResolution (prevLedger.mCloseResolution, - prevLedger.getCloseAgree (), mLedgerSeq); + prevLedger.getCloseAgree (), seq_); if (prevLedger.mCloseTime == 0) { @@ -187,7 +202,7 @@ Ledger::Ledger (void const* data, Ledger::Ledger (std::uint32_t ledgerSeq, std::uint32_t closeTime) : mTotCoins (0) - , mLedgerSeq (ledgerSeq) + , seq_ (ledgerSeq) , mCloseTime (closeTime) , mParentCloseTime (0) , mCloseResolution (ledgerDefaultTimeResolution) @@ -231,9 +246,9 @@ void Ledger::setImmutable () mAccountStateMap->setImmutable (); } -void Ledger::updateHash () +void Ledger::updateHash() { - if (!mImmutable) + if (! mImmutable) { if (mTransactionMap) mTransHash = mTransactionMap->getHash (); @@ -249,7 +264,7 @@ void Ledger::updateHash () // VFALCO This has to match addRaw mHash = sha512Half( HashPrefix::ledgerMaster, - std::uint32_t(mLedgerSeq), + std::uint32_t(seq_), std::uint64_t(mTotCoins), mParentHash, mTransHash, @@ -266,7 +281,7 @@ void Ledger::setRaw (SerialIter& sit, bool hasPrefix) if (hasPrefix) sit.get32 (); - mLedgerSeq = sit.get32 (); + seq_ = sit.get32 (); mTotCoins = sit.get64 (); mParentHash = sit.get256 (); mTransHash = sit.get256 (); @@ -276,19 +291,15 @@ void Ledger::setRaw (SerialIter& sit, bool hasPrefix) mCloseResolution = sit.get8 (); mCloseFlags = sit.get8 (); updateHash (); - - if (mValidHash) - { - mTransactionMap = std::make_shared (SHAMapType::TRANSACTION, mTransHash, - getApp().family(), deprecatedLogs().journal("SHAMap")); - mAccountStateMap = std::make_shared (SHAMapType::STATE, mAccountHash, - getApp().family(), deprecatedLogs().journal("SHAMap")); - } + mTransactionMap = std::make_shared (SHAMapType::TRANSACTION, mTransHash, + getApp().family(), deprecatedLogs().journal("SHAMap")); + mAccountStateMap = std::make_shared (SHAMapType::STATE, mAccountHash, + getApp().family(), deprecatedLogs().journal("SHAMap")); } void Ledger::addRaw (Serializer& s) const { - s.add32 (mLedgerSeq); + s.add32 (seq_); s.add64 (mTotCoins); s.add256 (mParentHash); s.add256 (mTransHash); @@ -324,36 +335,12 @@ void Ledger::setAccepted () setImmutable (); } -bool Ledger::hasAccount (RippleAddress const& accountID) const -{ - return mAccountStateMap->hasItem (getAccountRootIndex (accountID)); -} - bool Ledger::addSLE (SLE const& sle) { SHAMapItem item (sle.getIndex(), sle.getSerializer()); return mAccountStateMap->addItem(item, false, false); } -AccountState::pointer Ledger::getAccountState (RippleAddress const& accountID) const -{ - SLE::pointer sle = getSLEi (getAccountRootIndex (accountID)); - - if (!sle) - { - WriteLog (lsDEBUG, Ledger) << "Ledger:getAccountState:" << - " not found: " << accountID.humanAccountID () << - ": " << to_string (getAccountRootIndex (accountID)); - - return AccountState::pointer (); - } - - if (sle->getType () != ltACCOUNT_ROOT) - return AccountState::pointer (); - - return std::make_shared (sle, accountID); -} - bool Ledger::addTransaction (uint256 const& txID, const Serializer& txn) { // low-level - just add to table @@ -422,7 +409,7 @@ Transaction::pointer Ledger::getTransaction (uint256 const& transID) const } if (txn->getStatus () == NEW) - txn->setStatus (mClosed ? COMMITTED : INCLUDED, mLedgerSeq); + txn->setStatus (mClosed ? COMMITTED : INCLUDED, seq_); getApp().getMasterTransaction ().canonicalize (&txn); return txn; @@ -465,7 +452,7 @@ STTx::pointer Ledger::getSMTransaction ( SerialIter tSit (make_Slice(vl)); txMeta = std::make_shared ( - item->getTag (), mLedgerSeq, sit.getVL ()); + item->key(), seq_, sit.getVL ()); return std::make_shared (tSit); } @@ -507,13 +494,13 @@ bool Ledger::getTransaction ( it.getVL (); // skip transaction meta = std::make_shared ( - txID, mLedgerSeq, it.getVL ()); + txID, seq_, it.getVL ()); } else return false; if (txn->getStatus () == NEW) - txn->setStatus (mClosed ? COMMITTED : INCLUDED, mLedgerSeq); + txn->setStatus (mClosed ? COMMITTED : INCLUDED, seq_); getApp().getMasterTransaction ().canonicalize (&txn); return true; @@ -533,7 +520,7 @@ bool Ledger::getTransactionMeta ( SerialIter it (item->slice()); it.getVL (); // skip transaction - meta = std::make_shared (txID, mLedgerSeq, it.getVL ()); + meta = std::make_shared (txID, seq_, it.getVL ()); return true; } @@ -556,11 +543,10 @@ bool Ledger::getMetaHex (uint256 const& transID, std::string& hex) const } uint256 const& -Ledger::getHash () +Ledger::getHash() { - if (!mValidHash) - updateHash (); - + if (! mValidHash) + updateHash(); return mHash; } @@ -601,7 +587,7 @@ bool Ledger::saveValidatedLedger (bool current) WriteLog (lsFATAL, Ledger) << "sAL: " << getAccountHash () << " != " << mAccountStateMap->getHash (); WriteLog (lsFATAL, Ledger) << "saveAcceptedLedger: seq=" - << mLedgerSeq << ", current=" << current; + << seq_ << ", current=" << current; assert (false); } @@ -624,7 +610,7 @@ bool Ledger::saveValidatedLedger (bool current) catch (...) { WriteLog (lsWARNING, Ledger) << "An accepted ledger was missing nodes"; - getApp().getLedgerMaster().failedSave(mLedgerSeq, mHash); + getApp().getLedgerMaster().failedSave(seq_, mHash); // Clients can now trust the database for information about this // ledger sequence. getApp().pendingSaves().erase(getLedgerSeq()); @@ -633,7 +619,7 @@ bool Ledger::saveValidatedLedger (bool current) { auto db = getApp().getLedgerDB ().checkoutDb(); - *db << boost::str (deleteLedger % mLedgerSeq); + *db << boost::str (deleteLedger % seq_); } { @@ -699,7 +685,7 @@ bool Ledger::saveValidatedLedger (bool current) } else WriteLog (lsWARNING, Ledger) - << "Transaction in ledger " << mLedgerSeq + << "Transaction in ledger " << seq_ << " affects no accounts"; *db << @@ -716,7 +702,7 @@ bool Ledger::saveValidatedLedger (bool current) // TODO(tom): ARG! *db << boost::str (addLedger % - to_string (getHash ()) % mLedgerSeq % to_string (mParentHash) % + to_string (getHash ()) % seq_ % to_string (mParentHash) % beast::lexicalCastThrow (mTotCoins) % mCloseTime % mParentCloseTime % mCloseResolution % mCloseFlags % to_string (mAccountHash) % to_string (mTransHash)); @@ -736,7 +722,7 @@ bool Ledger::saveValidatedLedger (bool current) * @return The ledger, ledger sequence, and ledger hash. */ std::tuple -loadHelper(std::string const& sqlSuffix) +loadLedgerHelper(std::string const& sqlSuffix) { Ledger::pointer ledger; uint256 ledgerHash; @@ -827,7 +813,7 @@ Ledger::pointer Ledger::loadByIndex (std::uint32_t ledgerIndex) std::ostringstream s; s << "WHERE LedgerSeq = " << ledgerIndex; std::tie (ledger, std::ignore, std::ignore) = - loadHelper (s.str ()); + loadLedgerHelper (s.str ()); } finishLoadByIndexOrHash (ledger); @@ -841,7 +827,7 @@ Ledger::pointer Ledger::loadByHash (uint256 const& ledgerHash) std::ostringstream s; s << "WHERE LedgerHash = '" << ledgerHash << "'"; std::tie (ledger, std::ignore, std::ignore) = - loadHelper (s.str ()); + loadLedgerHelper (s.str ()); } finishLoadByIndexOrHash (ledger); @@ -945,52 +931,6 @@ Ledger::getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq) return ret; } -Ledger::pointer Ledger::getLastFullLedger () -{ - try - { - Ledger::pointer ledger; - std::uint32_t ledgerSeq; - uint256 ledgerHash; - std::tie (ledger, ledgerSeq, ledgerHash) = - loadHelper ("order by LedgerSeq desc limit 1"); - - if (!ledger) - return ledger; - - ledger->setClosed (); - - if (getApp().getOPs ().haveLedger (ledgerSeq)) - { - ledger->setAccepted (); - ledger->setValidated (); - } - - if (ledger->getHash () != ledgerHash) - { - if (ShouldLog (lsERROR, Ledger)) - { - WriteLog (lsERROR, Ledger) << "Failed on ledger"; - Json::Value p; - addJson (p, {*ledger, LedgerFill::full}); - WriteLog (lsERROR, Ledger) << p; - } - - assert (false); - return Ledger::pointer (); - } - - WriteLog (lsTRACE, Ledger) << "Loaded ledger: " << ledgerHash; - return ledger; - } - catch (SHAMapMissingNode& sn) - { - WriteLog (lsWARNING, Ledger) - << "Database contains ledger with missing nodes: " << sn; - return Ledger::pointer (); - } -} - void Ledger::setAcquiring (void) { if (!mTransactionMap || !mAccountStateMap) @@ -1026,57 +966,73 @@ void Ledger::setCloseTime (boost::posix_time::ptime ptm) mCloseTime = iToSeconds (ptm); } -LedgerStateParms Ledger::writeBack (LedgerStateParms parms, SLE::ref entry) +//------------------------------------------------------------------------------ + +bool +Ledger::exists (uint256 const& key) const { - bool create = false; - - if (!mAccountStateMap->hasItem (entry->getIndex ())) - { - if ((parms & lepCREATE) == 0) - { - WriteLog (lsERROR, Ledger) - << "WriteBack non-existent node without create"; - return lepMISSING; - } - - create = true; - } - - auto item = std::make_shared (entry->getIndex ()); - entry->add (item->peekSerializer()); - - if (create) - { - assert (!mAccountStateMap->hasItem (entry->getIndex ())); - - if (!mAccountStateMap->addGiveItem (item, false, false)) - { - assert (false); - return lepERROR; - } - - return lepCREATED; - } - - if (!mAccountStateMap->updateGiveItem (item, false, false)) - { - assert (false); - return lepERROR; - } - - return lepOKAY; + return mAccountStateMap->hasItem(key); } -SLE::pointer Ledger::getSLE (uint256 const& uHash) const +std::shared_ptr +Ledger::find (uint256 const& key) const { - std::shared_ptr node = mAccountStateMap->peekItem (uHash); - - if (!node) - return SLE::pointer (); - - return std::make_shared (node->peekSerializer (), node->getTag ()); + return mAccountStateMap->peekItem(key); } +void +Ledger::insert (SLE const& sle) +{ + assert(! mAccountStateMap->hasItem(sle.getIndex())); + auto item = std::make_shared( + sle.getIndex()); + sle.add(item->peekSerializer()); + auto const success = + mAccountStateMap->addGiveItem( + item, false, false); + (void)success; + assert(success); +} + +boost::optional +Ledger::fetch (uint256 const& key, + boost::optional type) const +{ + auto const item = + mAccountStateMap->peekItem(key); + if (! item) + return boost::none; + boost::optional result; + result.emplace(item->peekSerializer(), + item->getTag()); + if (type && result->getType() != type) + return {}; + return result; +} + +void +Ledger::replace (SLE const& sle) +{ + assert(mAccountStateMap->hasItem(sle.getIndex())); + auto item = std::make_shared( + sle.getIndex()); + sle.add(item->peekSerializer()); + auto const success = + mAccountStateMap->updateGiveItem( + item, false, false); + (void)success; + assert(success); +} + +void +Ledger::erase (uint256 const& key) +{ + assert(mAccountStateMap->hasItem(key)); + mAccountStateMap->delItem(key); +} + +//------------------------------------------------------------------------------ + SLE::pointer Ledger::getSLEi (uint256 const& uId) const { uint256 hash; @@ -1090,7 +1046,7 @@ SLE::pointer Ledger::getSLEi (uint256 const& uId) const if (!ret) { - ret = std::make_shared (node->peekSerializer (), node->getTag ()); + ret = std::make_shared (node->peekSerializer (), node->key()); ret->setImmutable (); getApp().getSLECache ().canonicalize (hash, ret); } @@ -1098,122 +1054,10 @@ SLE::pointer Ledger::getSLEi (uint256 const& uId) const return ret; } -void Ledger::visitAccountItems ( - Account const& accountID, std::function func) const -{ - // Visit each item in this account's owner directory - uint256 rootIndex = getOwnerDirIndex (accountID); - uint256 currentIndex = rootIndex; - - while (1) - { - SLE::pointer ownerDir = getSLEi (currentIndex); - - if (!ownerDir || (ownerDir->getType () != ltDIR_NODE)) - return; - - for (auto const& node : ownerDir->getFieldV256 (sfIndexes)) - { - func (getSLEi (node)); - } - - std::uint64_t uNodeNext = ownerDir->getFieldU64 (sfIndexNext); - - if (!uNodeNext) - return; - - currentIndex = getDirNodeIndex (rootIndex, uNodeNext); - } - -} - -bool Ledger::visitAccountItems ( - Account const& accountID, - uint256 const& startAfter, - std::uint64_t const hint, - unsigned int limit, - std::function func) const -{ - // Visit each item in this account's owner directory - uint256 const rootIndex (getOwnerDirIndex (accountID)); - uint256 currentIndex (rootIndex); - - // If startAfter is not zero try jumping to that page using the hint - if (startAfter.isNonZero ()) - { - uint256 const hintIndex (getDirNodeIndex (rootIndex, hint)); - SLE::pointer hintDir (getSLEi (hintIndex)); - if (hintDir != nullptr) - { - for (auto const& node : hintDir->getFieldV256 (sfIndexes)) - { - if (node == startAfter) - { - // We found the hint, we can start here - currentIndex = hintIndex; - break; - } - } - } - - bool found (false); - for (;;) - { - SLE::pointer ownerDir (getSLEi (currentIndex)); - - if (! ownerDir || ownerDir->getType () != ltDIR_NODE) - return found; - - for (auto const& node : ownerDir->getFieldV256 (sfIndexes)) - { - if (!found) - { - if (node == startAfter) - found = true; - } - else if (func (getSLEi (node)) && limit-- <= 1) - { - return found; - } - } - - std::uint64_t const uNodeNext (ownerDir->getFieldU64 (sfIndexNext)); - - if (uNodeNext == 0) - return found; - - currentIndex = getDirNodeIndex (rootIndex, uNodeNext); - } - } - else - { - for (;;) - { - SLE::pointer ownerDir (getSLEi (currentIndex)); - - if (! ownerDir || ownerDir->getType () != ltDIR_NODE) - return true; - - for (auto const& node : ownerDir->getFieldV256 (sfIndexes)) - { - if (func (getSLEi (node)) && limit-- <= 1) - return true; - } - - std::uint64_t const uNodeNext (ownerDir->getFieldU64 (sfIndexNext)); - - if (uNodeNext == 0) - return true; - - currentIndex = getDirNodeIndex (rootIndex, uNodeNext); - } - } -} - static void visitHelper ( std::function& function, std::shared_ptr const& item) { - function (std::make_shared (item->peekSerializer(), item->getTag ())); + function (std::make_shared (item->peekSerializer(), item->key())); } void Ledger::visitStateItems (std::function function) const @@ -1232,245 +1076,20 @@ void Ledger::visitStateItems (std::function function) const if (mHash.isNonZero ()) { getApp().getInboundLedgers().acquire( - mHash, mLedgerSeq, InboundLedger::fcGENERIC); + mHash, seq_, InboundLedger::fcGENERIC); } throw; } } -uint256 Ledger::getFirstLedgerIndex () const +uint256 Ledger::getNextLedgerIndex (uint256 const& hash, + boost::optional const& last) const { - std::shared_ptr node = mAccountStateMap->peekFirstItem (); - return node ? node->getTag () : uint256 (); -} - -uint256 Ledger::getLastLedgerIndex () const -{ - std::shared_ptr node = mAccountStateMap->peekLastItem (); - return node ? node->getTag () : uint256 (); -} - -uint256 Ledger::getNextLedgerIndex (uint256 const& uHash) const -{ - std::shared_ptr node = mAccountStateMap->peekNextItem (uHash); - return node ? node->getTag () : uint256 (); -} - -uint256 Ledger::getNextLedgerIndex (uint256 const& uHash, uint256 const& uEnd) const -{ - std::shared_ptr node = mAccountStateMap->peekNextItem (uHash); - - if ((!node) || (node->getTag () > uEnd)) - return uint256 (); - - return node->getTag (); -} - -uint256 Ledger::getPrevLedgerIndex (uint256 const& uHash) const -{ - std::shared_ptr node = mAccountStateMap->peekPrevItem (uHash); - return node ? node->getTag () : uint256 (); -} - -uint256 Ledger::getPrevLedgerIndex (uint256 const& uHash, uint256 const& uBegin) const -{ - std::shared_ptr node = mAccountStateMap->peekNextItem (uHash); - - if ((!node) || (node->getTag () < uBegin)) - return uint256 (); - - return node->getTag (); -} - -SLE::pointer Ledger::getASNodeI (uint256 const& nodeID, LedgerEntryType let) const -{ - SLE::pointer node = getSLEi (nodeID); - - if (node && (node->getType () != let)) - node.reset (); - - return node; -} - -SLE::pointer Ledger::getASNode ( - LedgerStateParms& parms, uint256 const& nodeID, LedgerEntryType let) const -{ - std::shared_ptr account = mAccountStateMap->peekItem (nodeID); - - if (!account) - { - if ( (parms & lepCREATE) == 0 ) - { - parms = lepMISSING; - - return SLE::pointer (); - } - - parms = parms | lepCREATED | lepOKAY; - SLE::pointer sle = std::make_shared (let, nodeID); - - return sle; - } - - SLE::pointer sle = - std::make_shared (account->peekSerializer (), nodeID); - - if (sle->getType () != let) - { - // maybe it's a currency or something - parms = parms | lepWRONGTYPE; - return SLE::pointer (); - } - - parms = parms | lepOKAY; - - return sle; -} - -SLE::pointer Ledger::getAccountRoot (Account const& accountID) const -{ - return getASNodeI (getAccountRootIndex (accountID), ltACCOUNT_ROOT); -} - -SLE::pointer Ledger::getAccountRoot (RippleAddress const& naAccountID) const -{ - return getASNodeI (getAccountRootIndex ( - naAccountID.getAccountID ()), ltACCOUNT_ROOT); -} - -SLE::pointer Ledger::getDirNode (uint256 const& uNodeIndex) const -{ - return getASNodeI (uNodeIndex, ltDIR_NODE); -} - -SLE::pointer -Ledger::getOffer (uint256 const& uIndex) const -{ - return getASNodeI (uIndex, ltOFFER); -} - -SLE::pointer -Ledger::getOffer (Account const& account, std::uint32_t uSequence) const -{ - return getOffer (getOfferIndex (account, uSequence)); -} - -SLE::pointer -Ledger::getRippleState (uint256 const& uNode) const -{ - return getASNodeI (uNode, ltRIPPLE_STATE); -} - -SLE::pointer -Ledger::getRippleState ( - Account const& a, Account const& b, Currency const& currency) const -{ - return getRippleState (getRippleStateIndex (a, b, currency)); -} - -uint256 Ledger::getLedgerHash (std::uint32_t ledgerIndex) -{ - // Return the hash of the specified ledger, 0 if not available - - // Easy cases... - if (ledgerIndex > mLedgerSeq) - { - WriteLog (lsWARNING, Ledger) << "Can't get seq " << ledgerIndex - << " from " << mLedgerSeq << " future"; - return uint256 (); - } - - if (ledgerIndex == mLedgerSeq) - return getHash (); - - if (ledgerIndex == (mLedgerSeq - 1)) - return mParentHash; - - // Within 256... - int diff = mLedgerSeq - ledgerIndex; - - if (diff <= 256) - { - auto hashIndex = getSLEi (getLedgerHashIndex ()); - - if (hashIndex) - { - assert (hashIndex->getFieldU32 (sfLastLedgerSequence) == - (mLedgerSeq - 1)); - STVector256 vec = hashIndex->getFieldV256 (sfHashes); - - if (vec.size () >= diff) - return vec[vec.size () - diff]; - - WriteLog (lsWARNING, Ledger) - << "Ledger " << mLedgerSeq - << " missing hash for " << ledgerIndex - << " (" << vec.size () << "," << diff << ")"; - } - else - { - WriteLog (lsWARNING, Ledger) - << "Ledger " << mLedgerSeq - << ":" << getHash () << " missing normal list"; - } - } - - if ((ledgerIndex & 0xff) != 0) - { - WriteLog (lsDEBUG, Ledger) << "Can't get seq " << ledgerIndex - << " from " << mLedgerSeq << " past"; - return uint256 (); - } - - // in skiplist - auto hashIndex = getSLEi (getLedgerHashIndex (ledgerIndex)); - - if (hashIndex) - { - int lastSeq = hashIndex->getFieldU32 (sfLastLedgerSequence); - assert (lastSeq >= ledgerIndex); - assert ((lastSeq & 0xff) == 0); - int sDiff = (lastSeq - ledgerIndex) >> 8; - - STVector256 vec = hashIndex->getFieldV256 (sfHashes); - - if (vec.size () > sDiff) - return vec[vec.size () - sDiff - 1]; - } - - WriteLog (lsWARNING, Ledger) << "Can't get seq " << ledgerIndex - << " from " << mLedgerSeq << " error"; - return uint256 (); -} - -Ledger::LedgerHashes Ledger::getLedgerHashes () const -{ - LedgerHashes ret; - SLE::pointer hashIndex = getSLEi (getLedgerHashIndex ()); - - if (hashIndex) - { - STVector256 vec = hashIndex->getFieldV256 (sfHashes); - int size = vec.size (); - ret.reserve (size); - auto seq = hashIndex->getFieldU32 (sfLastLedgerSequence) - size; - - for (int i = 0; i < size; ++i) - ret.push_back (std::make_pair (++seq, vec[i])); - } - - return ret; -} - -std::vector Ledger::getLedgerAmendments () const -{ - std::vector amendments; - SLE::pointer sleAmendments = getSLEi (getLedgerAmendmentIndex ()); - - if (sleAmendments) - amendments = static_cast (sleAmendments->getFieldV256 (sfAmendments)); - - return amendments; + auto const node = + mAccountStateMap->peekNextItem(hash); + if ((! node) || (last && node->key() >= *last)) + return {}; + return node->key(); } bool Ledger::walkLedger () const @@ -1519,7 +1138,7 @@ bool Ledger::walkLedger () const return missingNodes1.empty () && missingNodes2.empty (); } -bool Ledger::assertSane () const +bool Ledger::assertSane () { if (mHash.isNonZero () && mAccountHash.isNonZero () && @@ -1544,62 +1163,70 @@ bool Ledger::assertSane () const } // update the skip list with the information from our previous ledger +// VFALCO TODO Document this skip list concept void Ledger::updateSkipList () { - if (mLedgerSeq == 0) // genesis ledger has no previous ledger + if (seq_ == 0) // genesis ledger has no previous ledger return; - std::uint32_t prevIndex = mLedgerSeq - 1; + std::uint32_t prevIndex = seq_ - 1; // update record of every 256th ledger if ((prevIndex & 0xff) == 0) { - uint256 hash = getLedgerHashIndex (prevIndex); - SLE::pointer skipList = getSLE (hash); + auto const key = getLedgerHashIndex(prevIndex); + auto sle = fetch(key, ltLEDGER_HASHES); std::vector hashes; - // VFALCO TODO Document this skip list concept - if (!skipList) - skipList = std::make_shared (ltLEDGER_HASHES, hash); + bool created; + if (! sle) + { + sle.emplace(ltLEDGER_HASHES, key); + created = true; + } else - hashes = static_cast (skipList->getFieldV256 (sfHashes)); + { + hashes = static_cast( + sle->getFieldV256(sfHashes)); + created = false; + } assert (hashes.size () <= 256); hashes.push_back (mParentHash); - skipList->setFieldV256 (sfHashes, STVector256 (hashes)); - skipList->setFieldU32 (sfLastLedgerSequence, prevIndex); - - if (writeBack (lepCREATE, skipList) == lepERROR) - { - assert (false); - } + sle->setFieldV256 (sfHashes, STVector256 (hashes)); + sle->setFieldU32 (sfLastLedgerSequence, prevIndex); + if (created) + insert(*sle); + else + replace(*sle); } // update record of past 256 ledger - uint256 hash = getLedgerHashIndex (); - - SLE::pointer skipList = getSLE (hash); - + auto const key = getLedgerHashIndex(); + auto sle = fetch(key, ltLEDGER_HASHES); std::vector hashes; - - if (!skipList) - skipList = std::make_shared (ltLEDGER_HASHES, hash); + bool created; + if (! sle) + { + sle.emplace(ltLEDGER_HASHES, key); + created = true; + } else - hashes = static_cast(skipList->getFieldV256 (sfHashes)); - + { + hashes = static_cast( + sle->getFieldV256 (sfHashes)); + created = false; + } assert (hashes.size () <= 256); - if (hashes.size () == 256) hashes.erase (hashes.begin ()); - hashes.push_back (mParentHash); - skipList->setFieldV256 (sfHashes, STVector256 (hashes)); - skipList->setFieldU32 (sfLastLedgerSequence, prevIndex); - - if (writeBack (lepCREATE, skipList) == lepERROR) - { - assert (false); - } + sle->setFieldV256 (sfHashes, STVector256 (hashes)); + sle->setFieldU32 (sfLastLedgerSequence, prevIndex); + if (created) + insert(*sle); + else + replace(*sle); } /** Save, or arrange to save, a fully-validated ledger @@ -1675,9 +1302,9 @@ void Ledger::deprecatedUpdateCachedFees() const std::uint32_t reserveBase = getConfig ().FEE_ACCOUNT_RESERVE; std::int64_t reserveIncrement = getConfig ().FEE_OWNER_RESERVE; - LedgerStateParms p = lepNONE; - auto sle = getASNode (p, getLedgerFeeIndex (), ltFEE_SETTINGS); - + // VFALCO NOTE this doesn't go through the SLECache + auto const sle = this->fetch( + getLedgerFeeIndex(), ltFEE_SETTINGS); if (sle) { if (sle->getFieldIndex (sfBaseFee) != -1) @@ -1739,4 +1366,225 @@ std::vector Ledger::getNeededAccountStateHashes ( return ret; } +//------------------------------------------------------------------------------ +// +// API +// +//------------------------------------------------------------------------------ + +std::shared_ptr +fetch (Ledger const& ledger, uint256 const& key, + SLECache& cache, boost::optional type) +{ + uint256 hash; + auto const item = + ledger.peekAccountStateMap()->peekItem(key, hash); + if (! item) + return {}; + if (auto const sle = cache.fetch(hash)) + { + if (type && sle->getType() != type) + return {}; + return sle; + } + SerialIter sit(make_Slice(item->peekData())); + auto sle = std::make_shared(sit, item->key()); + // VFALCO Should we still cache it if the type doesn't match? + if (type && sle->getType() != type) + return {}; + sle->setImmutable (); + cache.canonicalize(hash, sle); + return sle; +} + +void +forEachItem (Ledger const& ledger, Account const& id, SLECache& cache, + std::function const&)> f) +{ + auto rootIndex = getOwnerDirIndex (id); + auto currentIndex = rootIndex; + for(;;) + { + auto ownerDir = fetch( + ledger, currentIndex, cache, ltDIR_NODE); + if (! ownerDir) + return; + for (auto const& key : ownerDir->getFieldV256 (sfIndexes)) + f(fetch(ledger, key, cache)); + auto uNodeNext = + ownerDir->getFieldU64 (sfIndexNext); + if (! uNodeNext) + return; + currentIndex = getDirNodeIndex (rootIndex, uNodeNext); + } +} + +bool +forEachItemAfter (Ledger const& ledger, Account const& id, SLECache& cache, + uint256 const& after, std::uint64_t const hint, unsigned int limit, + std::function const&)> f) +{ + auto const rootIndex = getOwnerDirIndex(id); + auto currentIndex = rootIndex; + + // If startAfter is not zero try jumping to that page using the hint + if (after.isNonZero ()) + { + auto const hintIndex = getDirNodeIndex (rootIndex, hint); + auto hintDir = fetch(ledger, hintIndex, cache); + if (hintDir) + { + for (auto const& key : hintDir->getFieldV256 (sfIndexes)) + { + if (key == after) + { + // We found the hint, we can start here + currentIndex = hintIndex; + break; + } + } + } + + bool found = false; + for (;;) + { + auto const ownerDir = fetch(ledger, currentIndex, cache); + if (! ownerDir || ownerDir->getType () != ltDIR_NODE) + return found; + for (auto const& key : ownerDir->getFieldV256 (sfIndexes)) + { + if (! found) + { + if (key == after) + found = true; + } + else if (f (fetch (ledger, key, cache)) && limit-- <= 1) + { + return found; + } + } + + auto const uNodeNext = + ownerDir->getFieldU64(sfIndexNext); + if (uNodeNext == 0) + return found; + currentIndex = getDirNodeIndex (rootIndex, uNodeNext); + } + } + else + { + for (;;) + { + auto const ownerDir = fetch(ledger, currentIndex, cache); + if (! ownerDir || ownerDir->getType () != ltDIR_NODE) + return true; + for (auto const& key : ownerDir->getFieldV256 (sfIndexes)) + if (f (fetch(ledger, key, cache)) && limit-- <= 1) + return true; + auto const uNodeNext = + ownerDir->getFieldU64 (sfIndexNext); + if (uNodeNext == 0) + return true; + currentIndex = getDirNodeIndex (rootIndex, uNodeNext); + } + } +} + +AccountState::pointer +getAccountState (Ledger const& ledger, + RippleAddress const& accountID, + SLECache& cache) +{ + auto const sle = fetch (ledger, + getAccountRootIndex(accountID.getAccountID()), + cache); + if (!sle) + { + // VFALCO Do we really need to log here? + WriteLog (lsDEBUG, Ledger) << "Ledger:getAccountState:" << + " not found: " << accountID.humanAccountID () << + ": " << to_string (getAccountRootIndex (accountID)); + + return {}; + } + + // VFALCO Does this ever really happen? + if (sle->getType () != ltACCOUNT_ROOT) + return {}; + + return std::make_shared(sle, accountID); +} + +boost::optional +hashOfSeq (Ledger& ledger, LedgerIndex seq, + SLECache& cache, beast::Journal journal) +{ + // Easy cases... + if (seq > ledger.seq()) + { + if (journal.warning) journal.warning << + "Can't get seq " << seq << + " from " << ledger.seq() << " future"; + return boost::none; + } + if (seq == ledger.seq()) + return ledger.getHash(); + if (seq == (ledger.seq() - 1)) + return ledger.getParentHash(); + + // Within 256... + { + int diff = ledger.seq() - seq; + if (diff <= 256) + { + auto const hashIndex = fetch( + ledger, getLedgerHashIndex(), cache); + if (hashIndex) + { + assert (hashIndex->getFieldU32 (sfLastLedgerSequence) == + (ledger.seq() - 1)); + STVector256 vec = hashIndex->getFieldV256 (sfHashes); + if (vec.size () >= diff) + return vec[vec.size () - diff]; + if (journal.warning) journal.warning << + "Ledger " << ledger.seq() << + " missing hash for " << seq << + " (" << vec.size () << "," << diff << ")"; + } + else + { + if (journal.warning) journal.warning << + "Ledger " << ledger.seq() << + ":" << ledger.getHash () << " missing normal list"; + } + } + if ((seq & 0xff) != 0) + { + if (journal.debug) journal.debug << + "Can't get seq " << seq << + " from " << ledger.seq() << " past"; + return boost::none; + } + } + + // in skiplist + auto const hashIndex = fetch(ledger, + getLedgerHashIndex(seq), cache); + if (hashIndex) + { + auto const lastSeq = + hashIndex->getFieldU32 (sfLastLedgerSequence); + assert (lastSeq >= seq); + assert ((lastSeq & 0xff) == 0); + auto const diff = (lastSeq - seq) >> 8; + STVector256 vec = hashIndex->getFieldV256 (sfHashes); + if (vec.size () > diff) + return vec[vec.size () - diff - 1]; + } + if (journal.warning) journal.warning << + "Can't get seq " << seq << + " from " << ledger.seq() << " error"; + return boost::none; +} + } // ripple diff --git a/src/ripple/app/ledger/Ledger.h b/src/ripple/app/ledger/Ledger.h index 70197fb477..51f222adbb 100644 --- a/src/ripple/app/ledger/Ledger.h +++ b/src/ripple/app/ledger/Ledger.h @@ -23,40 +23,34 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include namespace ripple { class Job; -enum LedgerStateParms -{ - lepNONE = 0, // no special flags - - // input flags - lepCREATE = 1, // Create if not present - - // output flags - lepOKAY = 2, // success - lepMISSING = 4, // No node in that slot - lepWRONGTYPE = 8, // Node of different type there - lepCREATED = 16, // Node was created - lepERROR = 32, // error -}; - class SqliteStatement; -// VFALCO TODO figure out exactly how this thing works. -// It seems like some ledger database is stored as a global, static in -// the class. But then what is the meaning of a Ledger object? Is this -// really two classes in one? StoreOfAllLedgers + SingleLedgerObject? -// -/** Holds some or all of a ledger. +/** Holds a ledger. + + The ledger is composed of two SHAMaps. The state map holds all of the + ledger entries such as account roots and order books. The tx map holds + all of the transactions and associated metadata that made it into that + particular ledger. Most of the operations on a ledger are concerned + with the state map. + + A View provides a structured interface to manipulate the state map in + a reversible way, with facilities to automatically produce metadata + when applying changes. + This can hold just the header, a partial set of data, or the entire set of data. It all depends on what is in the corresponding SHAMap entry. Various functions are provided to populate or depopulate the caches that @@ -82,42 +76,12 @@ public: using pointer = std::shared_ptr; using ref = const std::shared_ptr&; - enum TransResult - { - TR_ERROR = -1, - TR_SUCCESS = 0, - TR_NOTFOUND = 1, - TR_ALREADY = 2, - - // the transaction itself is corrupt - TR_BADTRANS = 3, - - // one of the accounts is invalid - TR_BADACCT = 4, - - // the sending(apply)/receiving(remove) account is broke - TR_INSUFF = 5, - - // account is past this transaction - TR_PASTASEQ = 6, - - // account is missing transactions before this - TR_PREASEQ = 7, - - // ledger too early - TR_BADLSEQ = 8, - - // amount is less than Tx fee - TR_TOOSMALL = 9, - }; - - // ledger close flags - static const std::uint32_t sLCF_NoConsensusTime = 1; - -public: + Ledger (Ledger const&) = delete; + Ledger& operator= (Ledger const&) = delete; // used for the starting bootstrap ledger - Ledger (const RippleAddress & masterID, std::uint64_t startAmount); + Ledger (RippleAddress const& masterID, + std::uint64_t startAmount); // Used for ledgers loaded from JSON files Ledger (uint256 const& parentHash, uint256 const& transHash, @@ -125,106 +89,196 @@ public: std::uint64_t totCoins, std::uint32_t closeTime, std::uint32_t parentCloseTime, int closeFlags, int closeResolution, std::uint32_t ledgerSeq, bool & loaded); - // used for database ledgers + // used for database ledgers Ledger (std::uint32_t ledgerSeq, std::uint32_t closeTime); + Ledger (void const* data, std::size_t size, bool hasPrefix); - Ledger (bool dummy, Ledger & previous); // ledger after this one - Ledger (Ledger & target, bool isMutable); // snapshot - Ledger (Ledger const&) = delete; - Ledger& operator= (Ledger const&) = delete; + // Create a new ledger that follows this one + // VFALCO `previous` should be const + Ledger (bool dummy, Ledger& previous); - ~Ledger (); + // Create a new ledger that's a snapshot of this one + Ledger (Ledger const& target, bool isMutable); - static Ledger::pointer getLastFullLedger (); + ~Ledger(); + + //-------------------------------------------------------------------------- + + /** Returns `true` if a ledger entry exists. */ + bool + exists (uint256 const& key) const; + + /** Return the state item for a key. + The item may not be modified. + @return The serialized ledger entry or empty + if the key does not exist. + */ + std::shared_ptr + find (uint256 const& key) const; + + /** Add a new state SLE. + Effects: + assert if the key already exists. + The key in the state map is associated + with an unflattened copy of the SLE. + @note The key is taken from the SLE. + */ + void + insert (SLE const& sle); + + /** Fetch a modifiable state SLE. + Effects: + Gives the caller ownership of an + unflattened copy of the SLE. + @param type An optional LedgerEntryType. If type is + engaged and the SLE's type does not match, + then boost::none is returned. + @return `empty` if the key is not present + */ + boost::optional + fetch (uint256 const& key, boost::optional< + LedgerEntryType> type = boost::none) const; + + // DEPRECATED + // Retrieve immutable ledger entry + SLE::pointer getSLEi (uint256 const& uHash) const; + + /** Replace an existing state SLE. + Effects: + assert if key does not already exist. + The previous flattened SLE associated with + the key is released. + The key in the state map is associated + with a flattened copy of the SLE. + @note The key is taken from the SLE + */ + void + replace (SLE const& sle); + + /** Remove an state SLE. + Effects: + assert if the key does not exist. + The flattened SLE associated with the key + is released from the state map. + */ + void + erase (uint256 const& key); + + //-------------------------------------------------------------------------- - void updateHash (); void setClosed () { mClosed = true; } + void setValidated() { mValidated = true; } - void setAccepted ( - std::uint32_t closeTime, int closeResolution, bool correctCloseTime); + + void setAccepted (std::uint32_t closeTime, + int closeResolution, bool correctCloseTime); void setAccepted (); + void setImmutable (); + bool isClosed () const { return mClosed; } + bool isAccepted () const { return mAccepted; } + bool isValidated () const { return mValidated; } + bool isImmutable () const { return mImmutable; } - bool isFixed () const - { - return mClosed || mImmutable; - } + void setFull () { - mTransactionMap->setLedgerSeq (mLedgerSeq); - mAccountStateMap->setLedgerSeq (mLedgerSeq); + mTransactionMap->setLedgerSeq (seq_); + mAccountStateMap->setLedgerSeq (seq_); } // ledger signature operations void addRaw (Serializer& s) const; void setRaw (SerialIter& sit, bool hasPrefix); - uint256 const& getHash (); + /** Return the hash of the ledger. + This will recalculate the hash if necessary. + */ + uint256 const& + getHash(); + uint256 const& getParentHash () const { return mParentHash; } + uint256 const& getTransHash () const { return mTransHash; } + uint256 const& getAccountHash () const { return mAccountHash; } + std::uint64_t getTotalCoins () const { return mTotCoins; } + void destroyCoins (std::uint64_t fee) { mTotCoins -= fee; } + void setTotalCoins (std::uint64_t totCoins) { mTotCoins = totCoins; } + std::uint32_t getCloseTimeNC () const { return mCloseTime; } + std::uint32_t getParentCloseTimeNC () const { return mParentCloseTime; } + + LedgerIndex + seq() const + { + return seq_; + } + + // DEPRECATED std::uint32_t getLedgerSeq () const { - return mLedgerSeq; + return seq_; } + int getCloseResolution () const { return mCloseResolution; } + bool getCloseAgree () const { return (mCloseFlags & sLCF_NoConsensusTime) == 0; @@ -236,7 +290,9 @@ public: assert (!mImmutable); mCloseTime = ct; } + void setCloseTime (boost::posix_time::ptime); + boost::posix_time::ptime getCloseTime () const; // low level functions @@ -244,6 +300,7 @@ public: { return mTransactionMap; } + std::shared_ptr const& peekAccountStateMap () const { return mAccountStateMap; @@ -260,104 +317,55 @@ public: // Transaction Functions bool addTransaction (uint256 const& id, Serializer const& txn); + bool addTransaction ( uint256 const& id, Serializer const& txn, Serializer const& metaData); + bool hasTransaction (uint256 const& TransID) const { return mTransactionMap->hasItem (TransID); } + Transaction::pointer getTransaction (uint256 const& transID) const; + bool getTransaction ( uint256 const& transID, Transaction::pointer & txn, TransactionMetaSet::pointer & txMeta) const; + bool getTransactionMeta ( uint256 const& transID, TransactionMetaSet::pointer & txMeta) const; + bool getMetaHex (uint256 const& transID, std::string & hex) const; static STTx::pointer getSTransaction ( std::shared_ptr const&, SHAMapTreeNode::TNType); + STTx::pointer getSMTransaction ( std::shared_ptr const&, SHAMapTreeNode::TNType, TransactionMetaSet::pointer & txMeta) const; - // high-level functions - bool hasAccount (const RippleAddress & acctID) const; - AccountState::pointer getAccountState (const RippleAddress & acctID) const; - LedgerStateParms writeBack (LedgerStateParms parms, SLE::ref); - SLE::pointer getAccountRoot (Account const& accountID) const; - SLE::pointer getAccountRoot (const RippleAddress & naAccountID) const; void updateSkipList (); - void visitAccountItems ( - Account const& accountID, std::function) const; - bool visitAccountItems ( - Account const& accountID, - uint256 const& startAfter, // Entry to start after - std::uint64_t const hint, // Hint which page to start at - unsigned int limit, - std::function ) const; void visitStateItems (std::function) const; - // database functions (low-level) - static Ledger::pointer loadByIndex (std::uint32_t ledgerIndex); - static Ledger::pointer loadByHash (uint256 const& ledgerHash); - static uint256 getHashByIndex (std::uint32_t index); - static bool getHashesByIndex ( - std::uint32_t index, uint256 & ledgerHash, uint256 & parentHash); - static std::map< std::uint32_t, std::pair > - getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq); bool pendSaveValidated (bool isSynchronous, bool isCurrent); - // next/prev function - SLE::pointer getSLE (uint256 const& uHash) const; // SLE is mutable - SLE::pointer getSLEi (uint256 const& uHash) const; // SLE is immutable - - // VFALCO NOTE These seem to let you walk the list of ledgers - // - uint256 getFirstLedgerIndex () const; - uint256 getLastLedgerIndex () const; - - // first node >hash - uint256 getNextLedgerIndex (uint256 const& uHash) const; - - // first node >hash, begin - uint256 getPrevLedgerIndex (uint256 const& uHash, uint256 const& uBegin) const; - - // Ledger hash table function - uint256 getLedgerHash (std::uint32_t ledgerIndex); - using LedgerHashes = std::vector>; - LedgerHashes getLedgerHashes () const; - - std::vector getLedgerAmendments () const; + // first node >hash, const& last = boost::none) const; std::vector getNeededTransactionHashes ( int max, SHAMapSyncFilter* filter) const; + std::vector getNeededAccountStateHashes ( int max, SHAMapSyncFilter* filter) const; - // - // Offer functions - // - - SLE::pointer getOffer (uint256 const& uIndex) const; - SLE::pointer getOffer (Account const& account, std::uint32_t uSequence) const; - - // // Directory functions // Directories are doubly linked lists of nodes. // Given a directory root and and index compute the index of a node. static void ownerDirDescriber (SLE::ref, bool, Account const& owner); - // Return a node: root or normal - SLE::pointer getDirNode (uint256 const& uNodeIndex) const; - // // Quality // @@ -368,17 +376,6 @@ public: Currency const& uTakerGetsCurrency, Account const& uTakerGetsIssuer, const std::uint64_t & uRate); - // - // Ripple functions : credit lines - // - - SLE::pointer - getRippleState (uint256 const& uNode) const; - - SLE::pointer - getRippleState ( - Account const& a, Account const& b, Currency const& currency) const; - std::uint32_t getReferenceFeeUnits() const { // Returns the cost of the reference transaction in fee units @@ -407,23 +404,24 @@ public: return mReserveIncrement; } - /** Const version of getHash() which gets the current value without calling - updateHash(). */ - uint256 const& getRawHash () const - { - return mHash; - } - bool walkLedger () const; - bool assertSane () const; + + bool assertSane (); + + // database functions (low-level) + static Ledger::pointer loadByIndex (std::uint32_t ledgerIndex); + + static Ledger::pointer loadByHash (uint256 const& ledgerHash); + + static uint256 getHashByIndex (std::uint32_t index); + + static bool getHashesByIndex ( + std::uint32_t index, uint256 & ledgerHash, uint256 & parentHash); + + static std::map< std::uint32_t, std::pair > + getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq); protected: - SLE::pointer getASNode ( - LedgerStateParms& parms, uint256 const& nodeID, LedgerEntryType let) const; - - // returned SLE is immutable - SLE::pointer getASNodeI (uint256 const& nodeID, LedgerEntryType let) const; - void saveValidatedLedgerAsync(Job&, bool current) { saveValidatedLedger(current); @@ -431,6 +429,12 @@ protected: bool saveValidatedLedger (bool current); private: + // ledger close flags + static const std::uint32_t sLCF_NoConsensusTime = 1; + + void + updateHash(); + // Updates the fees cached in the ledger. // Safe to call concurrently. We shouldn't be storing // fees in the Ledger object, they should be a local side-structure @@ -439,12 +443,12 @@ private: void deprecatedUpdateCachedFees() const; // The basic Ledger structure, can be opened, closed, or synching - uint256 mHash; // VFALCO This could be boost::optional - uint256 mParentHash; - uint256 mTransHash; - uint256 mAccountHash; + uint256 mHash; // VFALCO This could be boost::optional + uint256 mParentHash; + uint256 mTransHash; + uint256 mAccountHash; std::uint64_t mTotCoins; - std::uint32_t mLedgerSeq; + std::uint32_t seq_; // when this ledger closed std::uint32_t mCloseTime; @@ -481,19 +485,65 @@ private: std::uint32_t mutable mReserveIncrement = 0; }; -inline LedgerStateParms operator| ( - const LedgerStateParms& l1, const LedgerStateParms& l2) -{ - return static_cast ( - static_cast (l1) | static_cast (l2)); -} +//------------------------------------------------------------------------------ +// +// API +// +//------------------------------------------------------------------------------ -inline LedgerStateParms operator& ( - const LedgerStateParms& l1, const LedgerStateParms& l2) -{ - return static_cast ( - static_cast (l1) & static_cast (l2)); -} +std::tuple +loadLedgerHelper(std::string const& sqlSuffix); + +/** SLE cache-aware deserialized state SLE fetch. + Effects: + If the key exists, the item is flattened + and added to the SLE cache. + The returned object may not be modified. + @param type An optional LedgerEntryType. If type is + engaged and the SLE's type does not match, + an empty shared_ptr is returned. + @return `empty` if the key is not present +*/ +std::shared_ptr +fetch (Ledger const& ledger, uint256 const& key, SLECache& cache, + boost::optional type = boost::none); + +/** Iterate all items in an account's owner directory. */ +void +forEachItem (Ledger const& ledger, Account const& id, SLECache& cache, + std::function const&)> f); + +/** Iterate all items after an item in an owner directory. + @param after The key of the item to start after + @param hint The directory page containing `after` + @param limit The maximum number of items to return + @return `false` if the iteration failed +*/ +bool +forEachItemAfter (Ledger const& ledger, Account const& id, SLECache& cache, + uint256 const& after, std::uint64_t const hint, unsigned int limit, + std::function const&)>); + +// DEPRECATED +// VFALCO This could return by value +// This should take AccountID parameter +AccountState::pointer +getAccountState (Ledger const& ledger, + RippleAddress const& accountID, + SLECache& cache); + +/** Return the hash of a ledger by sequence. + The hash is retrieved by looking up the "skip list" + in the passed ledger. As the skip list is limited + in size, if the requested ledger sequence number is + out of the range of ledgers represented in the skip + list, then boost::none is returned. + @return The hash of the ledger with the + given sequence number or boost::none. +*/ +boost::optional +hashOfSeq (Ledger& ledger, LedgerIndex seq, + SLECache& cache, beast::Journal journal); } // ripple diff --git a/src/ripple/app/ledger/LedgerEntrySet.cpp b/src/ripple/app/ledger/LedgerEntrySet.cpp index 3bb148da93..b595fd71fd 100644 --- a/src/ripple/app/ledger/LedgerEntrySet.cpp +++ b/src/ripple/app/ledger/LedgerEntrySet.cpp @@ -103,29 +103,53 @@ SLE::pointer LedgerEntrySet::entryCreate (LedgerEntryType letType, uint256 const return sleNew; } -SLE::pointer LedgerEntrySet::entryCache (LedgerEntryType letType, uint256 const& index) +SLE::pointer LedgerEntrySet::entryCache (LedgerEntryType letType, uint256 const& key) { assert (mLedger); - SLE::pointer sleEntry; + SLE::pointer sle; - if (index.isNonZero ()) + // VFALCO Shouldn't be calling this with invalid keys, + // but apparently its happening. Need to track it down. + //assert(key.isNonZero ()); + + if (key.isNonZero ()) { LedgerEntryAction action; - sleEntry = getEntry (index, action); + sle = getEntry (key, action); - if (!sleEntry) + if (! sle) { assert (action != taaDELETE); - sleEntry = mImmutable ? mLedger->getSLEi (index) : mLedger->getSLE (index); + if (mImmutable) + { + // VFALCO NOTE We'd like all immutable callers to go through + // entryCacheI, then we can avoid calling getSLEi. + sle = mLedger->getSLEi(key); + } + else + { + auto maybe_sle = mLedger->fetch(key, letType); + if (maybe_sle) + sle = std::make_shared( + std::move(*maybe_sle)); + } - if (sleEntry) - entryCache (sleEntry); + if (sle) + entryCache (sle); } else if (action == taaDELETE) - sleEntry.reset (); + { + sle = nullptr; + } } - return sleEntry; + return sle; +} + +std::shared_ptr +LedgerEntrySet::entryCacheI (LedgerEntryType letType, uint256 const& key) +{ + return entryCache(letType, key); } void LedgerEntrySet::entryCache (SLE::ref sle) @@ -370,12 +394,16 @@ SLE::pointer LedgerEntrySet::getForMod (uint256 const& node, Ledger::ref ledger, return me->second; } - SLE::pointer ret = ledger->getSLE (node); + auto sle = ledger->fetch(node); + if (sle) + { + auto p = std::make_shared( + std::move(*sle)); + newMods.insert (std::make_pair (node, p)); + return p; + } - if (ret) - newMods.insert (std::make_pair (node, ret)); - - return ret; + return {}; } bool LedgerEntrySet::threadTx (RippleAddress const& threadTo, Ledger::ref ledger, @@ -418,8 +446,9 @@ bool LedgerEntrySet::threadTx (SLE::ref threadTo, Ledger::ref ledger, return false; } -bool LedgerEntrySet::threadOwners (SLE::ref node, Ledger::ref ledger, - NodeToLedgerEntry& newMods) +bool LedgerEntrySet::threadOwners( + std::shared_ptr const& node, + Ledger::ref ledger, NodeToLedgerEntry& newMods) { // thread new or modified node to owner or owners if (node->hasOneOwner ()) // thread to owner's account @@ -483,7 +512,8 @@ void LedgerEntrySet::calcRawMeta (Serializer& s, TER result, std::uint32_t index if (type == &sfGeneric) continue; - SLE::pointer origNode = mLedger->getSLEi (it.first); + std::shared_ptr const origNode = + mLedger->getSLEi(it.first); SLE::pointer curNode = it.second.mEntry; if ((type == &sfModifiedNode) && (*curNode == *origNode)) @@ -929,6 +959,22 @@ bool LedgerEntrySet::dirFirst ( return LedgerEntrySet::dirNext (uRootIndex, sleNode, uDirEntry, uEntryIndex); } +// Return the first entry and advance uDirEntry. +// <-- true, if had a next entry. +bool LedgerEntrySet::dirFirst ( + uint256 const& uRootIndex, // --> Root of directory. + std::shared_ptr& sleNode, // <-- current node + unsigned int& uDirEntry, // <-- next entry + uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. +{ + sleNode = entryCacheI (ltDIR_NODE, uRootIndex); + uDirEntry = 0; + + assert (sleNode); // Never probe for directories. + + return LedgerEntrySet::dirNext (uRootIndex, sleNode, uDirEntry, uEntryIndex); +} + // Return the current entry and advance uDirEntry. // <-- true, if had a next entry. bool LedgerEntrySet::dirNext ( @@ -979,6 +1025,57 @@ bool LedgerEntrySet::dirNext ( return true; } +// Return the current entry and advance uDirEntry. +// <-- true, if had a next entry. +bool LedgerEntrySet::dirNext ( + uint256 const& uRootIndex, // --> Root of directory + std::shared_ptr& sleNode, // <-> current node + unsigned int& uDirEntry, // <-> next entry + uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. +{ + STVector256 const svIndexes = sleNode->getFieldV256 (sfIndexes); + + assert (uDirEntry <= svIndexes.size ()); + + if (uDirEntry >= svIndexes.size ()) + { + std::uint64_t const uNodeNext = sleNode->getFieldU64 (sfIndexNext); + + if (!uNodeNext) + { + uEntryIndex.zero (); + + return false; + } + else + { + auto const sleNext = entryCacheI( + ltDIR_NODE, getDirNodeIndex (uRootIndex, uNodeNext)); + uDirEntry = 0; + + if (!sleNext) + { // This should never happen + WriteLog (lsFATAL, LedgerEntrySet) + << "Corrupt directory: index:" + << uRootIndex << " next:" << uNodeNext; + return false; + } + + sleNode = sleNext; + // TODO(tom): make this iterative. + return dirNext (uRootIndex, sleNode, uDirEntry, uEntryIndex); + } + } + + uEntryIndex = svIndexes[uDirEntry++]; + + WriteLog (lsTRACE, LedgerEntrySet) << "dirNext:" << + " uDirEntry=" << uDirEntry << + " uEntryIndex=" << uEntryIndex; + + return true; +} + uint256 LedgerEntrySet::getNextLedgerIndex (uint256 const& uHash) { // find next node in ledger that isn't deleted by LES diff --git a/src/ripple/app/ledger/LedgerEntrySet.h b/src/ripple/app/ledger/LedgerEntrySet.h index 887ec0e260..1b2c500532 100644 --- a/src/ripple/app/ledger/LedgerEntrySet.h +++ b/src/ripple/app/ledger/LedgerEntrySet.h @@ -155,7 +155,10 @@ public: // higher-level ledger functions SLE::pointer entryCreate (LedgerEntryType letType, uint256 const& uIndex); - SLE::pointer entryCache (LedgerEntryType letType, uint256 const& uIndex); + SLE::pointer entryCache (LedgerEntryType letType, uint256 const& key); + + std::shared_ptr + entryCacheI (LedgerEntryType letType, uint256 const& uIndex); // Directory functions. TER dirAdd ( @@ -174,9 +177,16 @@ public: bool dirFirst (uint256 const& uRootIndex, SLE::pointer& sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex); + bool dirFirst (uint256 const& uRootIndex, std::shared_ptr& sleNode, + unsigned int & uDirEntry, uint256 & uEntryIndex); + bool dirNext (uint256 const& uRootIndex, SLE::pointer& sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex); + bool dirNext (uint256 const& uRootIndex, std::shared_ptr& sleNode, + unsigned int & uDirEntry, uint256 & uEntryIndex); + bool dirIsEmpty (uint256 const& uDirIndex); + TER dirCount (uint256 const& uDirIndex, std::uint32_t & uCount); uint256 getNextLedgerIndex (uint256 const& uHash); @@ -322,8 +332,8 @@ private: bool threadTx ( SLE::ref threadTo, Ledger::ref ledger, NodeToLedgerEntry& newMods); - bool threadOwners ( - SLE::ref node, Ledger::ref ledger, NodeToLedgerEntry& newMods); + bool threadOwners (std::shared_ptr const& node, + Ledger::ref ledger, NodeToLedgerEntry& newMods); TER rippleSend ( Account const& uSenderID, Account const& uReceiverID, diff --git a/src/ripple/app/ledger/LedgerToJson.h b/src/ripple/app/ledger/LedgerToJson.h index 5184611557..6770a0ea15 100644 --- a/src/ripple/app/ledger/LedgerToJson.h +++ b/src/ripple/app/ledger/LedgerToJson.h @@ -33,7 +33,7 @@ namespace ripple { struct LedgerFill { - LedgerFill (Ledger const& l, + LedgerFill (Ledger& l, int o = 0, RPC::Yield const& y = {}, RPC::YieldStrategy const& ys = {}) @@ -47,7 +47,7 @@ struct LedgerFill enum Options { dumpTxrp = 1, dumpState = 2, expand = 4, full = 8, binary = 16}; - Ledger const& ledger; + Ledger& ledger; int options; RPC::Yield yield; RPC::YieldStrategy yieldStrategy; @@ -75,7 +75,7 @@ void fillJson (Object& json, LedgerFill const& fill) { using namespace ripple::RPC; - auto const& ledger = fill.ledger; + auto& ledger = fill.ledger; bool const bFull (fill.options & LedgerFill::full); bool const bExpand (fill.options & LedgerFill::expand); @@ -92,11 +92,11 @@ void fillJson (Object& json, LedgerFill const& fill) json[jss::closed] = true; // DEPRECATED - json[jss::hash] = to_string (ledger.getRawHash()); + json[jss::hash] = to_string (ledger.getHash()); // DEPRECATED json[jss::totalCoins] = to_string (ledger.getTotalCoins()); - json[jss::ledger_hash] = to_string (ledger.getRawHash()); + json[jss::ledger_hash] = to_string (ledger.getHash()); json[jss::transaction_hash] = to_string (ledger.getTransHash()); json[jss::account_hash] = to_string (ledger.getAccountHash()); json[jss::accepted] = ledger.isAccepted(); diff --git a/src/ripple/app/ledger/SLECache.h b/src/ripple/app/ledger/SLECache.h new file mode 100644 index 0000000000..ead0e955ff --- /dev/null +++ b/src/ripple/app/ledger/SLECache.h @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012-2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_APP_SLECACHE_H_INCLUDED +#define RIPPLE_APP_SLECACHE_H_INCLUDED + +#include +#include + +namespace ripple { + +/** STLedgerEntry cache. + This maps keys to the deserialized ledger entries, + to improve performance where the same item in + the ledger is accessed often. +*/ +using SLECache = TaggedCache ; + +} + +#endif diff --git a/src/ripple/app/ledger/impl/LedgerCleaner.cpp b/src/ripple/app/ledger/impl/LedgerCleaner.cpp index c3df8bd9bf..0c3b9dbc5c 100644 --- a/src/ripple/app/ledger/impl/LedgerCleaner.cpp +++ b/src/ripple/app/ledger/impl/LedgerCleaner.cpp @@ -248,12 +248,14 @@ public: stopped(); } + // VFALCO TODO This should return boost::optional LedgerHash getLedgerHash(Ledger::pointer ledger, LedgerIndex index) { - LedgerHash hash; + boost::optional hash; try { - hash = ledger->getLedgerHash(index); + hash = hashOfSeq(*ledger, index, + getApp().getSLECache(), m_journal); } catch (SHAMapMissingNode &) { @@ -262,7 +264,7 @@ public: getApp().getInboundLedgers().acquire ( ledger->getHash(), ledger->getLedgerSeq(), InboundLedger::fcGENERIC); } - return hash; + return hash ? *hash : zero; // kludge } /** Process a single ledger diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/ripple/app/ledger/impl/LedgerMaster.cpp index 3f6ebc1e58..84cbbb5928 100644 --- a/src/ripple/app/ledger/impl/LedgerMaster.cpp +++ b/src/ripple/app/ledger/impl/LedgerMaster.cpp @@ -635,14 +635,16 @@ public: void fixMismatch (Ledger::ref ledger) { int invalidate = 0; - uint256 hash; + boost::optional hash; for (std::uint32_t lSeq = ledger->getLedgerSeq () - 1; lSeq > 0; --lSeq) + { if (haveLedger (lSeq)) { try { - hash = ledger->getLedgerHash (lSeq); + hash = hashOfSeq(*ledger, lSeq, + getApp().getSLECache(), m_journal); } catch (...) { @@ -652,12 +654,12 @@ public: return; } - if (hash.isNonZero ()) + if (hash) { // try to close the seam Ledger::pointer otherLedger = getLedgerBySeq (lSeq); - if (otherLedger && (otherLedger->getHash () == hash)) + if (otherLedger && (otherLedger->getHash () == *hash)) { // we closed the seam CondLog (invalidate != 0, lsWARNING, LedgerMaster) << @@ -670,6 +672,7 @@ public: clearLedger (lSeq); ++invalidate; } + } // all prior ledgers invalidated CondLog (invalidate != 0, lsWARNING, LedgerMaster) << "All " << @@ -963,24 +966,24 @@ public: WriteLog (lsTRACE, LedgerMaster) << "advanceThread>"; } + // VFALCO NOTE This should return boost::optional LedgerHash getLedgerHashForHistory (LedgerIndex index) { // Try to get the hash of a ledger we need to fetch for history - uint256 ret; + boost::optional ret; if (mHistLedger && (mHistLedger->getLedgerSeq() >= index)) { - ret = mHistLedger->getLedgerHash (index); - if (ret.isZero()) + ret = hashOfSeq(*mHistLedger, index, + getApp().getSLECache(), m_journal); + if (! ret) ret = walkHashBySeq (index, mHistLedger); - } - - if (ret.isZero ()) - { - ret = walkHashBySeq (index); } - return ret; + if (! ret) + ret = walkHashBySeq (index); + + return *ret; } // Try to publish ledgers, acquire missing ledgers @@ -1160,31 +1163,35 @@ public: WriteLog (lsTRACE, LedgerMaster) << "Trying to fetch/publish valid ledger " << seq; Ledger::pointer ledger; - uint256 hash = valLedger->getLedgerHash (seq); // This can throw - + // This can throw + auto hash = hashOfSeq(*valLedger, seq, + getApp().getSLECache(), m_journal); + // VFALCO TODO Restructure this code so that zero is not used + if (! hash) + hash = zero; // kludge if (seq == valSeq) - { // We need to publish the ledger we just fully validated + { + // We need to publish the ledger we just fully validated ledger = valLedger; } + else if (hash->isZero()) + { + WriteLog (lsFATAL, LedgerMaster) << "Ledger: " << valSeq << " does not have hash for " << seq; + assert (false); + } else { - if (hash.isZero ()) - { - WriteLog (lsFATAL, LedgerMaster) << "Ledger: " << valSeq << " does not have hash for " << seq; - assert (false); - } - - ledger = mLedgerHistory.getLedgerByHash (hash); + ledger = mLedgerHistory.getLedgerByHash (*hash); } + // Can we try to acquire the ledger we need? if (! ledger && (++acqCount < 4)) - { // We can try to acquire the ledger we need - ledger = - getApp().getInboundLedgers ().acquire (hash, seq, InboundLedger::fcGENERIC); - } + ledger = getApp().getInboundLedgers ().acquire( + *hash, seq, InboundLedger::fcGENERIC); + // Did we acquire the next ledger we need to publish? if (ledger && (ledger->getLedgerSeq() == pubSeq)) - { // We acquired the next ledger we need to publish + { ledger->setValidated(); ret.push_back (ledger); ++pubSeq; @@ -1217,33 +1224,41 @@ public: } // Return the hash of the valid ledger with a particular sequence, given a subsequent ledger known valid + // VFALCO NOTE This should return boost::optional uint256 getLedgerHash(std::uint32_t desiredSeq, Ledger::ref knownGoodLedger) { assert(desiredSeq < knownGoodLedger->getLedgerSeq()); - uint256 hash = knownGoodLedger->getLedgerHash(desiredSeq); + auto hash = hashOfSeq(*knownGoodLedger, desiredSeq, + getApp().getSLECache(), m_journal); // Not directly in the given ledger - if (hash.isZero ()) + if (! hash) { std::uint32_t seq = (desiredSeq + 255) % 256; assert(seq < desiredSeq); - uint256 i = knownGoodLedger->getLedgerHash(seq); - if (i.isNonZero()) + hash = hashOfSeq(*knownGoodLedger, + seq, getApp().getSLECache(), m_journal); + if (hash) { - Ledger::pointer l = getLedgerByHash(i); + auto l = getLedgerByHash(*hash); if (l) { - hash = l->getLedgerHash(desiredSeq); - assert (hash.isNonZero()); + hash = hashOfSeq(*l, desiredSeq, + getApp().getSLECache(), m_journal); + assert (hash); } } else + { assert(false); + } } - return hash; + // VFALCO NOTE This shouldn't be needed, but + // preserves original behavior. + return hash ? *hash : zero; // kludge } void updatePaths (Job& job) @@ -1401,6 +1416,7 @@ public: return Ledger::getHashByIndex (index); } + // VFALCO NOTE This should return boost::optional uint256 walkHashBySeq (std::uint32_t index) { uint256 ledgerHash; @@ -1419,37 +1435,41 @@ public: from the reference ledger or any prior ledger are not present in the node store. */ + // VFALCO NOTE This should return boost::optional uint256 walkHashBySeq (std::uint32_t index, Ledger::ref referenceLedger) { - uint256 ledgerHash; if (!referenceLedger || (referenceLedger->getLedgerSeq() < index)) - return ledgerHash; // Nothing we can do. No validated ledger. + { + // Nothing we can do. No validated ledger. + return zero; + } // See if the hash for the ledger we need is in the reference ledger - ledgerHash = referenceLedger->getLedgerHash (index); - if (ledgerHash.isZero()) - { - // No, Try to get another ledger that might have the hash we need - // Compute the index and hash of a ledger that will have the hash we need - LedgerIndex refIndex = (index + 255) & (~255); - LedgerHash refHash = referenceLedger->getLedgerHash (refIndex); + auto ledgerHash = hashOfSeq(*referenceLedger, index, + getApp().getSLECache(), m_journal); + if (ledgerHash) + return *ledgerHash; - bool const nonzero (refHash.isNonZero ()); - assert (nonzero); - if (nonzero) + // No, Try to get another ledger that might have the hash we need + // Compute the index and hash of a ledger that will have the hash we need + LedgerIndex refIndex = (index + 255) & (~255); + auto const refHash = hashOfSeq(*referenceLedger, refIndex, + getApp().getSLECache(), m_journal); + assert(refHash); + if (refHash) + { + // We found the hash and sequence of a better reference ledger + auto const ledger = + getApp().getInboundLedgers().acquire ( + *refHash, refIndex, InboundLedger::fcGENERIC); + if (ledger) { - // We found the hash and sequence of a better reference ledger - Ledger::pointer ledger = - getApp().getInboundLedgers().acquire ( - refHash, refIndex, InboundLedger::fcGENERIC); - if (ledger) - { - ledgerHash = ledger->getLedgerHash (index); - assert (ledgerHash.isNonZero()); - } + ledgerHash = hashOfSeq(*ledger, index, + getApp().getSLECache(), m_journal); + assert (ledgerHash); } } - return ledgerHash; + return ledgerHash ? *ledgerHash : zero; // kludge } Ledger::pointer getLedgerBySeq (std::uint32_t index) @@ -1465,9 +1485,10 @@ public: try { - uint256 const& hash = valid->getLedgerHash (index); - if (hash.isNonZero()) - return mLedgerHistory.getLedgerByHash (hash); + auto const hash = hashOfSeq(*valid, index, + getApp().getSLECache(), m_journal); + if (hash) + return mLedgerHistory.getLedgerByHash (*hash); } catch (...) { diff --git a/src/ripple/app/ledger/tests/common_ledger.cpp b/src/ripple/app/ledger/tests/common_ledger.cpp index 6a30b80cfd..b3d2cec4ea 100644 --- a/src/ripple/app/ledger/tests/common_ledger.cpp +++ b/src/ripple/app/ledger/tests/common_ledger.cpp @@ -18,10 +18,10 @@ //============================================================================== #include -#include - -#include +#include #include +#include +#include #include #include @@ -143,7 +143,7 @@ createGenesisLedger(std::uint64_t start_amount_drops, TestAccount const& master) initializePathfinding(); Ledger::pointer ledger = std::make_shared(master.pk, start_amount_drops); - ledger->updateHash(); + ledger->getHash(); // updates the hash ledger->setClosed(); if (!ledger->assertSane()) throw std::runtime_error( @@ -488,10 +488,10 @@ Json::Value findPath(Ledger::pointer ledger, TestAccount const& src, return result.second; } -SLE::pointer +std::shared_ptr getLedgerEntryRippleState(Ledger::pointer ledger, TestAccount const& account1, TestAccount const& account2, - Currency currency) + Currency currency) { auto uNodeIndex = getRippleStateIndex( account1.pk.getAccountID(), account2.pk.getAccountID(), @@ -501,14 +501,15 @@ getLedgerEntryRippleState(Ledger::pointer ledger, throw std::runtime_error( "!uNodeIndex.isNonZero()"); - return ledger->getSLEi(uNodeIndex); + return fetch(*ledger, uNodeIndex, + getApp().getSLECache()); } void verifyBalance(Ledger::pointer ledger, TestAccount const& account, Amount const& amount) { - auto sle = getLedgerEntryRippleState(ledger, account, + auto const sle = getLedgerEntryRippleState(ledger, account, amount.getIssuer(), amount.getCurrency()); if (!sle) throw std::runtime_error( diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 5066bfeb05..3f8b181202 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -1041,6 +1043,7 @@ public: private: void updateTables (); void startNewLedger (); + Ledger::pointer getLastFullLedger(); bool loadOldLedger ( std::string const& ledgerID, bool replay, bool isFilename); @@ -1062,10 +1065,10 @@ void ApplicationImp::startNewLedger () { Ledger::pointer firstLedger = std::make_shared (rootAddress, SYSTEM_CURRENCY_START); - assert (firstLedger->getAccountState (rootAddress)); + assert (firstLedger->exists(getAccountRootIndex(rootAddress.getAccountID()))); // TODO(david): Add any default amendments // TODO(david): Set default fee/reserve - firstLedger->updateHash (); + firstLedger->getHash(); // updates the hash firstLedger->setClosed (); firstLedger->setAccepted (); m_ledgerMaster->pushLedger (firstLedger); @@ -1074,11 +1077,58 @@ void ApplicationImp::startNewLedger () secondLedger->setClosed (); secondLedger->setAccepted (); m_ledgerMaster->pushLedger (secondLedger, std::make_shared (true, std::ref (*secondLedger))); - assert (secondLedger->getAccountState (rootAddress)); + assert (secondLedger->exists(getAccountRootIndex(rootAddress.getAccountID()))); m_networkOPs->setLastCloseTime (secondLedger->getCloseTimeNC ()); } } +Ledger::pointer +ApplicationImp::getLastFullLedger() +{ + try + { + Ledger::pointer ledger; + std::uint32_t ledgerSeq; + uint256 ledgerHash; + std::tie (ledger, ledgerSeq, ledgerHash) = + loadLedgerHelper ("order by LedgerSeq desc limit 1"); + + if (!ledger) + return ledger; + + ledger->setClosed (); + + if (getApp().getOPs ().haveLedger (ledgerSeq)) + { + ledger->setAccepted (); + ledger->setValidated (); + } + + if (ledger->getHash () != ledgerHash) + { + if (ShouldLog (lsERROR, Ledger)) + { + WriteLog (lsERROR, Ledger) << "Failed on ledger"; + Json::Value p; + addJson (p, {*ledger, LedgerFill::full}); + WriteLog (lsERROR, Ledger) << p; + } + + assert (false); + return Ledger::pointer (); + } + + WriteLog (lsTRACE, Ledger) << "Loaded ledger: " << ledgerHash; + return ledger; + } + catch (SHAMapMissingNode& sn) + { + WriteLog (lsWARNING, Ledger) + << "Database contains ledger with missing nodes: " << sn; + return Ledger::pointer (); + } +} + bool ApplicationImp::loadOldLedger ( std::string const& ledgerID, bool replay, bool isFileName) { @@ -1185,7 +1235,9 @@ bool ApplicationImp::loadOldLedger ( } } else if (ledgerID.empty () || (ledgerID == "latest")) - loadLedger = Ledger::getLastFullLedger (); + { + loadLedger = getLastFullLedger (); + } else if (ledgerID.length () == 64) { // by hash diff --git a/src/ripple/app/main/Application.h b/src/ripple/app/main/Application.h index 58f9cf9ea1..62b48700c8 100644 --- a/src/ripple/app/main/Application.h +++ b/src/ripple/app/main/Application.h @@ -23,10 +23,11 @@ #include #include #include +#include #include #include // #include - + namespace boost { namespace asio { class io_service; } } namespace ripple { @@ -65,7 +66,6 @@ class DatabaseCon; class SHAMapStore; using NodeCache = TaggedCache ; -using SLECache = TaggedCache ; class Application : public beast::PropertyStream::Source { diff --git a/src/ripple/app/misc/AccountState.cpp b/src/ripple/app/misc/AccountState.cpp index 67c5714dfc..471643a7e5 100644 --- a/src/ripple/app/misc/AccountState.cpp +++ b/src/ripple/app/misc/AccountState.cpp @@ -29,25 +29,11 @@ namespace ripple { -AccountState::AccountState (RippleAddress const& naAccountID) - : mAccountID (naAccountID) - , mValid (false) +AccountState::AccountState (std::shared_ptr sle, + RippleAddress const& naAccountID) + : mLedgerEntry (sle) { - if (naAccountID.isValid ()) - { - mValid = true; - - mLedgerEntry = std::make_shared ( - ltACCOUNT_ROOT, getAccountRootIndex (naAccountID)); - - mLedgerEntry->setFieldAccount (sfAccount, naAccountID.getAccountID ()); - } -} - -AccountState::AccountState (SLE::ref ledgerEntry, RippleAddress const& naAccountID) : - mAccountID (naAccountID), mLedgerEntry (ledgerEntry), mValid (false) -{ - if (!mLedgerEntry) + if (! mLedgerEntry) return; if (mLedgerEntry->getType () != ltACCOUNT_ROOT) @@ -84,11 +70,4 @@ void AccountState::addJson (Json::Value& val) } } -void AccountState::dump () -{ - Json::Value j (Json::objectValue); - addJson (j); - WriteLog (lsINFO, Ledger) << j; -} - } // ripple diff --git a/src/ripple/app/misc/AccountState.h b/src/ripple/app/misc/AccountState.h index 6583d757f4..d9d321cf4f 100644 --- a/src/ripple/app/misc/AccountState.h +++ b/src/ripple/app/misc/AccountState.h @@ -28,70 +28,35 @@ namespace ripple { // -// Provide abstract access to an account's state, such that access to the serialized format is hidden. +// Provide abstract access to an account's state, such that +// access to the serialized format is hidden. // +// VFALCO TODO Remove this class, its redundant and hardly used class AccountState { public: + // VFALCO TODO Figure out if we need this to be shared using pointer = std::shared_ptr; -public: - // For new accounts - explicit AccountState (RippleAddress const& naAccountID); - // For accounts in a ledger - AccountState (SLE::ref ledgerEntry, RippleAddress const& naAccountI); + AccountState (std::shared_ptr sle, + RippleAddress const& naAccountI); - bool haveAuthorizedKey () - { - return mLedgerEntry->isFieldPresent (sfRegularKey); - } - - RippleAddress getAuthorizedKey () - { - return mLedgerEntry->getFieldAccount (sfRegularKey); - } - - STAmount getBalance () const - { - return mLedgerEntry->getFieldAmount (sfBalance); - } - - std::uint32_t getSeq () const - { - return mLedgerEntry->getFieldU32 (sfSequence); - } - - STLedgerEntry::pointer getSLE () - { - return mLedgerEntry; - } - - STLedgerEntry const& peekSLE () const + SLE const& + sle() const { return *mLedgerEntry; } - STLedgerEntry& peekSLE () - { - return *mLedgerEntry; - } - - Blob getRaw () const; - void addJson (Json::Value& value); - void dump (); - +private: + // VFALCO TODO Remove this static std::string createGravatarUrl (uint128 uEmailHash); -private: - RippleAddress const mAccountID; - RippleAddress mAuthorizedKey; - STLedgerEntry::pointer mLedgerEntry; - - bool mValid; + bool mValid = false; + std::shared_ptr mLedgerEntry; }; } // ripple diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp index daf444686e..8a0c5f47df 100644 --- a/src/ripple/app/misc/NetworkOPs.cpp +++ b/src/ripple/app/misc/NetworkOPs.cpp @@ -245,13 +245,6 @@ public: std::uint32_t startLedgerSeq, std::uint32_t endLedgerSeq, int maxTransactions) override; - // - // Account functions. - // - - AccountState::pointer getAccountState ( - Ledger::ref lrLedger, RippleAddress const& accountID) override; - // // Directory functions. // @@ -1082,16 +1075,6 @@ int NetworkOPsImp::findTransactionsByDestination ( return 0; } -// -// Account functions -// - -AccountState::pointer NetworkOPsImp::getAccountState ( - Ledger::ref lrLedger, RippleAddress const& accountID) -{ - return lrLedger->getAccountState (accountID); -} - // // Directory functions // @@ -1104,7 +1087,8 @@ STVector256 NetworkOPsImp::getDirNodeInfo ( std::uint64_t& uNodeNext) { STVector256 svIndexes; - SLE::pointer sleNode = lrLedger->getDirNode (uNodeIndex); + auto const sleNode = fetch(*lrLedger, uNodeIndex, + getApp().getSLECache(), ltDIR_NODE); if (sleNode) { @@ -1149,8 +1133,8 @@ Json::Value NetworkOPsImp::getOwnerInfo ( { Json::Value jvObjects (Json::objectValue); auto uRootIndex = getOwnerDirIndex (naAccount.getAccountID ()); - auto sleNode = lpLedger->getDirNode (uRootIndex); - + auto sleNode = fetch(*lpLedger, uRootIndex, + getApp().getSLECache(), ltDIR_NODE); if (sleNode) { std::uint64_t uNodeDir; @@ -1159,7 +1143,8 @@ Json::Value NetworkOPsImp::getOwnerInfo ( { for (auto const& uDirEntry : sleNode->getFieldV256 (sfIndexes)) { - auto sleCur = lpLedger->getSLEi (uDirEntry); + auto sleCur = fetch(*lpLedger, uDirEntry, + getApp().getSLECache()); switch (sleCur->getType ()) { @@ -1192,8 +1177,9 @@ Json::Value NetworkOPsImp::getOwnerInfo ( if (uNodeDir) { - sleNode = lpLedger->getDirNode ( - getDirNodeIndex (uRootIndex, uNodeDir)); + sleNode = fetch(*lpLedger, getDirNodeIndex( + uRootIndex, uNodeDir), getApp().getSLECache(), + ltDIR_NODE); assert (sleNode); } } diff --git a/src/ripple/app/misc/NetworkOPs.h b/src/ripple/app/misc/NetworkOPs.h index fc6f0ce979..134b79e375 100644 --- a/src/ripple/app/misc/NetworkOPs.h +++ b/src/ripple/app/misc/NetworkOPs.h @@ -168,14 +168,6 @@ public: RippleAddress const& destinationAccount, std::uint32_t startLedgerSeq, std::uint32_t endLedgerSeq, int maxTransactions) = 0; - //-------------------------------------------------------------------------- - // - // Account functions - // - - virtual AccountState::pointer getAccountState (Ledger::ref lrLedger, - RippleAddress const& accountID) = 0; - //-------------------------------------------------------------------------- // // Directory functions diff --git a/src/ripple/app/paths/PathRequest.cpp b/src/ripple/app/paths/PathRequest.cpp index d6e7054653..933a05feb3 100644 --- a/src/ripple/app/paths/PathRequest.cpp +++ b/src/ripple/app/paths/PathRequest.cpp @@ -149,8 +149,9 @@ bool PathRequest::isValid (RippleLineCache::ref crCache) if (bValid) { - auto asSrc = getApp().getOPs ().getAccountState ( - crCache->getLedger(), raSrcAccount); + auto asSrc = getAccountState( + *crCache->getLedger(), raSrcAccount, + getApp().getSLECache()); if (!asSrc) { @@ -160,8 +161,8 @@ bool PathRequest::isValid (RippleLineCache::ref crCache) } else { - auto asDst = getApp().getOPs ().getAccountState ( - lrLedger, raDstAccount); + auto asDst = getAccountState(*lrLedger, + raDstAccount, getApp().getSLECache()); Json::Value& jvDestCur = (jvStatus[jss::destination_currencies] = Json::arrayValue); @@ -187,7 +188,7 @@ bool PathRequest::isValid (RippleLineCache::ref crCache) else { bool const disallowXRP ( - asDst->peekSLE ().getFlags() & lsfDisallowXRP); + asDst->sle().getFlags() & lsfDisallowXRP); auto usDestCurrID = accountDestCurrencies ( raDstAccount, crCache, !disallowXRP); @@ -196,7 +197,7 @@ bool PathRequest::isValid (RippleLineCache::ref crCache) jvDestCur.append (to_string (currency)); jvStatus["destination_tag"] = - (asDst->peekSLE ().getFlags () & lsfRequireDestTag) + (asDst->sle().getFlags () & lsfRequireDestTag) != 0; } } diff --git a/src/ripple/app/paths/Pathfinder.cpp b/src/ripple/app/paths/Pathfinder.cpp index 081e85832a..d06acc6e80 100644 --- a/src/ripple/app/paths/Pathfinder.cpp +++ b/src/ripple/app/paths/Pathfinder.cpp @@ -271,7 +271,7 @@ bool Pathfinder::findPaths (int searchLevel) bool bSrcXrp = isXRP (mSrcCurrency); bool bDstXrp = isXRP (mDstAmount.getCurrency()); - if (!mLedger->getSLEi (getAccountRootIndex (mSrcAccount))) + if (! mLedger->exists (getAccountRootIndex (mSrcAccount))) { // We can't even start without a source account. WriteLog (lsDEBUG, Pathfinder) << "invalid source account"; @@ -279,14 +279,14 @@ bool Pathfinder::findPaths (int searchLevel) } if ((mEffectiveDst != mDstAccount) && - ! mLedger->getSLEi (getAccountRootIndex (mEffectiveDst))) + ! mLedger->exists (getAccountRootIndex (mEffectiveDst))) { WriteLog (lsDEBUG, Pathfinder) << "Non-existent gateway"; return false; } - if (!mLedger->getSLEi (getAccountRootIndex (mDstAccount))) + if (! mLedger->exists (getAccountRootIndex (mDstAccount))) { // Can't find the destination account - we must be funding a new // account. @@ -703,7 +703,8 @@ int Pathfinder::getPathsOut ( if (!it.second) return it.first->second; - auto sleAccount = mLedger->getSLEi (getAccountRootIndex (account)); + auto sleAccount = fetch(*mLedger, getAccountRootIndex (account), + getApp().getSLECache()); if (!sleAccount) return 0; @@ -839,8 +840,9 @@ bool Pathfinder::isNoRipple ( Account const& toAccount, Currency const& currency) { - auto sleRipple = mLedger->getSLEi ( - getRippleStateIndex (toAccount, fromAccount, currency)); + auto sleRipple = fetch (*mLedger, + getRippleStateIndex (toAccount, fromAccount, currency), + getApp().getSLECache()); auto const flag ((toAccount > fromAccount) ? lsfHighNoRipple : lsfLowNoRipple); @@ -918,7 +920,9 @@ void Pathfinder::addLink ( else { // search for accounts to add - auto sleEnd = mLedger->getSLEi(getAccountRootIndex (uEndAccount)); + auto const sleEnd = fetch( + *mLedger, getAccountRootIndex (uEndAccount), + getApp().getSLECache()); if (sleEnd) { diff --git a/src/ripple/app/paths/RippleState.cpp b/src/ripple/app/paths/RippleState.cpp index ce3dc7b7f3..f8eb588d15 100644 --- a/src/ripple/app/paths/RippleState.cpp +++ b/src/ripple/app/paths/RippleState.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include #include @@ -25,25 +26,27 @@ namespace ripple { -RippleState::pointer RippleState::makeItem ( - Account const& accountID, STLedgerEntry::ref ledgerEntry) +RippleState::pointer +RippleState::makeItem ( + Account const& accountID, + std::shared_ptr sle) { // VFALCO Does this ever happen in practice? - if (!ledgerEntry || ledgerEntry->getType () != ltRIPPLE_STATE) - return pointer (); - - return pointer (new RippleState (ledgerEntry, accountID)); + if (! sle || sle->getType () != ltRIPPLE_STATE) + return {}; + return std::make_shared( + std::move(sle), accountID); } RippleState::RippleState ( - STLedgerEntry::ref ledgerEntry, + std::shared_ptr&& sle, Account const& viewAccount) - : mLedgerEntry (ledgerEntry) - , mLowLimit (ledgerEntry->getFieldAmount (sfLowLimit)) - , mHighLimit (ledgerEntry->getFieldAmount (sfHighLimit)) + : mLedgerEntry (std::move(sle)) + , mLowLimit (mLedgerEntry->getFieldAmount (sfLowLimit)) + , mHighLimit (mLedgerEntry->getFieldAmount (sfHighLimit)) , mLowID (mLowLimit.getIssuer ()) , mHighID (mHighLimit.getIssuer ()) - , mBalance (ledgerEntry->getFieldAmount (sfBalance)) + , mBalance (mLedgerEntry->getFieldAmount (sfBalance)) { mFlags = mLedgerEntry->getFieldU32 (sfFlags); @@ -73,12 +76,11 @@ getRippleStateItems ( Ledger::ref ledger) { std::vector items; - - ledger->visitAccountItems (accountID, - [&items,&accountID](SLE::ref sleCur) + forEachItem(*ledger, accountID, getApp().getSLECache(), + [&items,&accountID]( + std::shared_ptr const&sleCur) { auto ret = RippleState::makeItem (accountID, sleCur); - if (ret) items.push_back (ret); }); diff --git a/src/ripple/app/paths/RippleState.h b/src/ripple/app/paths/RippleState.h index 6044be2d63..175ab301dc 100644 --- a/src/ripple/app/paths/RippleState.h +++ b/src/ripple/app/paths/RippleState.h @@ -22,34 +22,47 @@ #include #include +#include #include #include // namespace ripple { -// -// A ripple line's state. -// - Isolate ledger entry format. -// - +/** Wraps a trust line SLE for convenience. + The complication of trust lines is that there is a + "low" account and a "high" account. This wraps the + SLE and expresses its data from the perspective of + a chosen account on the line. +*/ +// VFALCO TODO Rename to TrustLine class RippleState { public: + // VFALCO Why is this shared_ptr? using pointer = std::shared_ptr ; public: - RippleState () = delete; + RippleState() = delete; - virtual ~RippleState () { } + virtual ~RippleState() = default; - static RippleState::pointer makeItem ( - Account const& accountID, STLedgerEntry::ref ledgerEntry); + static RippleState::pointer makeItem( + Account const& accountID, + std::shared_ptr sle); - LedgerEntryType getType () + // Must be public, for make_shared + RippleState (std::shared_ptr&& sle, + Account const& viewAccount); + + /** Returns the state map key for the ledger entry. */ + uint256 + key() const { - return ltRIPPLE_STATE; + return mLedgerEntry->getIndex(); } + // VFALCO Take off the "get" from each function name + Account const& getAccountID () const { return mViewLowest ? mLowID : mHighID; @@ -118,32 +131,10 @@ public: return ((std::uint32_t) (mViewLowest ? mLowQualityOut : mHighQualityOut)); } - STLedgerEntry::pointer getSLE () - { - return mLedgerEntry; - } - - const STLedgerEntry& peekSLE () const - { - return *mLedgerEntry; - } - - STLedgerEntry& peekSLE () - { - return *mLedgerEntry; - } - Json::Value getJson (int); - Blob getRaw () const; - private: - RippleState ( - STLedgerEntry::ref ledgerEntry, - Account const& viewAccount); - -private: - STLedgerEntry::pointer mLedgerEntry; + std::shared_ptr mLedgerEntry; bool mViewLowest; diff --git a/src/ripple/app/tests/Env.cpp b/src/ripple/app/tests/Env.cpp index ba28bb66f8..6bf9637532 100644 --- a/src/ripple/app/tests/Env.cpp +++ b/src/ripple/app/tests/Env.cpp @@ -45,10 +45,9 @@ AccountInfo::balance( return STAmount(issue, 0, 0); if (isXRP(issue)) return root_->getFieldAmount(sfBalance); - auto amount = ledger_->getRippleState( + auto amount = ledger_->fetch(getRippleStateIndex( account_, issue.account, - issue.currency)->getFieldAmount( - sfBalance); + issue.currency))->getFieldAmount(sfBalance); amount.setIssuer(issue.account); if (account_.id() > issue.account) amount.negate(); @@ -204,7 +203,7 @@ Env::autofill (JTx& jt) auto const account = lookup(jv[jss::Account].asString()); auto const ar = - ledger->getAccountRoot(account); + ledger->fetch(getAccountRootIndex(account)); if (ar->isFieldPresent(sfRegularKey)) jtx::sign(jv, lookup( ar->getFieldAccount160(sfRegularKey))); diff --git a/src/ripple/app/tests/Env.h b/src/ripple/app/tests/Env.h index 11bbe850cb..810c25c599 100644 --- a/src/ripple/app/tests/Env.h +++ b/src/ripple/app/tests/Env.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -45,15 +46,15 @@ class AccountInfo private: Account account_; std::shared_ptr ledger_; - std::shared_ptr root_; + boost::optional root_; public: AccountInfo(Account const& account, std::shared_ptr ledger) : account_(account) , ledger_(std::move(ledger)) - , root_(ledger_->getAccountRoot( - account.id())) + , root_(ledger_->fetch( + getAccountRootIndex(account.id()))) { } diff --git a/src/ripple/app/tests/JTx.cpp b/src/ripple/app/tests/JTx.cpp index a5d3c4d79a..1f89c2c463 100644 --- a/src/ripple/app/tests/JTx.cpp +++ b/src/ripple/app/tests/JTx.cpp @@ -170,8 +170,9 @@ fill_seq (Json::Value& jv, return; RippleAddress ra; ra.setAccountID(jv[jss::Account].asString()); - auto const ar = ledger.getAccountRoot( - ra.getAccountID()); + auto const ar = ledger.fetch( + getAccountRootIndex(ra.getAccountID())); + jv[jss::Sequence] = ar->getFieldU32(sfSequence); } diff --git a/src/ripple/app/tx/impl/LocalTxs.cpp b/src/ripple/app/tx/impl/LocalTxs.cpp index 4e690b738f..e17c96a719 100644 --- a/src/ripple/app/tx/impl/LocalTxs.cpp +++ b/src/ripple/app/tx/impl/LocalTxs.cpp @@ -20,6 +20,7 @@ #include #include #include +#include /* This code prevents scenarios like the following: @@ -120,21 +121,16 @@ public: bool can_remove (LocalTx& txn, Ledger::ref ledger) { - if (txn.isExpired (ledger->getLedgerSeq ())) return true; - if (ledger->hasTransaction (txn.getID ())) return true; - - SLE::pointer sle = ledger->getAccountRoot (txn.getAccount ()); - if (!sle) + auto const sle = ledger->fetch( + getAccountRootIndex(txn.getAccount())); + if (! sle) return false; - if (sle->getFieldU32 (sfSequence) > txn.getSeq ()) return true; - - return false; } diff --git a/src/ripple/app/tx/impl/TransactionEngine.cpp b/src/ripple/app/tx/impl/TransactionEngine.cpp index a170e65e6d..6bf40d6b95 100644 --- a/src/ripple/app/tx/impl/TransactionEngine.cpp +++ b/src/ripple/app/tx/impl/TransactionEngine.cpp @@ -36,6 +36,9 @@ void TransactionEngine::txnWrite () // Write back the account states for (auto& it : mNodes) { + // VFALCO TODO rvalue move the mEntry, make + // sure the mNodes is not used after + // this function is called. SLE::ref sleEntry = it.second.mEntry; switch (it.second.mAction) @@ -49,11 +52,10 @@ void TransactionEngine::txnWrite () case taaCREATE: { + // VFALCO Is this logging necessary anymore? WriteLog (lsDEBUG, TransactionEngine) << "applyTransaction: taaCREATE: " << sleEntry->getText (); - - if (mLedger->writeBack (lepCREATE, sleEntry) & lepERROR) - assert (false); + mLedger->insert(*sleEntry); } break; @@ -61,9 +63,7 @@ void TransactionEngine::txnWrite () { WriteLog (lsDEBUG, TransactionEngine) << "applyTransaction: taaMODIFY: " << sleEntry->getText (); - - if (mLedger->writeBack (lepNONE, sleEntry) & lepERROR) - assert (false); + mLedger->replace(*sleEntry); } break; @@ -71,9 +71,7 @@ void TransactionEngine::txnWrite () { WriteLog (lsDEBUG, TransactionEngine) << "applyTransaction: taaDELETE: " << sleEntry->getText (); - - if (!mLedger->peekAccountStateMap ()->delItem (it.first)) - assert (false); + mLedger->erase(it.first); } break; } diff --git a/src/ripple/app/tx/tests/MultiSign.test.cpp b/src/ripple/app/tx/tests/MultiSign.test.cpp index 700ca6f176..eb3c865517 100644 --- a/src/ripple/app/tx/tests/MultiSign.test.cpp +++ b/src/ripple/app/tx/tests/MultiSign.test.cpp @@ -1462,12 +1462,12 @@ class MultiSign_test : public beast::unit_test::suite } // Verify that alice has an offer. { - std::vector offers = + auto offers = getOffersOnAccount (ledger, alice); expect (offers.size() == 1); if (! offers.empty()) { - SLE::pointer const& offer = offers[0]; + auto const& offer = offers[0]; expect (takerGets == offer->getFieldAmount(sfTakerGets)); expect (takerPays == offer->getFieldAmount(sfTakerPays)); offerSeq = offer->getFieldU32 (sfSequence); @@ -1486,7 +1486,7 @@ class MultiSign_test : public beast::unit_test::suite } // Make sure alice's offer is really gone from the ledger. { - std::vector offers = + auto offers = getOffersOnAccount (ledger, alice); expect (offers.empty() == true); } @@ -1558,7 +1558,7 @@ class MultiSign_test : public beast::unit_test::suite } // Make sure Alice has the ticket. { - std::vector tickets = + auto getTicketsOnAccount (ledger, alice); expect (tickets.size() == 1); if (! tickets.empty()) @@ -1583,7 +1583,7 @@ class MultiSign_test : public beast::unit_test::suite } // Make sure the ticket is gone. { - std::vector tickets = + auto tickets = getTicketsOnAccount (ledger, alice); expect (tickets.size() == 0); } diff --git a/src/ripple/app/tx/tests/common_transactor.cpp b/src/ripple/app/tx/tests/common_transactor.cpp index a02de08d47..08828d9ae6 100644 --- a/src/ripple/app/tx/tests/common_transactor.cpp +++ b/src/ripple/app/tx/tests/common_transactor.cpp @@ -16,6 +16,7 @@ //============================================================================== #include +#include #include #include #include @@ -136,7 +137,9 @@ void TestLedger::applyTecTransaction (STTx const& tx, TER err, bool check) AccountState::pointer TestLedger::getAccountState (UserAccount const& acct) const { - return lastClosedLedger_->getAccountState (acct.acctPublicKey ()); + return ripple::getAccountState( + *lastClosedLedger_, acct.acctPublicKey(), + getApp().getSLECache()); } //------------------------------------------------------------------------------ @@ -362,12 +365,13 @@ void payInDrops (TestLedger& ledger, std::uint64_t getNativeBalance(TestLedger& ledger, UserAccount& acct) { - return ledger.getAccountState(acct)->getBalance().mantissa (); + return ledger.getAccountState(acct)->sle().getFieldAmount( + sfBalance).mantissa(); } std::uint32_t getOwnerCount(TestLedger& ledger, UserAccount& acct) { - return ledger.getAccountState(acct)->getSLE()->getFieldU32 (sfOwnerCount); + return ledger.getAccountState(acct)->sle().getFieldU32 (sfOwnerCount); } std::vector getRippleStates ( @@ -375,9 +379,9 @@ std::vector getRippleStates ( { std::vector states; - ledger.openLedger()->visitAccountItems ( - acct.getID(), - [&states, &acct, &peer](SLE::ref sleCur) + forEachItem(*ledger.openLedger(), acct.getID(), getApp().getSLECache(), + [&states, &acct, &peer]( + std::shared_ptr const& sleCur) { // See whether this SLE is a lt_RIPPLE_STATE if (!sleCur || sleCur->getType () != ltRIPPLE_STATE) @@ -394,14 +398,14 @@ std::vector getRippleStates ( return states; } -std::vector +std::vector > getOffersOnAccount (TestLedger& ledger, UserAccount const& acct) { - std::vector offers; + std::vector > offers; - ledger.openLedger()->visitAccountItems ( - acct.getID(), - [&offers, &acct](SLE::ref sleCur) + forEachItem(*ledger.openLedger(), acct.getID(), getApp().getSLECache(), + [&offers, &acct]( + std::shared_ptr const& sleCur) { // If sleCur is an ltOFFER save it. if (sleCur && sleCur->getType () == ltOFFER) @@ -410,14 +414,14 @@ getOffersOnAccount (TestLedger& ledger, UserAccount const& acct) return offers; } -std::vector +std::vector > getTicketsOnAccount (TestLedger& ledger, UserAccount const& acct) { - std::vector offers; + std::vector > offers; - ledger.openLedger()->visitAccountItems ( - acct.getID(), - [&offers, &acct](SLE::ref sleCur) + forEachItem(*ledger.openLedger(), acct.getID(), getApp().getSLECache(), + [&offers, &acct]( + std::shared_ptr const& sleCur) { // If sleCur is an ltTICKET save it. if (sleCur && sleCur->getType () == ltTICKET) diff --git a/src/ripple/app/tx/tests/common_transactor.h b/src/ripple/app/tx/tests/common_transactor.h index 3b4933e80d..6031c2e872 100644 --- a/src/ripple/app/tx/tests/common_transactor.h +++ b/src/ripple/app/tx/tests/common_transactor.h @@ -128,6 +128,8 @@ public: void applyTecTransaction (STTx const& tx, TER err, bool check = true); // Return the AccountState for a UserAccount + // VFALCO This function is not necessary, just expose + // the ledger data member and use the free function. AccountState::pointer getAccountState (UserAccount const& acct) const; // Return the current open ledger. @@ -347,11 +349,11 @@ std::vector getRippleStates ( TestLedger& ledger, UserAccount const& from, UserAccount const& peer); // Get all Offers on an account. -std::vector +std::vector > getOffersOnAccount (TestLedger& ledger, UserAccount const& acct); // Get all Tickets on an account. -std::vector +std::vector > getTicketsOnAccount (TestLedger& ledger, UserAccount const& acct); } // test diff --git a/src/ripple/basics/base_uint.h b/src/ripple/basics/base_uint.h index e1ebc16616..f0bdb981fb 100644 --- a/src/ripple/basics/base_uint.h +++ b/src/ripple/basics/base_uint.h @@ -123,7 +123,15 @@ private: } public: - base_uint () { *this = beast::zero; } + base_uint() + { + *this = beast::zero; + } + + base_uint(beast::Zero) + { + *this = beast::zero; + } explicit base_uint (Blob const& vch) { diff --git a/src/ripple/protocol/STLedgerEntry.h b/src/ripple/protocol/STLedgerEntry.h index 7997283017..707efed584 100644 --- a/src/ripple/protocol/STLedgerEntry.h +++ b/src/ripple/protocol/STLedgerEntry.h @@ -61,6 +61,10 @@ public: std::string getText () const override; Json::Value getJson (int options) const override; + /** Returns the 'key' (or 'index') of this item. + The key identifies this entry's position in + the SHAMap associative container. + */ uint256 const& getIndex () const { return mIndex; @@ -93,15 +97,15 @@ public: return mFormat; } - bool isThreadedType (); // is this a ledger entry that can be threaded - bool isThreaded (); // is this ledger entry actually threaded - bool hasOneOwner (); // This node has one other node that owns it - bool hasTwoOwners (); // This node has two nodes that own it (like ripple balance) - RippleAddress getOwner (); - RippleAddress getFirstOwner (); - RippleAddress getSecondOwner (); - uint256 getThreadedTransaction (); - std::uint32_t getThreadedLedger (); + bool isThreadedType() const; // is this a ledger entry that can be threaded + bool isThreaded () const; // is this ledger entry actually threaded + bool hasOneOwner () const; // This node has one other node that owns it + bool hasTwoOwners () const; // This node has two nodes that own it (like ripple balance) + RippleAddress getOwner () const; + RippleAddress getFirstOwner () const; + RippleAddress getSecondOwner () const; + uint256 getThreadedTransaction () const; + std::uint32_t getThreadedLedger () const; bool thread (uint256 const& txID, std::uint32_t ledgerSeq, uint256 & prevTxID, std::uint32_t & prevLedgerID); diff --git a/src/ripple/protocol/impl/STLedgerEntry.cpp b/src/ripple/protocol/impl/STLedgerEntry.cpp index 6738bd8563..987e07519c 100644 --- a/src/ripple/protocol/impl/STLedgerEntry.cpp +++ b/src/ripple/protocol/impl/STLedgerEntry.cpp @@ -118,22 +118,47 @@ Json::Value STLedgerEntry::getJson (int options) const return ret; } -bool STLedgerEntry::isThreadedType () +bool STLedgerEntry::isThreadedType () const { return getFieldIndex (sfPreviousTxnID) != -1; } -bool STLedgerEntry::isThreaded () +bool STLedgerEntry::isThreaded () const { return isFieldPresent (sfPreviousTxnID); } -uint256 STLedgerEntry::getThreadedTransaction () +bool STLedgerEntry::hasOneOwner () const +{ + return (mType != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1); +} + +bool STLedgerEntry::hasTwoOwners () const +{ + return mType == ltRIPPLE_STATE; +} + +RippleAddress STLedgerEntry::getOwner () const +{ + return getFieldAccount (sfAccount); +} + +RippleAddress STLedgerEntry::getFirstOwner () const +{ + return RippleAddress::createAccountID (getFieldAmount (sfLowLimit).getIssuer ()); +} + +RippleAddress STLedgerEntry::getSecondOwner () const +{ + return RippleAddress::createAccountID (getFieldAmount (sfHighLimit).getIssuer ()); +} + +uint256 STLedgerEntry::getThreadedTransaction () const { return getFieldH256 (sfPreviousTxnID); } -std::uint32_t STLedgerEntry::getThreadedLedger () +std::uint32_t STLedgerEntry::getThreadedLedger () const { return getFieldU32 (sfPreviousTxnLgrSeq); } @@ -158,29 +183,4 @@ bool STLedgerEntry::thread (uint256 const& txID, std::uint32_t ledgerSeq, return true; } -bool STLedgerEntry::hasOneOwner () -{ - return (mType != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1); -} - -bool STLedgerEntry::hasTwoOwners () -{ - return mType == ltRIPPLE_STATE; -} - -RippleAddress STLedgerEntry::getOwner () -{ - return getFieldAccount (sfAccount); -} - -RippleAddress STLedgerEntry::getFirstOwner () -{ - return RippleAddress::createAccountID (getFieldAmount (sfLowLimit).getIssuer ()); -} - -RippleAddress STLedgerEntry::getSecondOwner () -{ - return RippleAddress::createAccountID (getFieldAmount (sfHighLimit).getIssuer ()); -} - } // ripple diff --git a/src/ripple/rpc/handlers/AccountInfo.cpp b/src/ripple/rpc/handlers/AccountInfo.cpp index 1c39790c11..2fc773f37c 100644 --- a/src/ripple/rpc/handlers/AccountInfo.cpp +++ b/src/ripple/rpc/handlers/AccountInfo.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include namespace ripple { @@ -62,7 +63,8 @@ Json::Value doAccountInfo (RPC::Context& context) return jvAccepted; AccountState::pointer asAccepted = - context.netOps.getAccountState (ledger, naAccount); + getAccountState(*ledger, naAccount, + getApp().getSLECache()); if (asAccepted) { @@ -71,7 +73,8 @@ Json::Value doAccountInfo (RPC::Context& context) // See if there's a SignerEntries for this account. Account const account = naAccount.getAccountID (); uint256 const signerListIndex = getSignerListIndex (account); - SLE::pointer signerList = ledger->getSLEi (signerListIndex); + auto const signerList = fetch(*ledger, signerListIndex, + getApp().getSLECache()); if (signerList) { diff --git a/src/ripple/rpc/handlers/AccountLines.cpp b/src/ripple/rpc/handlers/AccountLines.cpp index 9be10e3abd..1d25122d6a 100644 --- a/src/ripple/rpc/handlers/AccountLines.cpp +++ b/src/ripple/rpc/handlers/AccountLines.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include @@ -100,7 +101,8 @@ Json::Value doAccountLines (RPC::Context& context) return result; } - if (! ledger->hasAccount (rippleAddress)) + if (! ledger->exists(getAccountRootIndex( + rippleAddress.getAccountID()))) return rpcError (rpcACT_NOT_FOUND); std::string strPeer (params.isMember (jss::peer) @@ -166,7 +168,8 @@ Json::Value doAccountLines (RPC::Context& context) return RPC::expected_field_error (jss::marker, "string"); startAfter.SetHex (marker.asString ()); - SLE::pointer sleLine (ledger->getSLEi (startAfter)); + auto const sleLine = fetch(*ledger, startAfter, + getApp().getSLECache()); if (sleLine == nullptr || sleLine->getType () != ltRIPPLE_STATE) return rpcError (rpcINVALID_PARAMS); @@ -179,7 +182,7 @@ Json::Value doAccountLines (RPC::Context& context) return rpcError (rpcINVALID_PARAMS); // Caller provided the first line (startAfter), add it as first result - auto const line (RippleState::makeItem (raAccount, sleLine)); + auto const line = RippleState::makeItem (raAccount, sleLine); if (line == nullptr) return rpcError (rpcINVALID_PARAMS); @@ -193,10 +196,12 @@ Json::Value doAccountLines (RPC::Context& context) visitData.items.reserve (++reserve); } - if (! ledger->visitAccountItems (raAccount, startAfter, startHint, reserve, - [&visitData](SLE::ref sleCur) + if (! forEachItemAfter(*ledger, raAccount, getApp().getSLECache(), + startAfter, startHint, reserve, + [&visitData](std::shared_ptr const& sleCur) { - auto const line (RippleState::makeItem (visitData.accountID, sleCur)); + auto const line = + RippleState::makeItem (visitData.accountID, sleCur); if (line != nullptr && (! visitData.rippleAddressPeer.isValid () || visitData.raPeerAccount == line->getAccountIDPeer ())) @@ -216,7 +221,7 @@ Json::Value doAccountLines (RPC::Context& context) result[jss::limit] = limit; RippleState::pointer line (visitData.items.back ()); - result[jss::marker] = to_string (line->peekSLE ().getIndex ()); + result[jss::marker] = to_string (line->key()); visitData.items.pop_back (); } diff --git a/src/ripple/rpc/handlers/AccountObjects.cpp b/src/ripple/rpc/handlers/AccountObjects.cpp index 9c4e795848..6458bd6695 100644 --- a/src/ripple/rpc/handlers/AccountObjects.cpp +++ b/src/ripple/rpc/handlers/AccountObjects.cpp @@ -68,7 +68,8 @@ Json::Value doAccountObjects (RPC::Context& context) } } - if (! ledger->hasAccount (raAccount)) + if (! ledger->exists(getAccountRootIndex( + raAccount.getAccountID()))) return rpcError (rpcACT_NOT_FOUND); auto type = ltINVALID; diff --git a/src/ripple/rpc/handlers/AccountOffers.cpp b/src/ripple/rpc/handlers/AccountOffers.cpp index 2437bccf5d..74bd5477e2 100644 --- a/src/ripple/rpc/handlers/AccountOffers.cpp +++ b/src/ripple/rpc/handlers/AccountOffers.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include namespace ripple { @@ -62,7 +63,8 @@ Json::Value doAccountOffers (RPC::Context& context) if (bIndex) result[jss::account_index] = iIndex; - if (! ledger->hasAccount (rippleAddress)) + if (! ledger->exists(getAccountRootIndex( + rippleAddress.getAccountID()))) return rpcError (rpcACT_NOT_FOUND); unsigned int limit; @@ -88,7 +90,7 @@ Json::Value doAccountOffers (RPC::Context& context) Account const& raAccount (rippleAddress.getAccountID ()); Json::Value& jsonOffers (result[jss::offers] = Json::arrayValue); - std::vector offers; + std::vector > offers; unsigned int reserve (limit); uint256 startAfter; std::uint64_t startHint; @@ -103,7 +105,8 @@ Json::Value doAccountOffers (RPC::Context& context) return RPC::expected_field_error (jss::marker, "string"); startAfter.SetHex (marker.asString ()); - SLE::pointer sleOffer (ledger->getSLEi (startAfter)); + auto const sleOffer = fetch (*ledger, startAfter, + getApp().getSLECache()); if (sleOffer == nullptr || sleOffer->getType () != ltOFFER || @@ -130,8 +133,9 @@ Json::Value doAccountOffers (RPC::Context& context) offers.reserve (++reserve); } - if (! ledger->visitAccountItems (raAccount, startAfter, startHint, reserve, - [&offers](SLE::ref offer) + if (! forEachItemAfter(*ledger, raAccount, getApp().getSLECache(), + startAfter, startHint, reserve, + [&offers](std::shared_ptr const& offer) { if (offer->getType () == ltOFFER) { diff --git a/src/ripple/rpc/handlers/LedgerEntry.cpp b/src/ripple/rpc/handlers/LedgerEntry.cpp index 23a3641c05..2624e1a278 100644 --- a/src/ripple/rpc/handlers/LedgerEntry.cpp +++ b/src/ripple/rpc/handlers/LedgerEntry.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include namespace ripple { @@ -207,7 +208,8 @@ Json::Value doLedgerEntry (RPC::Context& context) if (uNodeIndex.isNonZero ()) { - auto sleNode = lpLedger->getSLEi(uNodeIndex); + auto const sleNode = fetch(*lpLedger, uNodeIndex, + getApp().getSLECache()); if (context.params.isMember(jss::binary)) bNodeBinary = context.params[jss::binary].asBool(); diff --git a/src/ripple/rpc/handlers/LedgerRequest.cpp b/src/ripple/rpc/handlers/LedgerRequest.cpp index f361a055a6..eb69e9784c 100644 --- a/src/ripple/rpc/handlers/LedgerRequest.cpp +++ b/src/ripple/rpc/handlers/LedgerRequest.cpp @@ -63,27 +63,30 @@ Json::Value doLedgerRequest (RPC::Context& context) if (ledgerIndex >= ledger->getLedgerSeq()) return RPC::make_param_error("Ledger index too large"); + auto const j = + deprecatedLogs().journal("RPCHandler"); // Try to get the hash of the desired ledger from the validated ledger - ledgerHash = ledger->getLedgerHash (ledgerIndex); - - if (ledgerHash == zero) + auto ledgerHash = hashOfSeq(*ledger, ledgerIndex, + getApp().getSLECache(), j); + if (! ledgerHash) { // Find a ledger more likely to have the hash of the desired ledger auto refIndex = (ledgerIndex + 255) & (~255); - auto refHash = ledger->getLedgerHash (refIndex); - assert (refHash.isNonZero ()); + auto refHash = hashOfSeq(*ledger, refIndex, + getApp().getSLECache(), j); + assert(refHash); - ledger = ledgerMaster.getLedgerByHash (refHash); - if (!ledger) + ledger = ledgerMaster.getLedgerByHash (*refHash); + if (! ledger) { // We don't have the ledger we need to figure out which ledger // they want. Try to get it. if (auto il = getApp().getInboundLedgers().acquire ( - refHash, refIndex, InboundLedger::fcGENERIC)) + *refHash, refIndex, InboundLedger::fcGENERIC)) return getJson (LedgerFill (*il)); - if (auto il = getApp().getInboundLedgers().find (refHash)) + if (auto il = getApp().getInboundLedgers().find (*refHash)) { Json::Value jvResult = il->getJson (0); @@ -95,8 +98,11 @@ Json::Value doLedgerRequest (RPC::Context& context) return Json::Value(); } - ledgerHash = ledger->getLedgerHash (ledgerIndex); - assert (ledgerHash.isNonZero ()); + ledgerHash = hashOfSeq(*ledger, ledgerIndex, + getApp().getSLECache(), j); + assert (ledgerHash); + if (! ledgerHash) + ledgerHash = zero; // kludge } } diff --git a/src/ripple/rpc/handlers/NoRippleCheck.cpp b/src/ripple/rpc/handlers/NoRippleCheck.cpp index 69180c22e1..1f26177290 100644 --- a/src/ripple/rpc/handlers/NoRippleCheck.cpp +++ b/src/ripple/rpc/handlers/NoRippleCheck.cpp @@ -106,15 +106,17 @@ Json::Value doNoRippleCheck (RPC::Context& context) return result; } - AccountState::pointer accountState = ledger->getAccountState (rippleAddress); + AccountState::pointer accountState = + getAccountState(*ledger, rippleAddress, + getApp().getSLECache()); if (! accountState) return rpcError (rpcACT_NOT_FOUND); - std::uint32_t seq = accountState->peekSLE().getFieldU32 (sfSequence); + std::uint32_t seq = accountState->sle().getFieldU32 (sfSequence); Json::Value& problems = (result["problems"] = Json::arrayValue); - bool bDefaultRipple = accountState->peekSLE().getFieldU32 (sfFlags) & lsfDefaultRipple; + bool bDefaultRipple = accountState->sle().getFieldU32 (sfFlags) & lsfDefaultRipple; if (bDefaultRipple & ! roleGateway) { @@ -135,8 +137,9 @@ Json::Value doNoRippleCheck (RPC::Context& context) auto const accountID = rippleAddress.getAccountID (); - ledger->visitAccountItems (accountID, uint256(), 0, limit, - [&](SLE::ref ownedItem) + forEachItemAfter (*ledger, accountID, getApp().getSLECache(), + uint256(), 0, limit, + [&](std::shared_ptr const& ownedItem) { if (ownedItem->getType() == ltRIPPLE_STATE) { diff --git a/src/ripple/rpc/impl/Accounts.cpp b/src/ripple/rpc/impl/Accounts.cpp index 4daee3363d..de829282d1 100644 --- a/src/ripple/rpc/impl/Accounts.cpp +++ b/src/ripple/rpc/impl/Accounts.cpp @@ -19,6 +19,7 @@ #include #include +#include namespace ripple { namespace RPC { @@ -40,7 +41,8 @@ Json::Value accounts ( naAccount.setAccountPublic (naMasterGenerator, uIndex++); - AccountState::pointer as = netOps.getAccountState (lrLedger, naAccount); + AccountState::pointer as = + getAccountState (*lrLedger, naAccount, getApp().getSLECache()); if (as) { diff --git a/src/ripple/rpc/impl/GetAccountObjects.cpp b/src/ripple/rpc/impl/GetAccountObjects.cpp index f5f85f392e..695d44209d 100644 --- a/src/ripple/rpc/impl/GetAccountObjects.cpp +++ b/src/ripple/rpc/impl/GetAccountObjects.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include @@ -38,8 +39,9 @@ getAccountObjects (Ledger const& ledger, Account const& account, found = true; } - auto dir = ledger.getDirNode (dirIndex); - if (dir == nullptr) + auto dir = fetch(ledger, dirIndex, + getApp().getSLECache(), ltDIR_NODE); + if (! dir) return false; std::uint32_t i = 0; @@ -60,7 +62,8 @@ getAccountObjects (Ledger const& ledger, Account const& account, for (; iter != entries.end (); ++iter) { - auto const sleNode = ledger.getSLEi (*iter); + auto const sleNode = fetch(ledger, *iter, + getApp().getSLECache()); if (type == ltINVALID || sleNode->getType () == type) { jvObjects.append (sleNode->getJson (0)); @@ -84,9 +87,10 @@ getAccountObjects (Ledger const& ledger, Account const& account, if (nodeIndex == 0) return true; - dirIndex = getDirNodeIndex (rootDirIndex, nodeIndex); - dir = ledger.getDirNode (dirIndex); - if (dir == nullptr) + dirIndex = getDirNodeIndex (rootDirIndex, nodeIndex); + dir = fetch(ledger, dirIndex, + getApp().getSLECache(), ltDIR_NODE); + if (! dir) return true; if (i == limit) diff --git a/src/ripple/rpc/impl/TransactionSign.cpp b/src/ripple/rpc/impl/TransactionSign.cpp index 99dad4ccf0..47550a53da 100644 --- a/src/ripple/rpc/impl/TransactionSign.cpp +++ b/src/ripple/rpc/impl/TransactionSign.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -111,7 +112,8 @@ void TxnSignApiFacade::snapshotAccountState (RippleAddress const& accountID) ledger_ = netOPs_->getCurrentLedger (); accountID_ = accountID; - accountState_ = netOPs_->getAccountState (ledger_, accountID_); + accountState_ = getAccountState ( + *ledger_, accountID_, getApp().getSLECache()); } bool TxnSignApiFacade::isValidAccount () const @@ -127,7 +129,7 @@ std::uint32_t TxnSignApiFacade::getSeq () const if (!ledger_) // Unit testing. return 0; - return accountState_->getSeq (); + return accountState_->sle().getFieldU32(sfSequence); } Transaction::pointer TxnSignApiFacade::processTransaction ( @@ -192,11 +194,8 @@ bool TxnSignApiFacade::hasAccountRoot () const { if (!netOPs_) // Unit testing. return true; - - SLE::pointer const sleAccountRoot = - ledger_->getSLEi(getAccountRootIndex(accountID_)); - - return static_cast (sleAccountRoot); + return ledger_->exists( + getAccountRootIndex(accountID_)); } error_code_i acctMatchesPubKey ( @@ -217,7 +216,7 @@ error_code_i acctMatchesPubKey ( } // If we *can* get to the accountRoot, check for MASTER_DISABLED - STLedgerEntry const& sle = accountState->peekSLE (); + auto const& sle = accountState->sle(); if (isMasterKey) { if (sle.isFlag(lsfDisableMaster)) @@ -248,11 +247,13 @@ error_code_i TxnSignApiFacade::multiAcctMatchesPubKey ( RippleAddress const& publicKey) const { AccountState::pointer accountState; + // VFALCO Do we need to check netOPs_? if (netOPs_ && ledger_) // If it's available, get the AccountState for the multi-signer's // accountID. It's okay if the AccountState is not available, // since they might be signing with a phantom (unfunded) account. - accountState = netOPs_->getAccountState (ledger_, accountID); + accountState = getAccountState ( + *ledger_, accountID, getApp().getSLECache()); return acctMatchesPubKey (accountState, accountID, publicKey); } diff --git a/src/ripple/shamap/SHAMapItem.h b/src/ripple/shamap/SHAMapItem.h index 9a5e923526..e3559d9b16 100644 --- a/src/ripple/shamap/SHAMapItem.h +++ b/src/ripple/shamap/SHAMapItem.h @@ -43,7 +43,15 @@ public: Slice slice() const; + uint256 const& + key() const + { + return mTag; + } + + // DEPRECATED uint256 const& getTag() const; + Blob const& peekData() const; Serializer& peekSerializer();