Refactor LedgerEntrySet:

* Remove duplicate:
    This changes behavior to fix an apparent bug. The
    copy will now correctly inherit mParams instead
    of reverting to tapNONE

* Tidy up LedgerEntrySet declarations
* Tidy up TransactionEngine
* Tidy PathCursor declarations
* Add LedgerEntrySet::apply
* Add LedgerEntrySet ctor
* Add Keylet, keylet namespace
* Add defaulted copy members
* Use optional in TransactionEngine
* Use optional<LedgerEntrySet> in PathState
* Return shared_ptr in Ledger::fetch
* Don't call entryCache with zero
* Deprecate invalidate
* Remove default constructor
* Remove unused container API
* Remove CountedObject base class
* Remove insert, clear
* Remove entryCreate overload
* Remove unused and tidy up STLedgerEntry
* Make getEntry private and tidy
* Replace members with adjustOwnerCount free function
* Replace accountFunds with funds free function
This commit is contained in:
Vinnie Falco
2015-06-09 10:37:13 -04:00
committed by Nik Bougalis
parent aead038215
commit d21171b21e
32 changed files with 746 additions and 526 deletions

View File

@@ -99,7 +99,8 @@ void AcceptedLedgerTx::buildJson ()
if (account != amount.issue ().account) if (account != amount.issue ().account)
{ {
LedgerEntrySet les (mLedger, tapNONE, true); LedgerEntrySet les (mLedger, tapNONE, true);
auto const ownerFunds (les.accountFunds (account, amount, fhIGNORE_FREEZE)); auto const ownerFunds (funds(
les, account, amount, fhIGNORE_FREEZE));
mJson[jss::transaction][jss::owner_funds] = ownerFunds.getText (); mJson[jss::transaction][jss::owner_funds] = ownerFunds.getText ();
} }

View File

@@ -984,20 +984,19 @@ Ledger::insert (SLE const& sle)
assert(success); assert(success);
} }
boost::optional<SLE> std::shared_ptr<SLE>
Ledger::fetch (uint256 const& key, Ledger::fetch (uint256 const& key,
boost::optional<LedgerEntryType> type) const boost::optional<LedgerEntryType> type) const
{ {
auto const item = auto const item =
mAccountStateMap->peekItem(key); mAccountStateMap->peekItem(key);
if (! item) if (! item)
return boost::none; return nullptr;
boost::optional<SLE> result; auto const sle = std::make_shared<SLE>(
result.emplace(item->peekSerializer(), item->peekSerializer(), item->getTag());
item->getTag()); if (type && sle->getType() != type)
if (type && result->getType() != type) return nullptr;
return {}; return sle;
return result;
} }
void void
@@ -1171,7 +1170,8 @@ void Ledger::updateSkipList ()
bool created; bool created;
if (! sle) if (! sle)
{ {
sle.emplace(ltLEDGER_HASHES, key); sle = std::make_shared<SLE>(
ltLEDGER_HASHES, key);
created = true; created = true;
} }
else else
@@ -1198,7 +1198,8 @@ void Ledger::updateSkipList ()
bool created; bool created;
if (! sle) if (! sle)
{ {
sle.emplace(ltLEDGER_HASHES, key); sle = std::make_shared<SLE>(
ltLEDGER_HASHES, key);
created = true; created = true;
} }
else else

View File

@@ -25,6 +25,7 @@
#include <ripple/app/tx/TransactionMeta.h> #include <ripple/app/tx/TransactionMeta.h>
#include <ripple/app/ledger/SLECache.h> #include <ripple/app/ledger/SLECache.h>
#include <ripple/app/misc/AccountState.h> #include <ripple/app/misc/AccountState.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/STLedgerEntry.h> #include <ripple/protocol/STLedgerEntry.h>
#include <ripple/basics/CountedObject.h> #include <ripple/basics/CountedObject.h>
#include <ripple/protocol/Serializer.h> #include <ripple/protocol/Serializer.h>
@@ -138,10 +139,16 @@ public:
then boost::none is returned. then boost::none is returned.
@return `empty` if the key is not present @return `empty` if the key is not present
*/ */
boost::optional<SLE> std::shared_ptr<SLE>
fetch (uint256 const& key, boost::optional< fetch (uint256 const& key, boost::optional<
LedgerEntryType> type = boost::none) const; LedgerEntryType> type = boost::none) const;
std::shared_ptr<SLE>
fetch (Keylet const& k) const
{
return fetch(k.key, k.type);
}
// DEPRECATED // DEPRECATED
// Retrieve immutable ledger entry // Retrieve immutable ledger entry
SLE::pointer getSLEi (uint256 const& uHash) const; SLE::pointer getSLEi (uint256 const& uHash) const;

View File

@@ -36,29 +36,74 @@ namespace ripple {
// //
#define DIR_NODE_MAX 32 #define DIR_NODE_MAX 32
void LedgerEntrySet::init (Ledger::ref ledger, uint256 const& transactionID, LedgerEntrySet::LedgerEntrySet (LedgerEntrySet const& other)
std::uint32_t ledgerID, TransactionEngineParams params) : mLedger(other.mLedger)
, mEntries(other.mEntries)
, mDeferredCredits(other.mDeferredCredits)
, mSet(other.mSet)
// VFALCO NOTE This is a change in behavior,
// previous version set tapNONE
, mParams(other.mParams)
, mSeq(other.mSeq + 1)
{
}
LedgerEntrySet::LedgerEntrySet(Ledger::ref ledger,
uint256 const& transactionID,
std::uint32_t ledgerID,
TransactionEngineParams params)
: mLedger(ledger)
, mParams(params)
{ {
mEntries.clear ();
if (mDeferredCredits)
mDeferredCredits->clear ();
mLedger = ledger;
mSet.init (transactionID, ledgerID); mSet.init (transactionID, ledgerID);
mParams = params;
mSeq = 0;
} }
void LedgerEntrySet::clear () LedgerEntrySet::LedgerEntrySet (Ledger::ref ledger,
TransactionEngineParams tep, bool immutable)
: mLedger (ledger)
, mParams (tep)
, mImmutable (immutable)
{ {
mEntries.clear ();
mSet.clear ();
if (mDeferredCredits)
mDeferredCredits->clear ();
} }
LedgerEntrySet LedgerEntrySet::duplicate () const void LedgerEntrySet::apply()
{ {
return LedgerEntrySet (mLedger, mEntries, mSet, mSeq + 1, mDeferredCredits); // Write back the account states
for (auto const& item : mEntries)
{
// VFALCO TODO rvalue move the mEntry, make
// sure the mNodes is not used after
// this function is called.
auto sle = item.second.mEntry;
switch (item.second.mAction)
{
case taaNONE:
assert (false);
break;
case taaCACHED:
break;
case taaCREATE:
// VFALCO Is this logging necessary anymore?
WriteLog (lsDEBUG, LedgerEntrySet) <<
"applyTransaction: taaCREATE: " << sle->getText ();
mLedger->insert(*sle);
break;
case taaMODIFY:
WriteLog (lsDEBUG, LedgerEntrySet) <<
"applyTransaction: taaMODIFY: " << sle->getText ();
mLedger->replace(*sle);
break;
case taaDELETE:
WriteLog (lsDEBUG, LedgerEntrySet) <<
"applyTransaction: taaDELETE: " << sle->getText ();
mLedger->erase(item.first);
break;
}
}
} }
void LedgerEntrySet::swapWith (LedgerEntrySet& e) void LedgerEntrySet::swapWith (LedgerEntrySet& e)
@@ -74,7 +119,7 @@ void LedgerEntrySet::swapWith (LedgerEntrySet& e)
// Find an entry in the set. If it has the wrong sequence number, copy it and update the sequence number. // Find an entry in the set. If it has the wrong sequence number, copy it and update the sequence number.
// This is basically: copy-on-read. // This is basically: copy-on-read.
SLE::pointer LedgerEntrySet::getEntry (uint256 const& index, LedgerEntryAction& action) SLE::pointer LedgerEntrySet::getEntry (uint256 const& index, Action& action)
{ {
auto it = mEntries.find (index); auto it = mEntries.find (index);
@@ -87,7 +132,7 @@ SLE::pointer LedgerEntrySet::getEntry (uint256 const& index, LedgerEntryAction&
if (it->second.mSeq != mSeq) if (it->second.mSeq != mSeq)
{ {
assert (it->second.mSeq < mSeq); assert (it->second.mSeq < mSeq);
it->second.mEntry = std::make_shared<STLedgerEntry> (*it->second.mEntry); it->second.mEntry = std::make_shared<SLE> (*it->second.mEntry);
it->second.mSeq = mSeq; it->second.mSeq = mSeq;
} }
@@ -95,26 +140,15 @@ SLE::pointer LedgerEntrySet::getEntry (uint256 const& index, LedgerEntryAction&
return it->second.mEntry; return it->second.mEntry;
} }
SLE::pointer LedgerEntrySet::entryCreate (LedgerEntryType letType, uint256 const& index)
{
assert (index.isNonZero ());
SLE::pointer sleNew = std::make_shared<SLE> (letType, index);
entryCreate (sleNew);
return sleNew;
}
SLE::pointer LedgerEntrySet::entryCache (LedgerEntryType letType, uint256 const& key) SLE::pointer LedgerEntrySet::entryCache (LedgerEntryType letType, uint256 const& key)
{ {
assert(key.isNonZero ());
assert (mLedger); assert (mLedger);
SLE::pointer sle; SLE::pointer sle;
// VFALCO Shouldn't be calling this with invalid keys,
// but apparently its happening. Need to track it down.
//assert(key.isNonZero ());
if (key.isNonZero ()) if (key.isNonZero ())
{ {
LedgerEntryAction action; Action action;
sle = getEntry (key, action); sle = getEntry (key, action);
if (! sle) if (! sle)
@@ -128,10 +162,7 @@ SLE::pointer LedgerEntrySet::entryCache (LedgerEntryType letType, uint256 const&
} }
else else
{ {
auto maybe_sle = mLedger->fetch(key, letType); sle = mLedger->fetch(key, letType);
if (maybe_sle)
sle = std::make_shared<SLE>(
std::move(*maybe_sle));
} }
if (sle) if (sle)
@@ -160,7 +191,7 @@ void LedgerEntrySet::entryCache (SLE::ref sle)
if (it == mEntries.end ()) if (it == mEntries.end ())
{ {
mEntries.insert (std::make_pair (sle->getIndex (), LedgerEntrySetEntry (sle, taaCACHED, mSeq))); mEntries.insert (std::make_pair (sle->getIndex (), Item (sle, taaCACHED, mSeq)));
return; return;
} }
@@ -185,7 +216,7 @@ void LedgerEntrySet::entryCreate (SLE::ref sle)
if (it == mEntries.end ()) if (it == mEntries.end ())
{ {
mEntries.insert (std::make_pair (sle->getIndex (), LedgerEntrySetEntry (sle, taaCREATE, mSeq))); mEntries.insert (std::make_pair (sle->getIndex (), Item (sle, taaCREATE, mSeq)));
return; return;
} }
@@ -223,7 +254,7 @@ void LedgerEntrySet::entryModify (SLE::ref sle)
if (it == mEntries.end ()) if (it == mEntries.end ())
{ {
mEntries.insert (std::make_pair (sle->getIndex (), LedgerEntrySetEntry (sle, taaMODIFY, mSeq))); mEntries.insert (std::make_pair (sle->getIndex (), Item (sle, taaMODIFY, mSeq)));
return; return;
} }
@@ -260,7 +291,7 @@ void LedgerEntrySet::entryDelete (SLE::ref sle)
if (it == mEntries.end ()) if (it == mEntries.end ())
{ {
assert (false); // deleting an entry not cached? assert (false); // deleting an entry not cached?
mEntries.insert (std::make_pair (sle->getIndex (), LedgerEntrySetEntry (sle, taaDELETE, mSeq))); mEntries.insert (std::make_pair (sle->getIndex (), Item (sle, taaDELETE, mSeq)));
return; return;
} }
@@ -379,7 +410,8 @@ SLE::pointer LedgerEntrySet::getForMod (uint256 const& node, Ledger::ref ledger,
if (it->second.mSeq != mSeq) if (it->second.mSeq != mSeq)
{ {
it->second.mEntry = std::make_shared<STLedgerEntry> (*it->second.mEntry); it->second.mEntry =
std::make_shared<SLE> (*it->second.mEntry);
it->second.mSeq = mSeq; it->second.mSeq = mSeq;
} }
@@ -395,15 +427,10 @@ SLE::pointer LedgerEntrySet::getForMod (uint256 const& node, Ledger::ref ledger,
} }
auto sle = ledger->fetch(node); auto sle = ledger->fetch(node);
if (sle) if (! sle)
{ return nullptr;
auto p = std::make_shared<SLE>( newMods.insert (std::make_pair (node, sle));
std::move(*sle)); return sle;
newMods.insert (std::make_pair (node, p));
return p;
}
return {};
} }
bool LedgerEntrySet::threadTx (RippleAddress const& threadTo, Ledger::ref ledger, bool LedgerEntrySet::threadTx (RippleAddress const& threadTo, Ledger::ref ledger,
@@ -611,36 +638,6 @@ void LedgerEntrySet::calcRawMeta (Serializer& s, TER result, std::uint32_t index
WriteLog (lsTRACE, LedgerEntrySet) << "Metadata:" << mSet.getJson (0); WriteLog (lsTRACE, LedgerEntrySet) << "Metadata:" << mSet.getJson (0);
} }
TER LedgerEntrySet::dirCount (uint256 const& uRootIndex, std::uint32_t& uCount)
{
std::uint64_t uNodeDir = 0;
uCount = 0;
do
{
SLE::pointer sleNode = entryCache (ltDIR_NODE, getDirNodeIndex (uRootIndex, uNodeDir));
if (sleNode)
{
uCount += sleNode->getFieldV256 (sfIndexes).size ();
uNodeDir = sleNode->getFieldU64 (sfIndexNext); // Get next node.
}
else if (uNodeDir)
{
WriteLog (lsWARNING, LedgerEntrySet) << "dirCount: no such node";
assert (false);
return tefBAD_LEDGER;
}
}
while (uNodeDir);
return tesSUCCESS;
}
bool LedgerEntrySet::dirIsEmpty (uint256 const& uRootIndex) bool LedgerEntrySet::dirIsEmpty (uint256 const& uRootIndex)
{ {
std::uint64_t uNodeDir = 0; std::uint64_t uNodeDir = 0;
@@ -679,10 +676,10 @@ TER LedgerEntrySet::dirAdd (
if (!sleRoot) if (!sleRoot)
{ {
// No root, make it. // No root, make it.
sleRoot = entryCreate (ltDIR_NODE, uRootIndex); sleRoot = std::make_shared<SLE>(ltDIR_NODE, uRootIndex);
sleRoot->setFieldH256 (sfRootIndex, uRootIndex); sleRoot->setFieldH256 (sfRootIndex, uRootIndex);
entryCreate (sleRoot);
fDescriber (sleRoot, true); fDescriber (sleRoot, true);
sleNode = sleRoot; sleNode = sleRoot;
uNodeDir = 0; uNodeDir = 0;
} }
@@ -726,8 +723,10 @@ TER LedgerEntrySet::dirAdd (
entryModify (sleRoot); entryModify (sleRoot);
// Create the new node. // Create the new node.
sleNode = entryCreate (ltDIR_NODE, getDirNodeIndex (uRootIndex, uNodeDir)); sleNode = std::make_shared<SLE>(
ltDIR_NODE, getDirNodeIndex(uRootIndex, uNodeDir));
sleNode->setFieldH256 (sfRootIndex, uRootIndex); sleNode->setFieldH256 (sfRootIndex, uRootIndex);
entryCreate (sleNode);
if (uNodeDir != 1) if (uNodeDir != 1)
sleNode->setFieldU64 (sfIndexPrevious, uNodeDir - 1); sleNode->setFieldU64 (sfIndexPrevious, uNodeDir - 1);
@@ -1080,7 +1079,7 @@ uint256 LedgerEntrySet::getNextLedgerIndex (uint256 const& uHash)
{ {
// find next node in ledger that isn't deleted by LES // find next node in ledger that isn't deleted by LES
uint256 ledgerNext = uHash; uint256 ledgerNext = uHash;
std::map<uint256, LedgerEntrySetEntry>::const_iterator it; std::map<uint256, Item>::const_iterator it;
do do
{ {
@@ -1113,69 +1112,6 @@ uint256 LedgerEntrySet::getNextLedgerIndex (
return next; return next;
} }
void LedgerEntrySet::incrementOwnerCount (SLE::ref sleAccount)
{
increaseOwnerCount (sleAccount, 1);
}
void LedgerEntrySet::incrementOwnerCount (Account const& owner)
{
increaseOwnerCount(
entryCache (ltACCOUNT_ROOT, getAccountRootIndex (owner)), 1);
}
void
LedgerEntrySet::increaseOwnerCount (SLE::ref sleAccount, std::uint32_t howMuch)
{
assert (sleAccount);
std::uint32_t const current_count = sleAccount->getFieldU32 (sfOwnerCount);
std::uint32_t new_count = current_count + howMuch;
// Check for integer overflow -- well defined behavior on unsigned.
if (new_count < current_count)
{
WriteLog (lsFATAL, LedgerEntrySet) <<
"Account " << sleAccount->getFieldAccount160 (sfAccount) <<
" owner count exceeds max!";
new_count = std::numeric_limits<std::uint32_t>::max ();
}
sleAccount->setFieldU32 (sfOwnerCount, new_count);
entryModify (sleAccount);
}
void LedgerEntrySet::decrementOwnerCount (SLE::ref sleAccount)
{
decreaseOwnerCount (sleAccount, 1);
}
void LedgerEntrySet::decrementOwnerCount (Account const& owner)
{
decreaseOwnerCount(
entryCache (ltACCOUNT_ROOT, getAccountRootIndex (owner)), 1);
}
void
LedgerEntrySet::decreaseOwnerCount (SLE::ref sleAccount, std::uint32_t howMuch)
{
assert (sleAccount);
std::uint32_t const current_count = sleAccount->getFieldU32 (sfOwnerCount);
std::uint32_t new_count = current_count - howMuch;
// Check for integer underflow -- well defined behavior on unsigned.
if (new_count > current_count)
{
WriteLog (lsFATAL, LedgerEntrySet) <<
"Account " << sleAccount->getFieldAccount160 (sfAccount) <<
" owner count set below 0!";
new_count = 0;
assert (false); // "This is a dangerous place." Stop in a debug build.
}
sleAccount->setFieldU32 (sfOwnerCount, new_count);
entryModify (sleAccount);
}
TER LedgerEntrySet::offerDelete (SLE::pointer sleOffer) TER LedgerEntrySet::offerDelete (SLE::pointer sleOffer)
{ {
if (!sleOffer) if (!sleOffer)
@@ -1197,7 +1133,8 @@ TER LedgerEntrySet::offerDelete (SLE::pointer sleOffer)
false, uBookNode, uDirectory, offerIndex, true, false); false, uBookNode, uDirectory, offerIndex, true, false);
if (tesSUCCESS == terResult) if (tesSUCCESS == terResult)
decrementOwnerCount (owner); adjustOwnerCount(*this, entryCache(ltACCOUNT_ROOT,
getAccountRootIndex(owner)), -1);
entryDelete (sleOffer); entryDelete (sleOffer);
@@ -1333,43 +1270,6 @@ bool LedgerEntrySet::isFrozen(
return false; return false;
} }
// Returns the funds available for account for a currency/issuer.
// Use when you need a default for rippling account's currency.
// XXX Should take into account quality?
// --> saDefault/currency/issuer
// <-- saFunds: Funds available. May be negative.
//
// If the issuer is the same as account, funds are unlimited, use result is
// saDefault.
STAmount LedgerEntrySet::accountFunds (
Account const& account, STAmount const& saDefault, FreezeHandling zeroIfFrozen)
{
STAmount saFunds;
if (!saDefault.native () && saDefault.getIssuer () == account)
{
saFunds = saDefault;
WriteLog (lsTRACE, LedgerEntrySet) << "accountFunds:" <<
" account=" << to_string (account) <<
" saDefault=" << saDefault.getFullText () <<
" SELF-FUNDED";
}
else
{
saFunds = accountHolds (
account, saDefault.getCurrency (), saDefault.getIssuer (),
zeroIfFrozen);
WriteLog (lsTRACE, LedgerEntrySet) << "accountFunds:" <<
" account=" << to_string (account) <<
" saDefault=" << saDefault.getFullText () <<
" saFunds=" << saFunds.getFullText ();
}
return saFunds;
}
TER LedgerEntrySet::trustCreate ( TER LedgerEntrySet::trustCreate (
const bool bSrcHigh, const bool bSrcHigh,
Account const& uSrcAccountID, Account const& uSrcAccountID,
@@ -1393,7 +1293,9 @@ TER LedgerEntrySet::trustCreate (
auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID; auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID; auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
SLE::pointer sleRippleState = entryCreate (ltRIPPLE_STATE, uIndex); auto sleRippleState = std::make_shared<SLE>(
ltRIPPLE_STATE, uIndex);
entryCreate (sleRippleState);
std::uint64_t uLowNode; std::uint64_t uLowNode;
std::uint64_t uHighNode; std::uint64_t uHighNode;
@@ -1469,7 +1371,7 @@ TER LedgerEntrySet::trustCreate (
} }
sleRippleState->setFieldU32 (sfFlags, uFlags); sleRippleState->setFieldU32 (sfFlags, uFlags);
incrementOwnerCount (sleAccount); adjustOwnerCount(*this, sleAccount, 1);
// ONLY: Create ripple balance. // ONLY: Create ripple balance.
sleRippleState->setFieldAmount (sfBalance, bSetHigh ? -saBalance : saBalance); sleRippleState->setFieldAmount (sfBalance, bSetHigh ? -saBalance : saBalance);
@@ -1659,7 +1561,8 @@ TER LedgerEntrySet::rippleCredit (
// Sender quality out is 0. // Sender quality out is 0.
{ {
// Clear the reserve of the sender, possibly delete the line! // Clear the reserve of the sender, possibly delete the line!
decrementOwnerCount (uSenderID); adjustOwnerCount(*this, entryCache(ltACCOUNT_ROOT,
getAccountRootIndex(uSenderID)), -1);
// Clear reserve flag. // Clear reserve flag.
sleRippleState->setFieldU32 ( sleRippleState->setFieldU32 (
@@ -1881,9 +1784,9 @@ bool LedgerEntrySet::checkState (
{ {
std::uint32_t const flags (state->getFieldU32 (sfFlags)); std::uint32_t const flags (state->getFieldU32 (sfFlags));
auto sender_account = entryCache (ltACCOUNT_ROOT, auto sle = entryCache (ltACCOUNT_ROOT,
getAccountRootIndex (sender)); getAccountRootIndex (sender));
assert (sender_account); assert (sle);
// YYY Could skip this if rippling in reverse. // YYY Could skip this if rippling in reverse.
if (before > zero if (before > zero
@@ -1893,7 +1796,7 @@ bool LedgerEntrySet::checkState (
&& (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) && (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
// Sender reserve is set. // Sender reserve is set.
&& static_cast <bool> (flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != && static_cast <bool> (flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
static_cast <bool> (sender_account->getFlags() & lsfDefaultRipple) static_cast <bool> (sle->getFlags() & lsfDefaultRipple)
&& !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) && !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze))
&& !state->getFieldAmount ( && !state->getFieldAmount (
!bSenderHigh ? sfLowLimit : sfHighLimit) !bSenderHigh ? sfLowLimit : sfHighLimit)
@@ -1905,8 +1808,9 @@ bool LedgerEntrySet::checkState (
!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) !bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
// Sender quality out is 0. // Sender quality out is 0.
{ {
// VFALCO Where is the line being deleted?
// Clear the reserve of the sender, possibly delete the line! // Clear the reserve of the sender, possibly delete the line!
decrementOwnerCount (sender_account); adjustOwnerCount(*this, sle, -1);
// Clear reserve flag. // Clear reserve flag.
state->setFieldU32 (sfFlags, state->setFieldU32 (sfFlags,
@@ -2146,4 +2050,70 @@ ScopedDeferCredits::~ScopedDeferCredits ()
} }
} }
//------------------------------------------------------------------------------
void
adjustOwnerCount (LedgerEntrySet& view,
std::shared_ptr<SLE> const& sle, int amount)
{
assert(amount != 0);
auto const current =
sle->getFieldU32 (sfOwnerCount);
auto adjusted = current + amount;
if (amount > 0)
{
// Overflow is well defined on unsigned
if (adjusted < current)
{
WriteLog (lsFATAL, LedgerEntrySet) <<
"Account " << sle->getFieldAccount160(sfAccount) <<
" owner count exceeds max!";
adjusted =
std::numeric_limits<std::uint32_t>::max ();
}
}
else
{
// Underflow is well defined on unsigned
if (adjusted > current)
{
WriteLog (lsFATAL, LedgerEntrySet) <<
"Account " << sle->getFieldAccount160 (sfAccount) <<
" owner count set below 0!";
adjusted = 0;
assert(false);
}
}
sle->setFieldU32 (sfOwnerCount, adjusted);
view.entryModify (sle);
}
STAmount
funds (LedgerEntrySet& view, Account const& id,
STAmount const& saDefault, FreezeHandling freezeHandling)
{
STAmount saFunds;
if (!saDefault.native () &&
saDefault.getIssuer () == id)
{
saFunds = saDefault;
WriteLog (lsTRACE, LedgerEntrySet) << "accountFunds:" <<
" account=" << to_string (id) <<
" saDefault=" << saDefault.getFullText () <<
" SELF-FUNDED";
}
else
{
saFunds = view.accountHolds(id,
saDefault.getCurrency(), saDefault.getIssuer(),
freezeHandling);
WriteLog (lsTRACE, LedgerEntrySet) << "accountFunds:" <<
" account=" << to_string (id) <<
" saDefault=" << saDefault.getFullText () <<
" saFunds=" << saFunds.getFullText ();
}
return saFunds;
}
} // ripple } // ripple

View File

@@ -24,7 +24,9 @@
#include <ripple/app/ledger/DeferredCredits.h> #include <ripple/app/ledger/DeferredCredits.h>
#include <ripple/basics/CountedObject.h> #include <ripple/basics/CountedObject.h>
#include <ripple/protocol/STLedgerEntry.h> #include <ripple/protocol/STLedgerEntry.h>
#include <beast/utility/noexcept.h>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <utility>
namespace ripple { namespace ripple {
@@ -50,39 +52,12 @@ enum TransactionEngineParams
tapADMIN = 0x400, tapADMIN = 0x400,
}; };
enum LedgerEntryAction
{
taaNONE,
taaCACHED, // Unmodified.
taaMODIFY, // Modifed, must have previously been taaCACHED.
taaDELETE, // Delete, must have previously been taaDELETE or taaMODIFY.
taaCREATE, // Newly created.
};
enum FreezeHandling enum FreezeHandling
{ {
fhIGNORE_FREEZE, fhIGNORE_FREEZE,
fhZERO_IF_FROZEN fhZERO_IF_FROZEN
}; };
class LedgerEntrySetEntry
: public CountedObject <LedgerEntrySetEntry>
{
public:
static char const* getCountedObjectName () { return "LedgerEntrySetEntry"; }
SLE::pointer mEntry;
LedgerEntryAction mAction;
int mSeq;
LedgerEntrySetEntry (SLE::ref e, LedgerEntryAction a, int s)
: mEntry (e)
, mAction (a)
, mSeq (s)
{
}
};
/** An LES is a LedgerEntrySet. /** An LES is a LedgerEntrySet.
It's a view into a ledger used while a transaction is processing. It's a view into a ledger used while a transaction is processing.
@@ -91,30 +66,73 @@ public:
transaction finishes, the LES is committed into the ledger to make transaction finishes, the LES is committed into the ledger to make
the modifications. The transaction metadata is built from the LES too. the modifications. The transaction metadata is built from the LES too.
*/ */
/** @{ */
class LedgerEntrySet class LedgerEntrySet
: public CountedObject <LedgerEntrySet> {
private:
using NodeToLedgerEntry =
hash_map<uint256, SLE::pointer>;
enum Action
{
taaNONE,
taaCACHED, // Unmodified.
taaMODIFY, // Modifed, must have previously been taaCACHED.
taaDELETE, // Delete, must have previously been taaDELETE or taaMODIFY.
taaCREATE, // Newly created.
};
class Item
{ {
public: public:
static char const* getCountedObjectName () { return "LedgerEntrySet"; } int mSeq;
Action mAction;
std::shared_ptr<SLE> mEntry;
LedgerEntrySet ( Item (SLE::ref e, Action a, int s)
Ledger::ref ledger, TransactionEngineParams tep, bool immutable = false) : mSeq (s)
: mLedger (ledger), mParams (tep), mSeq (0), mImmutable (immutable) , mAction (a)
, mEntry (e)
{ {
} }
};
LedgerEntrySet () : mParams (tapNONE), mSeq (0), mImmutable (false) Ledger::pointer mLedger;
{ // Implementation requires an ordered container
} std::map<uint256, Item> mEntries;
boost::optional<DeferredCredits> mDeferredCredits;
TransactionMetaSet mSet;
TransactionEngineParams mParams = tapNONE;
int mSeq = 0;
bool mImmutable = false;
// Make a duplicate of this set. public:
LedgerEntrySet duplicate () const; LedgerEntrySet& operator= (LedgerEntrySet const&) = delete;
/** Construct a copy.
Effects:
The copy is identical except that
the sequence number is one higher.
*/
LedgerEntrySet (LedgerEntrySet const&);
LedgerEntrySet (Ledger::ref ledger,
uint256 const& transactionID,
std::uint32_t ledgerID,
TransactionEngineParams params);
LedgerEntrySet (Ledger::ref ledger,
TransactionEngineParams tep,
bool immutable = false);
/** Apply changes to the backing ledger. */
void
apply();
// Swap the contents of two sets // Swap the contents of two sets
void swapWith (LedgerEntrySet&); void swapWith (LedgerEntrySet&);
void invalidate () // VFALCO Only called from RippleCalc.cpp
void deprecatedInvalidate()
{ {
mLedger.reset (); mLedger.reset ();
mDeferredCredits.reset (); mDeferredCredits.reset ();
@@ -135,26 +153,17 @@ public:
++mSeq; ++mSeq;
} }
void init (Ledger::ref ledger, uint256 const& transactionID,
std::uint32_t ledgerID, TransactionEngineParams params);
void clear ();
Ledger::pointer& getLedger () Ledger::pointer& getLedger ()
{ {
return mLedger; return mLedger;
} }
// basic entry functions
SLE::pointer getEntry (uint256 const& index, LedgerEntryAction&);
void entryCache (SLE::ref); // Add this entry to the cache void entryCache (SLE::ref); // Add this entry to the cache
void entryCreate (SLE::ref); // This entry will be created void entryCreate (SLE::ref); // This entry will be created
void entryDelete (SLE::ref); // This entry will be deleted void entryDelete (SLE::ref); // This entry will be deleted
void entryModify (SLE::ref); // This entry will be modified void entryModify (SLE::ref); // This entry will be modified
// higher-level ledger functions // higher-level ledger functions
SLE::pointer entryCreate (LedgerEntryType letType, uint256 const& uIndex);
SLE::pointer entryCache (LedgerEntryType letType, uint256 const& key); SLE::pointer entryCache (LedgerEntryType letType, uint256 const& key);
std::shared_ptr<SLE const> std::shared_ptr<SLE const>
@@ -177,35 +186,24 @@ public:
bool dirFirst (uint256 const& uRootIndex, SLE::pointer& sleNode, bool dirFirst (uint256 const& uRootIndex, SLE::pointer& sleNode,
unsigned int & uDirEntry, uint256 & uEntryIndex); unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirFirst (uint256 const& uRootIndex, std::shared_ptr<SLE const>& sleNode, bool dirFirst (uint256 const& uRootIndex, std::shared_ptr<SLE const>& sleNode,
unsigned int & uDirEntry, uint256 & uEntryIndex); unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirNext (uint256 const& uRootIndex, SLE::pointer& sleNode, bool dirNext (uint256 const& uRootIndex, SLE::pointer& sleNode,
unsigned int & uDirEntry, uint256 & uEntryIndex); unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirNext (uint256 const& uRootIndex, std::shared_ptr<SLE const>& sleNode, bool dirNext (uint256 const& uRootIndex, std::shared_ptr<SLE const>& sleNode,
unsigned int & uDirEntry, uint256 & uEntryIndex); unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirIsEmpty (uint256 const& uDirIndex); bool dirIsEmpty (uint256 const& uDirIndex);
TER dirCount (uint256 const& uDirIndex, std::uint32_t & uCount);
uint256 getNextLedgerIndex (uint256 const& uHash); uint256 getNextLedgerIndex (uint256 const& uHash);
uint256 getNextLedgerIndex (uint256 const& uHash, uint256 const& uEnd); uint256 getNextLedgerIndex (uint256 const& uHash, uint256 const& uEnd);
/** @{ */
void incrementOwnerCount (SLE::ref sleAccount);
void incrementOwnerCount (Account const& owner);
void increaseOwnerCount (SLE::ref sleAccount, std::uint32_t howMuch);
/** @} */
/** @{ */
void decrementOwnerCount (SLE::ref sleAccount);
void decrementOwnerCount (Account const& owner);
void decreaseOwnerCount (SLE::ref sleAccount, std::uint32_t howMuch);
/** @} */
// Offer functions. // Offer functions.
TER offerDelete (SLE::pointer); TER offerDelete (SLE::pointer);
TER offerDelete (uint256 const& offerIndex) TER offerDelete (uint256 const& offerIndex)
{ {
return offerDelete( entryCache (ltOFFER, offerIndex)); return offerDelete( entryCache (ltOFFER, offerIndex));
@@ -220,6 +218,7 @@ public:
bool isGlobalFrozen (Account const& issuer); bool isGlobalFrozen (Account const& issuer);
void enableDeferredCredits (bool enable=true); void enableDeferredCredits (bool enable=true);
bool areCreditsDeferred () const; bool areCreditsDeferred () const;
TER rippleCredit ( TER rippleCredit (
@@ -229,8 +228,7 @@ public:
STAmount accountHolds ( STAmount accountHolds (
Account const& account, Currency const& currency, Account const& account, Currency const& currency,
Account const& issuer, FreezeHandling freezeHandling); Account const& issuer, FreezeHandling freezeHandling);
STAmount accountFunds (
Account const& account, const STAmount & saDefault, FreezeHandling freezeHandling);
TER accountSend ( TER accountSend (
Account const& uSenderID, Account const& uReceiverID, Account const& uSenderID, Account const& uReceiverID,
const STAmount & saAmount); const STAmount & saAmount);
@@ -248,46 +246,15 @@ public:
STAmount const& saSrcLimit, STAmount const& saSrcLimit,
const std::uint32_t uSrcQualityIn = 0, const std::uint32_t uSrcQualityIn = 0,
const std::uint32_t uSrcQualityOut = 0); const std::uint32_t uSrcQualityOut = 0);
TER trustDelete ( TER trustDelete (
SLE::ref sleRippleState, Account const& uLowAccountID, SLE::ref sleRippleState, Account const& uLowAccountID,
Account const& uHighAccountID); Account const& uHighAccountID);
Json::Value getJson (int) const; Json::Value getJson (int) const;
void calcRawMeta (Serializer&, TER result, std::uint32_t index); void calcRawMeta (Serializer&, TER result, std::uint32_t index);
// iterator functions
using iterator = std::map<uint256, LedgerEntrySetEntry>::iterator;
using const_iterator = std::map<uint256, LedgerEntrySetEntry>::const_iterator;
bool empty () const
{
return mEntries.empty ();
}
const_iterator cbegin () const
{
return mEntries.cbegin ();
}
const_iterator cend () const
{
return mEntries.cend ();
}
const_iterator begin () const
{
return mEntries.cbegin ();
}
const_iterator end () const
{
return mEntries.cend ();
}
iterator begin ()
{
return mEntries.begin ();
}
iterator end ()
{
return mEntries.end ();
}
void setDeliveredAmount (STAmount const& amt) void setDeliveredAmount (STAmount const& amt)
{ {
mSet.setDeliveredAmount (amt); mSet.setDeliveredAmount (amt);
@@ -302,24 +269,7 @@ public:
TER transfer_xrp (Account const& from, Account const& to, STAmount const& amount); TER transfer_xrp (Account const& from, Account const& to, STAmount const& amount);
private: private:
Ledger::pointer mLedger; SLE::pointer getEntry (uint256 const& index, Action&);
std::map<uint256, LedgerEntrySetEntry> mEntries; // cannot be unordered!
// Defers credits made to accounts until later
boost::optional<DeferredCredits> mDeferredCredits;
using NodeToLedgerEntry = hash_map<uint256, SLE::pointer>;
TransactionMetaSet mSet;
TransactionEngineParams mParams;
int mSeq;
bool mImmutable;
LedgerEntrySet (
Ledger::ref ledger, const std::map<uint256, LedgerEntrySetEntry>& e,
const TransactionMetaSet & s, int m, boost::optional<DeferredCredits> const& ft) :
mLedger (ledger), mEntries (e), mDeferredCredits (ft), mSet (s), mParams (tapNONE),
mSeq (m), mImmutable (false)
{}
SLE::pointer getForMod ( SLE::pointer getForMod (
uint256 const& node, Ledger::ref ledger, uint256 const& node, Ledger::ref ledger,
@@ -359,8 +309,17 @@ private:
STAmount const& amount); STAmount const& amount);
}; };
template <class... Args>
inline
void
reconstruct (LedgerEntrySet& v, Args&&... args) noexcept
{
v.~LedgerEntrySet();
new(&v) LedgerEntrySet(
std::forward<Args>(args)...);
}
using LedgerView = LedgerEntrySet; using LedgerView = LedgerEntrySet;
/** @} */
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -382,6 +341,30 @@ std::uint32_t
rippleTransferRate (LedgerEntrySet& ledger, Account const& uSenderID, rippleTransferRate (LedgerEntrySet& ledger, Account const& uSenderID,
Account const& uReceiverID, Account const& issuer); Account const& uReceiverID, Account const& issuer);
//------------------------------------------------------------------------------
//
// API
//
//------------------------------------------------------------------------------
/** Adjust the owner count up or down. */
void
adjustOwnerCount (LedgerEntrySet& view,
std::shared_ptr<SLE> const& sle, int amount);
// Returns the funds available for account for a currency/issuer.
// Use when you need a default for rippling account's currency.
// XXX Should take into account quality?
// --> saDefault/currency/issuer
// <-- saFunds: Funds available. May be negative.
//
// If the issuer is the same as account, funds are unlimited, use result is
// saDefault.
STAmount
funds (LedgerEntrySet& view, Account const& id,
STAmount const& saDefault,
FreezeHandling freezeHandling);
} // ripple } // ripple
#endif #endif

View File

@@ -1193,6 +1193,8 @@ bool ApplicationImp::loadOldLedger (
if (stp.object && (uIndex.isNonZero())) if (stp.object && (uIndex.isNonZero()))
{ {
// VFALCO TODO This is the only place that
// constructor is used, try to remove it
STLedgerEntry sle (*stp.object, uIndex); STLedgerEntry sle (*stp.object, uIndex);
bool ok = loadLedger->addSLE (sle); bool ok = loadLedger->addSLE (sle);
if (!ok) if (!ok)

View File

@@ -2496,9 +2496,10 @@ Json::Value NetworkOPsImp::transJson(
// If the offer create is not self funded then add the owner balance // If the offer create is not self funded then add the owner balance
if (account != amount.issue ().account) if (account != amount.issue ().account)
{ {
// VFALCO Why are we doing this hack?
LedgerEntrySet les (lpCurrent, tapNONE, true); LedgerEntrySet les (lpCurrent, tapNONE, true);
auto const ownerFunds (les.accountFunds (account, amount, fhIGNORE_FREEZE)); auto const ownerFunds = funds(
les,account, amount, fhIGNORE_FREEZE);
jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText (); jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText ();
} }
} }
@@ -2947,8 +2948,13 @@ void NetworkOPsImp::getBookPage (
m_journal.trace << "getBookPage: bDirectAdvance"; m_journal.trace << "getBookPage: bDirectAdvance";
uint256 const ledgerIndex =
lpLedger->getNextLedgerIndex (uTipIndex, uBookEnd);
if (ledgerIndex.isNonZero())
sleOfferDir = lesActive.entryCache ( sleOfferDir = lesActive.entryCache (
ltDIR_NODE, lpLedger->getNextLedgerIndex (uTipIndex, uBookEnd)); ltDIR_NODE, ledgerIndex);
else
sleOfferDir.reset();
if (!sleOfferDir) if (!sleOfferDir)
{ {

View File

@@ -32,7 +32,7 @@
#include <ripple/protocol/ErrorCodes.h> #include <ripple/protocol/ErrorCodes.h>
#include <ripple/protocol/UintTypes.h> #include <ripple/protocol/UintTypes.h>
#include <beast/module/core/text/LexicalCast.h> #include <beast/module/core/text/LexicalCast.h>
#include <boost/log/trivial.hpp> #include <boost/optional.hpp>
#include <tuple> #include <tuple>
namespace ripple { namespace ripple {
@@ -480,7 +480,8 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
if (valid) if (valid)
{ {
LedgerEntrySet lesSandbox (cache->getLedger (), tapNONE); LedgerEntrySet lesSandbox(
cache->getLedger(), tapNONE);
auto& sourceAccount = !isXRP (currIssuer.account) auto& sourceAccount = !isXRP (currIssuer.account)
? currIssuer.account ? currIssuer.account
: isXRP (currIssuer.currency) : isXRP (currIssuer.currency)
@@ -505,7 +506,7 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
m_journal.debug m_journal.debug
<< iIdentifier << " Trying with an extra path element"; << iIdentifier << " Trying with an extra path element";
spsPaths.push_back (fullLiquidityPath); spsPaths.push_back (fullLiquidityPath);
lesSandbox.clear(); reconstruct(lesSandbox, cache->getLedger (), tapNONE);
rc = path::RippleCalc::rippleCalculate ( rc = path::RippleCalc::rippleCalculate (
lesSandbox, lesSandbox,
saMaxAmount, saMaxAmount,

View File

@@ -268,7 +268,7 @@ TER PathState::pushNode (
auto const& backNode = nodes_.back (); auto const& backNode = nodes_.back ();
if (backNode.isAccount()) if (backNode.isAccount())
{ {
auto sleRippleState = lesEntries.entryCache ( auto sleRippleState = lesEntries_->entryCache (
ltRIPPLE_STATE, ltRIPPLE_STATE,
getRippleStateIndex ( getRippleStateIndex (
backNode.account_, backNode.account_,
@@ -295,7 +295,7 @@ TER PathState::pushNode (
<< backNode.account_ << " and " << node.account_ << backNode.account_ << " and " << node.account_
<< " for " << node.issue_.currency << "." ; << " for " << node.issue_.currency << "." ;
auto sleBck = lesEntries.entryCache ( auto sleBck = lesEntries_->entryCache (
ltACCOUNT_ROOT, ltACCOUNT_ROOT,
getAccountRootIndex (backNode.account_)); getAccountRootIndex (backNode.account_));
// Is the source account the highest numbered account ID? // Is the source account the highest numbered account ID?
@@ -323,13 +323,13 @@ TER PathState::pushNode (
if (resultCode == tesSUCCESS) if (resultCode == tesSUCCESS)
{ {
STAmount saOwed = creditBalance (lesEntries, STAmount saOwed = creditBalance (*lesEntries_,
node.account_, backNode.account_, node.account_, backNode.account_,
node.issue_.currency); node.issue_.currency);
STAmount saLimit; STAmount saLimit;
if (saOwed <= zero) { if (saOwed <= zero) {
saLimit = creditLimit (lesEntries, saLimit = creditLimit (*lesEntries_,
node.account_, node.account_,
backNode.account_, backNode.account_,
node.issue_.currency); node.issue_.currency);
@@ -437,7 +437,7 @@ TER PathState::expandPath (
WriteLog (lsTRACE, RippleCalc) WriteLog (lsTRACE, RippleCalc)
<< "expandPath> " << spSourcePath.getJson (0); << "expandPath> " << spSourcePath.getJson (0);
lesEntries = lesSource.duplicate (); lesEntries_.emplace(lesSource);
terStatus = tesSUCCESS; terStatus = tesSUCCESS;
@@ -632,7 +632,7 @@ void PathState::checkFreeze()
// Check each order book for a global freeze // Check each order book for a global freeze
if (nodes_[i].uFlags & STPathElement::typeIssuer) if (nodes_[i].uFlags & STPathElement::typeIssuer)
{ {
sle = lesEntries.entryCache (ltACCOUNT_ROOT, sle = lesEntries_->entryCache (ltACCOUNT_ROOT,
getAccountRootIndex (nodes_[i].issue_.account)); getAccountRootIndex (nodes_[i].issue_.account));
if (sle && sle->isFlag (lsfGlobalFreeze)) if (sle && sle->isFlag (lsfGlobalFreeze))
@@ -651,7 +651,7 @@ void PathState::checkFreeze()
if (inAccount != outAccount) if (inAccount != outAccount)
{ {
sle = lesEntries.entryCache (ltACCOUNT_ROOT, sle = lesEntries_->entryCache (ltACCOUNT_ROOT,
getAccountRootIndex (outAccount)); getAccountRootIndex (outAccount));
if (sle && sle->isFlag (lsfGlobalFreeze)) if (sle && sle->isFlag (lsfGlobalFreeze))
@@ -660,7 +660,7 @@ void PathState::checkFreeze()
return; return;
} }
sle = lesEntries.entryCache (ltRIPPLE_STATE, sle = lesEntries_->entryCache (ltRIPPLE_STATE,
getRippleStateIndex (inAccount, getRippleStateIndex (inAccount,
outAccount, currencyID)); outAccount, currencyID));
@@ -688,9 +688,9 @@ TER PathState::checkNoRipple (
Currency const& currency) Currency const& currency)
{ {
// fetch the ripple lines into and out of this node // fetch the ripple lines into and out of this node
SLE::pointer sleIn = lesEntries.entryCache (ltRIPPLE_STATE, SLE::pointer sleIn = lesEntries_->entryCache (ltRIPPLE_STATE,
getRippleStateIndex (firstAccount, secondAccount, currency)); getRippleStateIndex (firstAccount, secondAccount, currency));
SLE::pointer sleOut = lesEntries.entryCache (ltRIPPLE_STATE, SLE::pointer sleOut = lesEntries_->entryCache (ltRIPPLE_STATE,
getRippleStateIndex (secondAccount, thirdAccount, currency)); getRippleStateIndex (secondAccount, thirdAccount, currency));
if (!sleIn || !sleOut) if (!sleIn || !sleOut)

View File

@@ -23,6 +23,7 @@
#include <ripple/app/ledger/LedgerEntrySet.h> #include <ripple/app/ledger/LedgerEntrySet.h>
#include <ripple/app/paths/Node.h> #include <ripple/app/paths/Node.h>
#include <ripple/app/paths/Types.h> #include <ripple/app/paths/Types.h>
#include <boost/optional.hpp>
namespace ripple { namespace ripple {
@@ -102,7 +103,11 @@ class PathState : public CountedObject <PathState>
static bool lessPriority (PathState const& lhs, PathState const& rhs); static bool lessPriority (PathState const& lhs, PathState const& rhs);
LedgerEntrySet& ledgerEntries() { return lesEntries; } // VFALCO Remove or rename to view,
LedgerEntrySet& ledgerEntries()
{
return *lesEntries_;
}
bool isDry() const bool isDry() const
{ {
@@ -116,6 +121,19 @@ class PathState : public CountedObject <PathState>
/** Clear path structures, and clear each node. */ /** Clear path structures, and clear each node. */
void clear(); void clear();
TER pushNode (
int const iType,
Account const& account,
Currency const& currency,
Account const& issuer);
TER pushImpliedNodes (
Account const& account,
Currency const& currency,
Account const& issuer);
Json::Value getJson () const;
TER terStatus; TER terStatus;
path::Node::List nodes_; path::Node::List nodes_;
@@ -132,7 +150,7 @@ class PathState : public CountedObject <PathState>
// Source may only be used there if not mentioned by an account. // Source may only be used there if not mentioned by an account.
AccountIssueToNodeIndex umReverse; AccountIssueToNodeIndex umReverse;
LedgerEntrySet lesEntries; boost::optional<LedgerEntrySet> lesEntries_;
int mIndex; // Index/rank amoung siblings. int mIndex; // Index/rank amoung siblings.
std::uint64_t uQuality; // 0 = no quality/liquity left. std::uint64_t uQuality; // 0 = no quality/liquity left.
@@ -147,19 +165,6 @@ class PathState : public CountedObject <PathState>
// If true, all liquidity on this path has been consumed. // If true, all liquidity on this path has been consumed.
bool allLiquidityConsumed_ = false; bool allLiquidityConsumed_ = false;
TER pushNode (
int const iType,
Account const& account,
Currency const& currency,
Account const& issuer);
TER pushImpliedNodes (
Account const& account,
Currency const& currency,
Account const& issuer);
Json::Value getJson () const;
}; };
} // ripple } // ripple

View File

@@ -288,7 +288,9 @@ TER RippleCalc::rippleCalculate ()
assert (mActiveLedger.isValid ()); assert (mActiveLedger.isValid ());
mActiveLedger.swapWith (pathState->ledgerEntries()); mActiveLedger.swapWith (pathState->ledgerEntries());
// For the path, save ledger state. // For the path, save ledger state.
mActiveLedger.invalidate ();
// VFALCO Can this be done without the function call?
mActiveLedger.deprecatedInvalidate();
iBest = pathState->index (); iBest = pathState->index ();
} }
@@ -339,7 +341,10 @@ TER RippleCalc::rippleCalculate ()
// return. // return.
assert (pathState->ledgerEntries().isValid ()); assert (pathState->ledgerEntries().isValid ());
mActiveLedger.swapWith (pathState->ledgerEntries()); mActiveLedger.swapWith (pathState->ledgerEntries());
pathState->ledgerEntries().invalidate ();
// VFALCO Why is this needed? Can it be done
// without the function call?
pathState->ledgerEntries().deprecatedInvalidate();
actualAmountIn_ += pathState->inPass(); actualAmountIn_ += pathState->inPass();
actualAmountOut_ += pathState->outPass(); actualAmountOut_ += pathState->outPass();

View File

@@ -128,7 +128,7 @@ TER PathCursor::advanceNode (bool const bReverse) const
= node().sleOffer->getFieldAmount (sfTakerGets); = node().sleOffer->getFieldAmount (sfTakerGets);
// Funds left. // Funds left.
node().saOfferFunds = ledger().accountFunds ( node().saOfferFunds = funds (ledger(),
node().offerOwnerAccount_, node().offerOwnerAccount_,
node().saTakerGets, node().saTakerGets,
fhZERO_IF_FROZEN); fhZERO_IF_FROZEN);
@@ -329,7 +329,7 @@ TER PathCursor::advanceNode (bool const bReverse) const
// Only the current node is allowed to use the source. // Only the current node is allowed to use the source.
node().saOfferFunds = ledger().accountFunds ( node().saOfferFunds = funds(ledger(),
node().offerOwnerAccount_, node().offerOwnerAccount_,
node().saTakerGets, node().saTakerGets,
fhZERO_IF_FROZEN); fhZERO_IF_FROZEN);

View File

@@ -30,7 +30,9 @@ TER PathCursor::liquidity (LedgerEntrySet const& lesCheckpoint) const
TER resultCode = tecPATH_DRY; TER resultCode = tecPATH_DRY;
PathCursor pc = *this; PathCursor pc = *this;
ledger() = lesCheckpoint.duplicate (); // duplicate
reconstruct(rippleCalc_.mActiveLedger, lesCheckpoint);
for (pc.nodeIndex_ = pc.nodeSize(); pc.nodeIndex_--; ) for (pc.nodeIndex_ = pc.nodeSize(); pc.nodeIndex_--; )
{ {
WriteLog (lsTRACE, RippleCalc) WriteLog (lsTRACE, RippleCalc)
@@ -59,7 +61,9 @@ TER PathCursor::liquidity (LedgerEntrySet const& lesCheckpoint) const
return resultCode; return resultCode;
// Do forward. // Do forward.
ledger() = lesCheckpoint.duplicate (); // duplicate
reconstruct(rippleCalc_.mActiveLedger, lesCheckpoint);
for (pc.nodeIndex_ = 0; pc.nodeIndex_ < pc.nodeSize(); ++pc.nodeIndex_) for (pc.nodeIndex_ = 0; pc.nodeIndex_ < pc.nodeSize(); ++pc.nodeIndex_)
{ {
WriteLog (lsTRACE, RippleCalc) WriteLog (lsTRACE, RippleCalc)

View File

@@ -55,7 +55,8 @@ public:
private: private:
PathCursor(PathCursor const&) = default; PathCursor(PathCursor const&) = default;
PathCursor increment(int delta = 1) const { PathCursor increment(int delta = 1) const
{
return {rippleCalc_, pathState_, multiQuality_, nodeIndex_ + delta}; return {rippleCalc_, pathState_, multiQuality_, nodeIndex_ + delta};
} }
@@ -90,11 +91,6 @@ private:
STAmount& saInAct, STAmount& saInAct,
STAmount& saInFees) const; STAmount& saInFees) const;
RippleCalc& rippleCalc_;
PathState& pathState_;
bool multiQuality_;
NodeIndex nodeIndex_;
LedgerEntrySet& ledger() const LedgerEntrySet& ledger() const
{ {
return rippleCalc_.mActiveLedger; return rippleCalc_.mActiveLedger;
@@ -129,6 +125,11 @@ private:
{ {
return node (restrict (nodeIndex_ + 1)); return node (restrict (nodeIndex_ + 1));
} }
RippleCalc& rippleCalc_;
PathState& pathState_;
bool multiQuality_;
NodeIndex nodeIndex_;
}; };
} // path } // path

View File

@@ -46,7 +46,7 @@ class AccountInfo
private: private:
Account account_; Account account_;
std::shared_ptr<Ledger> ledger_; std::shared_ptr<Ledger> ledger_;
boost::optional<SLE const> root_; std::shared_ptr<SLE const> root_;
public: public:
AccountInfo(Account const& account, AccountInfo(Account const& account,

View File

@@ -22,6 +22,7 @@
#include <ripple/app/ledger/Ledger.h> #include <ripple/app/ledger/Ledger.h>
#include <ripple/app/ledger/LedgerEntrySet.h> #include <ripple/app/ledger/LedgerEntrySet.h>
#include <boost/optional.hpp>
#include <utility> #include <utility>
namespace ripple { namespace ripple {
@@ -35,11 +36,7 @@ static multisign_t const multisign;
// One instance per ledger. // One instance per ledger.
// Only one transaction applied at a time. // Only one transaction applied at a time.
class TransactionEngine class TransactionEngine
: public CountedObject <TransactionEngine>
{ {
public:
static char const* getCountedObjectName () { return "TransactionEngine"; }
private: private:
bool enableMultiSign_ = bool enableMultiSign_ =
#if RIPPLE_ENABLE_MULTI_SIGN #if RIPPLE_ENABLE_MULTI_SIGN
@@ -48,9 +45,7 @@ private:
false; false;
#endif #endif
LedgerEntrySet mNodes; boost::optional<LedgerEntrySet> mNodes;
void txnWrite ();
protected: protected:
Ledger::pointer mLedger; Ledger::pointer mLedger;
@@ -59,6 +54,7 @@ protected:
public: public:
TransactionEngine() = default; TransactionEngine() = default;
explicit
TransactionEngine (Ledger::ref ledger) TransactionEngine (Ledger::ref ledger)
: mLedger (ledger) : mLedger (ledger)
{ {
@@ -81,7 +77,7 @@ public:
LedgerEntrySet& LedgerEntrySet&
view () view ()
{ {
return mNodes; return *mNodes;
} }
Ledger::ref Ledger::ref

View File

@@ -52,9 +52,11 @@ public:
if (!sleTicket) if (!sleTicket)
return tecNO_ENTRY; return tecNO_ENTRY;
Account const ticket_owner (sleTicket->getFieldAccount160 (sfAccount)); auto const ticket_owner =
sleTicket->getFieldAccount160 (sfAccount);
bool authorized (mTxnAccountID == ticket_owner); bool authorized =
mTxnAccountID == ticket_owner;
// The target can also always remove a ticket // The target can also always remove a ticket
if (!authorized && sleTicket->isFieldPresent (sfTarget)) if (!authorized && sleTicket->isFieldPresent (sfTarget))
@@ -77,7 +79,8 @@ public:
TER const result = mEngine->view ().dirDelete (false, hint, TER const result = mEngine->view ().dirDelete (false, hint,
getOwnerDirIndex (ticket_owner), ticketId, false, (hint == 0)); getOwnerDirIndex (ticket_owner), ticketId, false, (hint == 0));
mEngine->view ().decrementOwnerCount (ticket_owner); adjustOwnerCount(mEngine->view(), mEngine->view().entryCache(
ltACCOUNT_ROOT, getAccountRootIndex(ticket_owner)), -1);
mEngine->view ().entryDelete (sleTicket); mEngine->view ().entryDelete (sleTicket);
return result; return result;

View File

@@ -122,15 +122,18 @@ private:
SLE::pointer amendmentObject (mEngine->view().entryCache (ltAMENDMENTS, index)); SLE::pointer amendmentObject (mEngine->view().entryCache (ltAMENDMENTS, index));
if (!amendmentObject) if (!amendmentObject)
amendmentObject = mEngine->view().entryCreate(ltAMENDMENTS, index); {
amendmentObject = std::make_shared<SLE>(
ltAMENDMENTS, index);
mEngine->view().entryCreate(amendmentObject);
}
STVector256 amendments (amendmentObject->getFieldV256 (sfAmendments)); STVector256 amendments =
amendmentObject->getFieldV256(sfAmendments);
if (std::find (amendments.begin(), amendments.end(), if (std::find (amendments.begin(), amendments.end(),
amendment) != amendments.end ()) amendment) != amendments.end ())
{
return tefALREADY; return tefALREADY;
}
amendments.push_back (amendment); amendments.push_back (amendment);
amendmentObject->setFieldV256 (sfAmendments, amendments); amendmentObject->setFieldV256 (sfAmendments, amendments);
@@ -151,7 +154,11 @@ private:
SLE::pointer feeObject = mEngine->view().entryCache (ltFEE_SETTINGS, index); SLE::pointer feeObject = mEngine->view().entryCache (ltFEE_SETTINGS, index);
if (!feeObject) if (!feeObject)
feeObject = mEngine->view().entryCreate (ltFEE_SETTINGS, index); {
feeObject = std::make_shared<SLE>(
ltFEE_SETTINGS, index);
mEngine->view().entryCreate(feeObject);
}
// VFALCO-FIXME this generates errors // VFALCO-FIXME this generates errors
// m_journal.trace << // m_journal.trace <<

View File

@@ -101,11 +101,9 @@ private:
{ {
if (offer.fully_consumed ()) if (offer.fully_consumed ())
return true; return true;
auto const amount = funds(view, offer.owner(),
auto const funds (view.accountFunds (offer.owner(), offer.amount().out, fhZERO_IF_FROZEN);
offer.amount().out, fhZERO_IF_FROZEN)); return (amount <= zero);
return (funds <= zero);
} }
static static
@@ -202,7 +200,7 @@ private:
m_journal.debug << " in: " << offers_direct.tip ().amount().in; m_journal.debug << " in: " << offers_direct.tip ().amount().in;
m_journal.debug << " out: " << offers_direct.tip ().amount ().out; m_journal.debug << " out: " << offers_direct.tip ().amount ().out;
m_journal.debug << " owner: " << offers_direct.tip ().owner (); m_journal.debug << " owner: " << offers_direct.tip ().owner ();
m_journal.debug << " funds: " << view.accountFunds ( m_journal.debug << " funds: " << funds(view,
offers_direct.tip ().owner (), offers_direct.tip ().owner (),
offers_direct.tip ().amount ().out, offers_direct.tip ().amount ().out,
fhIGNORE_FREEZE); fhIGNORE_FREEZE);
@@ -222,12 +220,12 @@ private:
{ {
if (m_journal.debug) if (m_journal.debug)
{ {
auto const owner1_funds_before = view.accountFunds ( auto const owner1_funds_before = funds(view,
offers_leg1.tip ().owner (), offers_leg1.tip ().owner (),
offers_leg1.tip ().amount ().out, offers_leg1.tip ().amount ().out,
fhIGNORE_FREEZE); fhIGNORE_FREEZE);
auto const owner2_funds_before = view.accountFunds ( auto const owner2_funds_before = funds(view,
offers_leg2.tip ().owner (), offers_leg2.tip ().owner (),
offers_leg2.tip ().amount ().out, offers_leg2.tip ().amount ().out,
fhIGNORE_FREEZE); fhIGNORE_FREEZE);
@@ -321,7 +319,7 @@ private:
m_journal.debug << " in: " << offer.amount ().in; m_journal.debug << " in: " << offer.amount ().in;
m_journal.debug << " out: " << offer.amount ().out; m_journal.debug << " out: " << offer.amount ().out;
m_journal.debug << " owner: " << offer.owner (); m_journal.debug << " owner: " << offer.owner ();
m_journal.debug << " funds: " << view.accountFunds ( m_journal.debug << " funds: " << funds(view,
offer.owner (), offer.amount ().out, fhIGNORE_FREEZE); offer.owner (), offer.amount ().out, fhIGNORE_FREEZE);
} }
@@ -604,7 +602,7 @@ public:
result = tecFROZEN; result = tecFROZEN;
} }
else if (view.accountFunds ( else if (funds(view,
mTxnAccountID, saTakerGets, fhZERO_IF_FROZEN) <= zero) mTxnAccountID, saTakerGets, fhZERO_IF_FROZEN) <= zero)
{ {
if (m_journal.debug) m_journal.debug << if (m_journal.debug) m_journal.debug <<
@@ -795,7 +793,7 @@ public:
if (result == tesSUCCESS) if (result == tesSUCCESS)
{ {
// Update owner count. // Update owner count.
view.incrementOwnerCount (sleCreator); adjustOwnerCount(view, sleCreator, 1);
if (m_journal.trace) m_journal.trace << if (m_journal.trace) m_journal.trace <<
"adding to book: " << to_string (saTakerPays.issue ()) << "adding to book: " << to_string (saTakerPays.issue ()) <<
@@ -818,8 +816,7 @@ public:
if (result == tesSUCCESS) if (result == tesSUCCESS)
{ {
SLE::pointer sleOffer (mEngine->view().entryCreate (ltOFFER, offer_index)); auto sleOffer = std::make_shared<SLE>(ltOFFER, offer_index);
sleOffer->setFieldAccount (sfAccount, mTxnAccountID); sleOffer->setFieldAccount (sfAccount, mTxnAccountID);
sleOffer->setFieldU32 (sfSequence, uSequence); sleOffer->setFieldU32 (sfSequence, uSequence);
sleOffer->setFieldH256 (sfBookDirectory, uDirectory); sleOffer->setFieldH256 (sfBookDirectory, uDirectory);
@@ -827,15 +824,13 @@ public:
sleOffer->setFieldAmount (sfTakerGets, saTakerGets); sleOffer->setFieldAmount (sfTakerGets, saTakerGets);
sleOffer->setFieldU64 (sfOwnerNode, uOwnerNode); sleOffer->setFieldU64 (sfOwnerNode, uOwnerNode);
sleOffer->setFieldU64 (sfBookNode, uBookNode); sleOffer->setFieldU64 (sfBookNode, uBookNode);
if (uExpiration) if (uExpiration)
sleOffer->setFieldU32 (sfExpiration, uExpiration); sleOffer->setFieldU32 (sfExpiration, uExpiration);
if (bPassive) if (bPassive)
sleOffer->setFlag (lsfPassive); sleOffer->setFlag (lsfPassive);
if (bSell) if (bSell)
sleOffer->setFlag (lsfSell); sleOffer->setFlag (lsfSell);
mEngine->view().entryCreate(sleOffer);
} }
if (result != tesSUCCESS) if (result != tesSUCCESS)

View File

@@ -85,14 +85,13 @@ public:
return tesSUCCESS; return tesSUCCESS;
} }
SLE::pointer sleTicket = mEngine->view().entryCreate (ltTICKET, SLE::pointer sleTicket = std::make_shared<SLE>(ltTICKET,
getTicketIndex (mTxnAccountID, mTxn.getSequence ())); getTicketIndex (mTxnAccountID, mTxn.getSequence ()));
sleTicket->setFieldAccount (sfAccount, mTxnAccountID); sleTicket->setFieldAccount (sfAccount, mTxnAccountID);
sleTicket->setFieldU32 (sfSequence, mTxn.getSequence ()); sleTicket->setFieldU32 (sfSequence, mTxn.getSequence ());
if (expiration != 0) if (expiration != 0)
sleTicket->setFieldU32 (sfExpiration, expiration); sleTicket->setFieldU32 (sfExpiration, expiration);
mEngine->view().entryCreate (sleTicket);
if (mTxn.isFieldPresent (sfTarget)) if (mTxn.isFieldPresent (sfTarget))
{ {
@@ -134,7 +133,7 @@ public:
sleTicket->setFieldU64(sfOwnerNode, hint); sleTicket->setFieldU64(sfOwnerNode, hint);
// If we succeeded, the new entry counts agains the creator's reserve. // If we succeeded, the new entry counts agains the creator's reserve.
mEngine->view ().incrementOwnerCount (mTxnAccount); adjustOwnerCount(mEngine->view(), mTxnAccount, 1);
return result; return result;
} }

View File

@@ -19,6 +19,7 @@
#include <BeastConfig.h> #include <BeastConfig.h>
#include <ripple/app/tx/LocalTxs.h> #include <ripple/app/tx/LocalTxs.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/misc/CanonicalTXSet.h> #include <ripple/app/misc/CanonicalTXSet.h>
#include <ripple/protocol/Indexes.h> #include <ripple/protocol/Indexes.h>
@@ -125,8 +126,9 @@ public:
return true; return true;
if (ledger->hasTransaction (txn.getID ())) if (ledger->hasTransaction (txn.getID ()))
return true; return true;
auto const sle = ledger->fetch( auto const sle = fetch(*ledger,
getAccountRootIndex(txn.getAccount())); getAccountRootIndex(txn.getAccount().getAccountID()),
getApp().getSLECache());
if (! sle) if (! sle)
return false; return false;
if (sle->getFieldU32 (sfSequence) > txn.getSeq ()) if (sle->getFieldU32 (sfSequence) > txn.getSeq ())

View File

@@ -122,8 +122,8 @@ OfferStream::step ()
// Calculate owner funds // Calculate owner funds
// NIKB NOTE The calling code also checks the funds, how expensive is // NIKB NOTE The calling code also checks the funds, how expensive is
// looking up the funds twice? // looking up the funds twice?
STAmount const owner_funds (view().accountFunds ( auto const owner_funds = funds(view(),
m_offer.owner(), amount.out, fhZERO_IF_FROZEN)); m_offer.owner(), amount.out, fhZERO_IF_FROZEN);
// Check for unfunded offer // Check for unfunded offer
if (owner_funds <= zero) if (owner_funds <= zero)
@@ -131,7 +131,7 @@ OfferStream::step ()
// If the owner's balance in the pristine view is the same, // If the owner's balance in the pristine view is the same,
// we haven't modified the balance and therefore the // we haven't modified the balance and therefore the
// offer is "found unfunded" versus "became unfunded" // offer is "found unfunded" versus "became unfunded"
auto const original_funds = view_cancel().accountFunds ( auto const original_funds = funds(view_cancel(),
m_offer.owner(), amount.out, fhZERO_IF_FROZEN); m_offer.owner(), amount.out, fhZERO_IF_FROZEN);
if (original_funds == owner_funds) if (original_funds == owner_funds)

View File

@@ -233,10 +233,11 @@ public:
} }
// Create the account. // Create the account.
auto const newIndex = getAccountRootIndex (uDstAccountID); sleDst = std::make_shared<SLE>(ltACCOUNT_ROOT,
sleDst = mEngine->view().entryCreate (ltACCOUNT_ROOT, newIndex); getAccountRootIndex (uDstAccountID));
sleDst->setFieldAccount (sfAccount, uDstAccountID); sleDst->setFieldAccount (sfAccount, uDstAccountID);
sleDst->setFieldU32 (sfSequence, 1); sleDst->setFieldU32 (sfSequence, 1);
mEngine->view().entryCreate(sleDst);
} }
else if ((sleDst->getFlags () & lsfRequireDestTag) && else if ((sleDst->getFlags () & lsfRequireDestTag) &&
!mTxn.isFieldPresent (sfDestinationTag)) !mTxn.isFieldPresent (sfDestinationTag))

View File

@@ -234,8 +234,8 @@ SetSignerList::replaceSignerList (uint256 const& index)
return tecINSUFFICIENT_RESERVE; return tecINSUFFICIENT_RESERVE;
// Everything's ducky. Add the ltSIGNER_LIST to the ledger. // Everything's ducky. Add the ltSIGNER_LIST to the ledger.
SLE::pointer signerList ( auto signerList = std::make_shared<SLE>(ltSIGNER_LIST, index);
mEngine->view().entryCreate (ltSIGNER_LIST, index)); mEngine->view().entryCreate (signerList);
writeSignersToLedger (signerList); writeSignersToLedger (signerList);
// Lambda for call to dirAdd. // Lambda for call to dirAdd.
@@ -259,7 +259,8 @@ SetSignerList::replaceSignerList (uint256 const& index)
signerList->setFieldU64 (sfOwnerNode, hint); signerList->setFieldU64 (sfOwnerNode, hint);
// If we succeeded, the new entry counts against the creator's reserve. // If we succeeded, the new entry counts against the creator's reserve.
mEngine->view ().increaseOwnerCount (mTxnAccount, addedOwnerCount); adjustOwnerCount(mEngine->view(),
mTxnAccount, addedOwnerCount);
return result; return result;
} }
@@ -295,13 +296,17 @@ SetSignerList::destroySignerList (uint256 const& index)
getOwnerDirIndex (mTxnAccountID), index, false, (hint == 0)); getOwnerDirIndex (mTxnAccountID), index, false, (hint == 0));
if (result == tesSUCCESS) if (result == tesSUCCESS)
mEngine->view ().decreaseOwnerCount (mTxnAccount, removeFromOwnerCount); adjustOwnerCount(mEngine->view(),
mTxnAccount, removeFromOwnerCount);
mEngine->view ().entryDelete (signerList); mEngine->view ().entryDelete (signerList);
return result; return result;
} }
// VFALCO NOTE This name is misleading, the signers
// are not written to the ledger they are
// added to the SLE.
void void
SetSignerList::writeSignersToLedger (SLE::pointer ledgerEntry) SetSignerList::writeSignersToLedger (SLE::pointer ledgerEntry)
{ {

View File

@@ -339,7 +339,8 @@ public:
if (bLowReserveSet && !bLowReserved) if (bLowReserveSet && !bLowReserved)
{ {
// Set reserve for low account. // Set reserve for low account.
mEngine->view ().incrementOwnerCount (sleLowAccount); adjustOwnerCount(mEngine->view(),
sleLowAccount, 1);
uFlagsOut |= lsfLowReserve; uFlagsOut |= lsfLowReserve;
if (!bHigh) if (!bHigh)
@@ -349,14 +350,16 @@ public:
if (bLowReserveClear && bLowReserved) if (bLowReserveClear && bLowReserved)
{ {
// Clear reserve for low account. // Clear reserve for low account.
mEngine->view ().decrementOwnerCount (sleLowAccount); adjustOwnerCount(mEngine->view(),
sleLowAccount, -1);
uFlagsOut &= ~lsfLowReserve; uFlagsOut &= ~lsfLowReserve;
} }
if (bHighReserveSet && !bHighReserved) if (bHighReserveSet && !bHighReserved)
{ {
// Set reserve for high account. // Set reserve for high account.
mEngine->view ().incrementOwnerCount (sleHighAccount); adjustOwnerCount(mEngine->view(),
sleHighAccount, 1);
uFlagsOut |= lsfHighReserve; uFlagsOut |= lsfHighReserve;
if (bHigh) if (bHigh)
@@ -366,7 +369,8 @@ public:
if (bHighReserveClear && bHighReserved) if (bHighReserveClear && bHighReserved)
{ {
// Clear reserve for high account. // Clear reserve for high account.
mEngine->view ().decrementOwnerCount (sleHighAccount); adjustOwnerCount(mEngine->view(),
sleHighAccount, -1);
uFlagsOut &= ~lsfHighReserve; uFlagsOut &= ~lsfHighReserve;
} }

View File

@@ -581,9 +581,9 @@ Taker::consume_offer (Offer const& offer, Amounts const& order)
} }
STAmount STAmount
Taker::get_funds (Account const& account, STAmount const& funds) const Taker::get_funds (Account const& account, STAmount const& amount) const
{ {
return view_.accountFunds (account, funds, fhZERO_IF_FROZEN); return funds(view_, account, amount, fhZERO_IF_FROZEN);
} }
TER Taker::transfer_xrp ( TER Taker::transfer_xrp (

View File

@@ -31,53 +31,6 @@ namespace ripple {
// XXX Make sure all fields are recognized in transactions. // XXX Make sure all fields are recognized in transactions.
// //
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)
{
case taaNONE:
assert (false);
break;
case taaCACHED:
break;
case taaCREATE:
{
// VFALCO Is this logging necessary anymore?
WriteLog (lsDEBUG, TransactionEngine) <<
"applyTransaction: taaCREATE: " << sleEntry->getText ();
mLedger->insert(*sleEntry);
}
break;
case taaMODIFY:
{
WriteLog (lsDEBUG, TransactionEngine) <<
"applyTransaction: taaMODIFY: " << sleEntry->getText ();
mLedger->replace(*sleEntry);
}
break;
case taaDELETE:
{
WriteLog (lsDEBUG, TransactionEngine) <<
"applyTransaction: taaDELETE: " << sleEntry->getText ();
mLedger->erase(it.first);
}
break;
}
}
}
std::pair<TER, bool> std::pair<TER, bool>
TransactionEngine::applyTransaction ( TransactionEngine::applyTransaction (
STTx const& txn, STTx const& txn,
@@ -96,7 +49,8 @@ TransactionEngine::applyTransaction (
return std::make_pair(temINVALID_FLAG, false); return std::make_pair(temINVALID_FLAG, false);
} }
mNodes.init (mLedger, txID, mLedger->getLedgerSeq (), params); mNodes.emplace(mLedger, txID,
mLedger->getLedgerSeq(), params);
#ifdef BEAST_DEBUG #ifdef BEAST_DEBUG
if (1) if (1)
@@ -146,9 +100,10 @@ TransactionEngine::applyTransaction (
// only claim the transaction fee // only claim the transaction fee
WriteLog (lsDEBUG, TransactionEngine) << WriteLog (lsDEBUG, TransactionEngine) <<
"Reprocessing tx " << txID << " to only claim fee"; "Reprocessing tx " << txID << " to only claim fee";
mNodes.clear (); mNodes.emplace(mLedger, txID,
mLedger->getLedgerSeq(), params);
SLE::pointer txnAcct = mNodes.entryCache (ltACCOUNT_ROOT, SLE::pointer txnAcct = mNodes->entryCache (ltACCOUNT_ROOT,
getAccountRootIndex (txn.getSourceAccount ())); getAccountRootIndex (txn.getSourceAccount ()));
if (!txnAcct) if (!txnAcct)
@@ -182,7 +137,7 @@ TransactionEngine::applyTransaction (
fee = balance; fee = balance;
txnAcct->setFieldAmount (sfBalance, balance - fee); txnAcct->setFieldAmount (sfBalance, balance - fee);
txnAcct->setFieldU32 (sfSequence, t_seq + 1); txnAcct->setFieldU32 (sfSequence, t_seq + 1);
mNodes.entryModify (txnAcct); mNodes->entryModify (txnAcct);
didApply = true; didApply = true;
} }
} }
@@ -202,7 +157,7 @@ TransactionEngine::applyTransaction (
WriteLog (lsFATAL, TransactionEngine) << WriteLog (lsFATAL, TransactionEngine) <<
transToken (terResult) << ": " << transHuman (terResult); transToken (terResult) << ": " << transHuman (terResult);
WriteLog (lsFATAL, TransactionEngine) << WriteLog (lsFATAL, TransactionEngine) <<
mNodes.getJson (0); mNodes->getJson (0);
didApply = false; didApply = false;
terResult = tefINTERNAL; terResult = tefINTERNAL;
} }
@@ -212,9 +167,10 @@ TransactionEngine::applyTransaction (
// Transaction succeeded fully or (retries are not allowed and the // Transaction succeeded fully or (retries are not allowed and the
// transaction could claim a fee) // transaction could claim a fee)
Serializer m; Serializer m;
mNodes.calcRawMeta (m, terResult, mTxnSeq++); mNodes->calcRawMeta (m, terResult, mTxnSeq++);
txnWrite (); assert(mLedger == mNodes->getLedger());
mNodes->apply();
Serializer s; Serializer s;
txn.add (s); txn.add (s);
@@ -253,7 +209,7 @@ TransactionEngine::applyTransaction (
} }
} }
mNodes.clear (); mNodes = boost::none;
if (!(params & tapOPEN_LEDGER) && isTemMalformed (terResult)) if (!(params & tapOPEN_LEDGER) && isTemMalformed (terResult))
{ {

View File

@@ -21,11 +21,13 @@
#define RIPPLE_PROTOCOL_INDEXES_H_INCLUDED #define RIPPLE_PROTOCOL_INDEXES_H_INCLUDED
#include <ripple/protocol/LedgerFormats.h> #include <ripple/protocol/LedgerFormats.h>
#include <ripple/protocol/Protocol.h>
#include <ripple/protocol/RippleAddress.h> #include <ripple/protocol/RippleAddress.h>
#include <ripple/protocol/Serializer.h> #include <ripple/protocol/Serializer.h>
#include <ripple/protocol/UintTypes.h> #include <ripple/protocol/UintTypes.h>
#include <ripple/basics/base_uint.h> #include <ripple/basics/base_uint.h>
#include <ripple/protocol/Book.h> #include <ripple/protocol/Book.h>
#include <cstdint>
namespace ripple { namespace ripple {
@@ -89,6 +91,137 @@ getRippleStateIndex (Account const& a, Issue const& issue);
uint256 uint256
getSignerListIndex (Account const& account); getSignerListIndex (Account const& account);
//------------------------------------------------------------------------------
/** A pair of SHAMap key and LedgerEntryType.
A Keylet identifies both a key in the state map
and its ledger entry type.
*/
struct Keylet
{
LedgerEntryType type;
uint256 key;
Keylet (LedgerEntryType type_,
uint256 const& key_)
: type(type_)
, key(key_)
{
}
};
/** Keylet computation funclets. */
namespace keylet {
/** Account root */
struct account_t
{
Keylet operator()(Account const& id) const;
// DEPRECATED
Keylet operator()(RippleAddress const& ra) const;
};
static account_t const account {};
/** OWner directory */
struct owndir_t
{
Keylet operator()(Account const& id) const;
};
static owndir_t const ownerDir {};
/** Skip list */
struct skip_t
{
Keylet operator()() const;
Keylet operator()(LedgerIndex ledger) const;
};
static skip_t const skip {};
/** The amendment table */
struct amendments_t
{
Keylet operator()() const;
};
static amendments_t const amendments {};
/** The ledger fees */
struct fee_t
{
Keylet operator()() const;
};
static fee_t const fee {};
/** The beginning of an order book */
struct book_t
{
Keylet operator()(Book const& b) const;
};
static book_t const book {};
/** An offer from an account */
struct offer_t
{
Keylet operator()(Account const& id,
std::uint32_t seq) const;
};
static offer_t const offer {};
/** An item in a directory */
struct item_t
{
Keylet operator()(Keylet const& k,
std::uint64_t index,
LedgerEntryType type) const;
};
static item_t const item {};
/** The directory for a specific quality */
struct quality_t
{
Keylet operator()(Keylet const& k,
std::uint64_t q) const;
};
static quality_t const quality {};
/** The directry for the next lower quality */
struct next_t
{
Keylet operator()(Keylet const& k) const;
};
static next_t const next {};
/** A ticket belonging to an account */
struct ticket_t
{
Keylet operator()(Account const& id,
std::uint32_t seq) const;
};
static ticket_t const ticket {};
/** A trust line */
struct trust_t
{
Keylet operator()(Account const& id0,
Account const& id1, Currency const& currency) const;
Keylet operator()(Account const& id,
Issue const& issue) const;
};
static trust_t const trust {};
/** A SignerList */
struct signers_t
{
Keylet operator()(Account const& id) const;
};
static signers_t const signers {};
} // keylet
} }
#endif #endif

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED #ifndef RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED
#define RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED #define RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED
#include <ripple/protocol/LedgerFormats.h> #include <ripple/protocol/Indexes.h>
#include <ripple/protocol/STObject.h> #include <ripple/protocol/STObject.h>
namespace ripple { namespace ripple {
@@ -35,10 +35,21 @@ public:
using pointer = std::shared_ptr<STLedgerEntry>; using pointer = std::shared_ptr<STLedgerEntry>;
using ref = const std::shared_ptr<STLedgerEntry>&; using ref = const std::shared_ptr<STLedgerEntry>&;
public: /** Create an empty object with the given key and type. */
explicit
STLedgerEntry (Keylet const& k);
STLedgerEntry (LedgerEntryType type,
uint256 const& key)
: STLedgerEntry(Keylet(type, key))
{
}
STLedgerEntry (const Serializer & s, uint256 const& index); STLedgerEntry (const Serializer & s, uint256 const& index);
STLedgerEntry (SerialIter & sit, uint256 const& index); STLedgerEntry (SerialIter & sit, uint256 const& index);
STLedgerEntry (LedgerEntryType type, uint256 const& index);
STLedgerEntry (const STObject & object, uint256 const& index); STLedgerEntry (const STObject & object, uint256 const& index);
STBase* STBase*
@@ -57,67 +68,79 @@ public:
{ {
return STI_LEDGERENTRY; return STI_LEDGERENTRY;
} }
std::string getFullText () const override; std::string getFullText () const override;
std::string getText () const override; std::string getText () const override;
Json::Value getJson (int options) const override; Json::Value getJson (int options) const override;
/** Returns the 'key' (or 'index') of this item. /** Returns the 'key' (or 'index') of this item.
The key identifies this entry's position in The key identifies this entry's position in
the SHAMap associative container. the SHAMap associative container.
*/ */
uint256 const&
key() const
{
return key_;
}
// DEPRECATED
uint256 const& getIndex () const uint256 const& getIndex () const
{ {
return mIndex; return key_;
}
void setIndex (uint256 const& i)
{
mIndex = i;
} }
void setImmutable () void setImmutable ()
{ {
mMutable = false; mMutable = false;
} }
bool isMutable () bool isMutable ()
{ {
return mMutable; return mMutable;
} }
STLedgerEntry::pointer getMutable () const;
LedgerEntryType getType () const LedgerEntryType getType () const
{ {
return mType; return type_;
} }
std::uint16_t getVersion () const std::uint16_t getVersion () const
{ {
return getFieldU16 (sfLedgerEntryType); return getFieldU16 (sfLedgerEntryType);
} }
LedgerFormats::Item const* getFormat ()
{
return mFormat;
}
bool isThreadedType() const; // is this a ledger entry that can be threaded bool isThreadedType() const; // is this a ledger entry that can be threaded
bool isThreaded () const; // is this ledger entry actually threaded bool isThreaded () const; // is this ledger entry actually threaded
bool hasOneOwner () const; // This node has one other node that owns it 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) bool hasTwoOwners () const; // This node has two nodes that own it (like ripple balance)
RippleAddress getOwner () const; RippleAddress getOwner () const;
RippleAddress getFirstOwner () const; RippleAddress getFirstOwner () const;
RippleAddress getSecondOwner () const; RippleAddress getSecondOwner () const;
uint256 getThreadedTransaction () const; uint256 getThreadedTransaction () const;
std::uint32_t getThreadedLedger () const; std::uint32_t getThreadedLedger () const;
bool thread (uint256 const& txID, std::uint32_t ledgerSeq, uint256 & prevTxID, bool thread (uint256 const& txID, std::uint32_t ledgerSeq, uint256 & prevTxID,
std::uint32_t & prevLedgerID); std::uint32_t & prevLedgerID);
private: private:
/** Make STObject comply with the template for this SLE type /* Make STObject comply with the template for this SLE type
Can throw Can throw
*/ */
void setSLEType (); void setSLEType ();
private: private:
uint256 mIndex; uint256 key_;
LedgerEntryType mType; LedgerEntryType type_;
LedgerFormats::Item const* mFormat; LedgerFormats::Item const* mFormat;
bool mMutable; bool mMutable;
}; };

View File

@@ -21,6 +21,7 @@
#include <ripple/basics/SHA512Half.h> #include <ripple/basics/SHA512Half.h>
#include <ripple/protocol/Indexes.h> #include <ripple/protocol/Indexes.h>
#include <beast/utility/static_initializer.h> #include <beast/utility/static_initializer.h>
#include <cassert>
namespace ripple { namespace ripple {
@@ -192,4 +193,118 @@ getSignerListIndex (Account const& account)
account); account);
} }
//------------------------------------------------------------------------------
namespace keylet {
Keylet account_t::operator()(
Account const& id) const
{
return { ltACCOUNT_ROOT,
getAccountRootIndex(id) };
}
Keylet account_t::operator()(
RippleAddress const& ra) const
{
return { ltACCOUNT_ROOT,
getAccountRootIndex(ra.getAccountID()) };
}
Keylet owndir_t::operator()(
Account const& id) const
{
return { ltDIR_NODE,
getOwnerDirIndex(id) };
}
Keylet skip_t::operator()() const
{
return { ltLEDGER_HASHES,
getLedgerHashIndex() };
}
Keylet skip_t::operator()(LedgerIndex ledger) const
{
return { ltLEDGER_HASHES,
getLedgerHashIndex(ledger) };
}
Keylet amendments_t::operator()() const
{
return { ltAMENDMENTS,
getLedgerAmendmentIndex() };
}
Keylet fee_t::operator()() const
{
return { ltFEE_SETTINGS,
getLedgerFeeIndex() };
}
Keylet book_t::operator()(Book const& b) const
{
return { ltDIR_NODE,
getBookBase(b) };
}
Keylet offer_t::operator()(Account const& id,
std::uint32_t seq) const
{
return { ltOFFER,
getOfferIndex(id, seq) };
}
Keylet item_t::operator()(Keylet const& k,
std::uint64_t index,
LedgerEntryType type) const
{
return { type,
getDirNodeIndex(k.key, index) };
}
Keylet quality_t::operator()(Keylet const& k,
std::uint64_t q) const
{
assert(k.type == ltDIR_NODE);
return { ltDIR_NODE,
getQualityIndex(k.key, q) };
}
Keylet next_t::operator()(Keylet const& k) const
{
assert(k.type == ltDIR_NODE);
return { ltDIR_NODE,
getQualityNext(k.key) };
}
Keylet ticket_t::operator()(Account const& id,
std::uint32_t seq) const
{
return { ltTICKET,
getTicketIndex(id, seq) };
}
Keylet trust_t::operator()(Account const& id0,
Account const& id1, Currency const& currency) const
{
return { ltRIPPLE_STATE,
getRippleStateIndex(id0, id1, currency) };
}
Keylet trust_t::operator()(Account const& id,
Issue const& issue) const
{
return { ltRIPPLE_STATE,
getRippleStateIndex(id, issue) };
}
Keylet signers_t::operator()(Account const& id) const
{
return { ltSIGNER_LIST,
getSignerListIndex(id) };
}
} // keylet
} // ripple } // ripple

View File

@@ -28,9 +28,24 @@
namespace ripple { namespace ripple {
STLedgerEntry::STLedgerEntry (Keylet const& k)
: STObject(sfLedgerEntry)
, key_ (k.key)
, type_ (k.type)
, mMutable (true)
{
mFormat =
LedgerFormats::getInstance().findByType (type_);
if (mFormat == nullptr)
throw std::runtime_error ("invalid ledger entry type");
set (mFormat->elements);
setFieldU16 (sfLedgerEntryType,
static_cast <std::uint16_t> (mFormat->getType ()));
}
STLedgerEntry::STLedgerEntry ( STLedgerEntry::STLedgerEntry (
SerialIter& sit, uint256 const& index) SerialIter& sit, uint256 const& index)
: STObject (sfLedgerEntry), mIndex (index), mMutable (true) : STObject (sfLedgerEntry), key_ (index), mMutable (true)
{ {
set (sit); set (sit);
setSLEType (); setSLEType ();
@@ -38,7 +53,7 @@ STLedgerEntry::STLedgerEntry (
STLedgerEntry::STLedgerEntry ( STLedgerEntry::STLedgerEntry (
const Serializer& s, uint256 const& index) const Serializer& s, uint256 const& index)
: STObject (sfLedgerEntry), mIndex (index), mMutable (true) : STObject (sfLedgerEntry), key_ (index), mMutable (true)
{ {
SerialIter sit (s.slice()); SerialIter sit (s.slice());
set (sit); set (sit);
@@ -47,7 +62,7 @@ STLedgerEntry::STLedgerEntry (
STLedgerEntry::STLedgerEntry ( STLedgerEntry::STLedgerEntry (
const STObject & object, uint256 const& index) const STObject & object, uint256 const& index)
: STObject (object), mIndex(index), mMutable (true) : STObject (object), key_(index), mMutable (true)
{ {
setSLEType (); setSLEType ();
} }
@@ -60,7 +75,7 @@ void STLedgerEntry::setSLEType ()
if (mFormat == nullptr) if (mFormat == nullptr)
throw std::runtime_error ("invalid ledger entry type"); throw std::runtime_error ("invalid ledger entry type");
mType = mFormat->getType (); type_ = mFormat->getType ();
if (!setType (mFormat->elements)) if (!setType (mFormat->elements))
{ {
WriteLog (lsWARNING, SerializedLedger) WriteLog (lsWARNING, SerializedLedger)
@@ -70,30 +85,10 @@ void STLedgerEntry::setSLEType ()
} }
} }
STLedgerEntry::STLedgerEntry (LedgerEntryType type, uint256 const& index) :
STObject (sfLedgerEntry), mIndex (index), mType (type), mMutable (true)
{
mFormat = LedgerFormats::getInstance().findByType (type);
if (mFormat == nullptr)
throw std::runtime_error ("invalid ledger entry type");
set (mFormat->elements);
setFieldU16 (sfLedgerEntryType,
static_cast <std::uint16_t> (mFormat->getType ()));
}
STLedgerEntry::pointer STLedgerEntry::getMutable () const
{
STLedgerEntry::pointer ret = std::make_shared<STLedgerEntry> (std::cref (*this));
ret->mMutable = true;
return ret;
}
std::string STLedgerEntry::getFullText () const std::string STLedgerEntry::getFullText () const
{ {
std::string ret = "\""; std::string ret = "\"";
ret += to_string (mIndex); ret += to_string (key_);
ret += "\" = { "; ret += "\" = { ";
ret += mFormat->getName (); ret += mFormat->getName ();
ret += ", "; ret += ", ";
@@ -105,7 +100,7 @@ std::string STLedgerEntry::getFullText () const
std::string STLedgerEntry::getText () const std::string STLedgerEntry::getText () const
{ {
return str (boost::format ("{ %s, %s }") return str (boost::format ("{ %s, %s }")
% to_string (mIndex) % to_string (key_)
% STObject::getText ()); % STObject::getText ());
} }
@@ -113,7 +108,7 @@ Json::Value STLedgerEntry::getJson (int options) const
{ {
Json::Value ret (STObject::getJson (options)); Json::Value ret (STObject::getJson (options));
ret[jss::index] = to_string (mIndex); ret[jss::index] = to_string (key_);
return ret; return ret;
} }
@@ -130,12 +125,12 @@ bool STLedgerEntry::isThreaded () const
bool STLedgerEntry::hasOneOwner () const bool STLedgerEntry::hasOneOwner () const
{ {
return (mType != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1); return (type_ != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1);
} }
bool STLedgerEntry::hasTwoOwners () const bool STLedgerEntry::hasTwoOwners () const
{ {
return mType == ltRIPPLE_STATE; return type_ == ltRIPPLE_STATE;
} }
RippleAddress STLedgerEntry::getOwner () const RippleAddress STLedgerEntry::getOwner () const

View File

@@ -306,7 +306,7 @@ ripplePathFind(RippleLineCache::pointer const& cache,
<< "Trying with an extra path element"; << "Trying with an extra path element";
spsComputed.push_back(fullLiquidityPath); spsComputed.push_back(fullLiquidityPath);
lesSandbox.clear(); reconstruct(lesSandbox, lpLedger, tapNONE);
rc = path::RippleCalc::rippleCalculate( rc = path::RippleCalc::rippleCalculate(
lesSandbox, lesSandbox,
saMaxAmount, // --> Amount to send is unlimited saMaxAmount, // --> Amount to send is unlimited