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)
{
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 ();
}

View File

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

View File

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

View File

@@ -34,31 +34,76 @@ namespace ripple {
// VFALCO TODO Replace this macro with a documented language constant
// NOTE Is this part of the protocol?
//
#define DIR_NODE_MAX 32
#define DIR_NODE_MAX 32
void LedgerEntrySet::init (Ledger::ref ledger, uint256 const& transactionID,
std::uint32_t ledgerID, TransactionEngineParams params)
LedgerEntrySet::LedgerEntrySet (LedgerEntrySet const& other)
: 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);
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)
@@ -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.
// 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);
@@ -87,7 +132,7 @@ SLE::pointer LedgerEntrySet::getEntry (uint256 const& index, LedgerEntryAction&
if (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;
}
@@ -95,26 +140,15 @@ SLE::pointer LedgerEntrySet::getEntry (uint256 const& index, LedgerEntryAction&
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)
{
assert(key.isNonZero ());
assert (mLedger);
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 ())
{
LedgerEntryAction action;
Action action;
sle = getEntry (key, action);
if (! sle)
@@ -128,10 +162,7 @@ SLE::pointer LedgerEntrySet::entryCache (LedgerEntryType letType, uint256 const&
}
else
{
auto maybe_sle = mLedger->fetch(key, letType);
if (maybe_sle)
sle = std::make_shared<SLE>(
std::move(*maybe_sle));
sle = mLedger->fetch(key, letType);
}
if (sle)
@@ -160,7 +191,7 @@ void LedgerEntrySet::entryCache (SLE::ref sle)
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;
}
@@ -185,7 +216,7 @@ void LedgerEntrySet::entryCreate (SLE::ref sle)
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;
}
@@ -223,7 +254,7 @@ void LedgerEntrySet::entryModify (SLE::ref sle)
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;
}
@@ -260,7 +291,7 @@ void LedgerEntrySet::entryDelete (SLE::ref sle)
if (it == mEntries.end ())
{
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;
}
@@ -379,7 +410,8 @@ SLE::pointer LedgerEntrySet::getForMod (uint256 const& node, Ledger::ref ledger,
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;
}
@@ -395,15 +427,10 @@ SLE::pointer LedgerEntrySet::getForMod (uint256 const& node, Ledger::ref ledger,
}
auto sle = ledger->fetch(node);
if (sle)
{
auto p = std::make_shared<SLE>(
std::move(*sle));
newMods.insert (std::make_pair (node, p));
return p;
}
return {};
if (! sle)
return nullptr;
newMods.insert (std::make_pair (node, sle));
return sle;
}
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);
}
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)
{
std::uint64_t uNodeDir = 0;
@@ -679,10 +676,10 @@ TER LedgerEntrySet::dirAdd (
if (!sleRoot)
{
// No root, make it.
sleRoot = entryCreate (ltDIR_NODE, uRootIndex);
sleRoot = std::make_shared<SLE>(ltDIR_NODE, uRootIndex);
sleRoot->setFieldH256 (sfRootIndex, uRootIndex);
entryCreate (sleRoot);
fDescriber (sleRoot, true);
sleNode = sleRoot;
uNodeDir = 0;
}
@@ -726,8 +723,10 @@ TER LedgerEntrySet::dirAdd (
entryModify (sleRoot);
// 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);
entryCreate (sleNode);
if (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
uint256 ledgerNext = uHash;
std::map<uint256, LedgerEntrySetEntry>::const_iterator it;
std::map<uint256, Item>::const_iterator it;
do
{
@@ -1113,69 +1112,6 @@ uint256 LedgerEntrySet::getNextLedgerIndex (
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)
{
if (!sleOffer)
@@ -1197,7 +1133,8 @@ TER LedgerEntrySet::offerDelete (SLE::pointer sleOffer)
false, uBookNode, uDirectory, offerIndex, true, false);
if (tesSUCCESS == terResult)
decrementOwnerCount (owner);
adjustOwnerCount(*this, entryCache(ltACCOUNT_ROOT,
getAccountRootIndex(owner)), -1);
entryDelete (sleOffer);
@@ -1333,43 +1270,6 @@ bool LedgerEntrySet::isFrozen(
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 (
const bool bSrcHigh,
Account const& uSrcAccountID,
@@ -1393,7 +1293,9 @@ TER LedgerEntrySet::trustCreate (
auto const& uLowAccountID = !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 uHighNode;
@@ -1469,7 +1371,7 @@ TER LedgerEntrySet::trustCreate (
}
sleRippleState->setFieldU32 (sfFlags, uFlags);
incrementOwnerCount (sleAccount);
adjustOwnerCount(*this, sleAccount, 1);
// ONLY: Create ripple balance.
sleRippleState->setFieldAmount (sfBalance, bSetHigh ? -saBalance : saBalance);
@@ -1659,7 +1561,8 @@ TER LedgerEntrySet::rippleCredit (
// Sender quality out is 0.
{
// Clear the reserve of the sender, possibly delete the line!
decrementOwnerCount (uSenderID);
adjustOwnerCount(*this, entryCache(ltACCOUNT_ROOT,
getAccountRootIndex(uSenderID)), -1);
// Clear reserve flag.
sleRippleState->setFieldU32 (
@@ -1881,9 +1784,9 @@ bool LedgerEntrySet::checkState (
{
std::uint32_t const flags (state->getFieldU32 (sfFlags));
auto sender_account = entryCache (ltACCOUNT_ROOT,
auto sle = entryCache (ltACCOUNT_ROOT,
getAccountRootIndex (sender));
assert (sender_account);
assert (sle);
// YYY Could skip this if rippling in reverse.
if (before > zero
@@ -1893,7 +1796,7 @@ bool LedgerEntrySet::checkState (
&& (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
// Sender reserve is set.
&& static_cast <bool> (flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
static_cast <bool> (sender_account->getFlags() & lsfDefaultRipple)
static_cast <bool> (sle->getFlags() & lsfDefaultRipple)
&& !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze))
&& !state->getFieldAmount (
!bSenderHigh ? sfLowLimit : sfHighLimit)
@@ -1905,8 +1808,9 @@ bool LedgerEntrySet::checkState (
!bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
// Sender quality out is 0.
{
// VFALCO Where is the line being deleted?
// Clear the reserve of the sender, possibly delete the line!
decrementOwnerCount (sender_account);
adjustOwnerCount(*this, sle, -1);
// Clear reserve flag.
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

View File

@@ -24,7 +24,9 @@
#include <ripple/app/ledger/DeferredCredits.h>
#include <ripple/basics/CountedObject.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <beast/utility/noexcept.h>
#include <boost/optional.hpp>
#include <utility>
namespace ripple {
@@ -50,39 +52,12 @@ enum TransactionEngineParams
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
{
fhIGNORE_FREEZE,
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.
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
the modifications. The transaction metadata is built from the LES too.
*/
/** @{ */
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:
int mSeq;
Action mAction;
std::shared_ptr<SLE> mEntry;
Item (SLE::ref e, Action a, int s)
: mSeq (s)
, mAction (a)
, mEntry (e)
{
}
};
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;
public:
static char const* getCountedObjectName () { return "LedgerEntrySet"; }
LedgerEntrySet& operator= (LedgerEntrySet const&) = delete;
LedgerEntrySet (
Ledger::ref ledger, TransactionEngineParams tep, bool immutable = false)
: mLedger (ledger), mParams (tep), mSeq (0), mImmutable (immutable)
{
}
/** Construct a copy.
Effects:
The copy is identical except that
the sequence number is one higher.
*/
LedgerEntrySet (LedgerEntrySet const&);
LedgerEntrySet () : mParams (tapNONE), mSeq (0), mImmutable (false)
{
}
LedgerEntrySet (Ledger::ref ledger,
uint256 const& transactionID,
std::uint32_t ledgerID,
TransactionEngineParams params);
// Make a duplicate of this set.
LedgerEntrySet duplicate () const;
LedgerEntrySet (Ledger::ref ledger,
TransactionEngineParams tep,
bool immutable = false);
/** Apply changes to the backing ledger. */
void
apply();
// Swap the contents of two sets
void swapWith (LedgerEntrySet&);
void invalidate ()
// VFALCO Only called from RippleCalc.cpp
void deprecatedInvalidate()
{
mLedger.reset ();
mDeferredCredits.reset ();
@@ -135,26 +153,17 @@ public:
++mSeq;
}
void init (Ledger::ref ledger, uint256 const& transactionID,
std::uint32_t ledgerID, TransactionEngineParams params);
void clear ();
Ledger::pointer& getLedger ()
{
return mLedger;
}
// basic entry functions
SLE::pointer getEntry (uint256 const& index, LedgerEntryAction&);
void entryCache (SLE::ref); // Add this entry to the cache
void entryCreate (SLE::ref); // This entry will be created
void entryDelete (SLE::ref); // This entry will be deleted
void entryModify (SLE::ref); // This entry will be modified
// higher-level ledger functions
SLE::pointer entryCreate (LedgerEntryType letType, uint256 const& uIndex);
SLE::pointer entryCache (LedgerEntryType letType, uint256 const& key);
std::shared_ptr<SLE const>
@@ -177,35 +186,24 @@ public:
bool dirFirst (uint256 const& uRootIndex, SLE::pointer& sleNode,
unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirFirst (uint256 const& uRootIndex, std::shared_ptr<SLE const>& 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<SLE const>& 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);
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.
TER offerDelete (SLE::pointer);
TER offerDelete (uint256 const& offerIndex)
{
return offerDelete( entryCache (ltOFFER, offerIndex));
@@ -220,6 +218,7 @@ public:
bool isGlobalFrozen (Account const& issuer);
void enableDeferredCredits (bool enable=true);
bool areCreditsDeferred () const;
TER rippleCredit (
@@ -229,8 +228,7 @@ public:
STAmount accountHolds (
Account const& account, Currency const& currency,
Account const& issuer, FreezeHandling freezeHandling);
STAmount accountFunds (
Account const& account, const STAmount & saDefault, FreezeHandling freezeHandling);
TER accountSend (
Account const& uSenderID, Account const& uReceiverID,
const STAmount & saAmount);
@@ -248,46 +246,15 @@ public:
STAmount const& saSrcLimit,
const std::uint32_t uSrcQualityIn = 0,
const std::uint32_t uSrcQualityOut = 0);
TER trustDelete (
SLE::ref sleRippleState, Account const& uLowAccountID,
Account const& uHighAccountID);
Json::Value getJson (int) const;
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)
{
mSet.setDeliveredAmount (amt);
@@ -302,24 +269,7 @@ public:
TER transfer_xrp (Account const& from, Account const& to, STAmount const& amount);
private:
Ledger::pointer mLedger;
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 getEntry (uint256 const& index, Action&);
SLE::pointer getForMod (
uint256 const& node, Ledger::ref ledger,
@@ -359,8 +309,17 @@ private:
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;
/** @} */
//------------------------------------------------------------------------------
@@ -382,6 +341,30 @@ std::uint32_t
rippleTransferRate (LedgerEntrySet& ledger, Account const& uSenderID,
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
#endif

View File

@@ -1193,6 +1193,8 @@ bool ApplicationImp::loadOldLedger (
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);
bool ok = loadLedger->addSLE (sle);
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 (account != amount.issue ().account)
{
// VFALCO Why are we doing this hack?
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 ();
}
}
@@ -2947,8 +2948,13 @@ void NetworkOPsImp::getBookPage (
m_journal.trace << "getBookPage: bDirectAdvance";
sleOfferDir = lesActive.entryCache (
ltDIR_NODE, lpLedger->getNextLedgerIndex (uTipIndex, uBookEnd));
uint256 const ledgerIndex =
lpLedger->getNextLedgerIndex (uTipIndex, uBookEnd);
if (ledgerIndex.isNonZero())
sleOfferDir = lesActive.entryCache (
ltDIR_NODE, ledgerIndex);
else
sleOfferDir.reset();
if (!sleOfferDir)
{

View File

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

View File

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

View File

@@ -23,6 +23,7 @@
#include <ripple/app/ledger/LedgerEntrySet.h>
#include <ripple/app/paths/Node.h>
#include <ripple/app/paths/Types.h>
#include <boost/optional.hpp>
namespace ripple {
@@ -102,20 +103,37 @@ class PathState : public CountedObject <PathState>
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
{
return !(saInPass && saOutPass);
}
private:
private:
TER checkNoRipple (
Account const&, Account const&, Account const&, Currency const&);
/** Clear path structures, and clear each node. */
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;
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.
AccountIssueToNodeIndex umReverse;
LedgerEntrySet lesEntries;
boost::optional<LedgerEntrySet> lesEntries_;
int mIndex; // Index/rank amoung siblings.
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.
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -52,9 +52,11 @@ public:
if (!sleTicket)
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
if (!authorized && sleTicket->isFieldPresent (sfTarget))
@@ -77,7 +79,8 @@ public:
TER const result = mEngine->view ().dirDelete (false, hint,
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);
return result;

View File

@@ -122,15 +122,18 @@ private:
SLE::pointer amendmentObject (mEngine->view().entryCache (ltAMENDMENTS, index));
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(),
amendment) != amendments.end ())
{
amendment) != amendments.end ())
return tefALREADY;
}
amendments.push_back (amendment);
amendmentObject->setFieldV256 (sfAmendments, amendments);
@@ -151,7 +154,11 @@ private:
SLE::pointer feeObject = mEngine->view().entryCache (ltFEE_SETTINGS, index);
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
// m_journal.trace <<

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -581,9 +581,9 @@ Taker::consume_offer (Offer const& offer, Amounts const& order)
}
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 (

View File

@@ -31,53 +31,6 @@ namespace ripple {
// 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>
TransactionEngine::applyTransaction (
STTx const& txn,
@@ -96,7 +49,8 @@ TransactionEngine::applyTransaction (
return std::make_pair(temINVALID_FLAG, false);
}
mNodes.init (mLedger, txID, mLedger->getLedgerSeq (), params);
mNodes.emplace(mLedger, txID,
mLedger->getLedgerSeq(), params);
#ifdef BEAST_DEBUG
if (1)
@@ -146,9 +100,10 @@ TransactionEngine::applyTransaction (
// only claim the transaction fee
WriteLog (lsDEBUG, TransactionEngine) <<
"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 ()));
if (!txnAcct)
@@ -182,7 +137,7 @@ TransactionEngine::applyTransaction (
fee = balance;
txnAcct->setFieldAmount (sfBalance, balance - fee);
txnAcct->setFieldU32 (sfSequence, t_seq + 1);
mNodes.entryModify (txnAcct);
mNodes->entryModify (txnAcct);
didApply = true;
}
}
@@ -202,7 +157,7 @@ TransactionEngine::applyTransaction (
WriteLog (lsFATAL, TransactionEngine) <<
transToken (terResult) << ": " << transHuman (terResult);
WriteLog (lsFATAL, TransactionEngine) <<
mNodes.getJson (0);
mNodes->getJson (0);
didApply = false;
terResult = tefINTERNAL;
}
@@ -212,9 +167,10 @@ TransactionEngine::applyTransaction (
// Transaction succeeded fully or (retries are not allowed and the
// transaction could claim a fee)
Serializer m;
mNodes.calcRawMeta (m, terResult, mTxnSeq++);
mNodes->calcRawMeta (m, terResult, mTxnSeq++);
txnWrite ();
assert(mLedger == mNodes->getLedger());
mNodes->apply();
Serializer s;
txn.add (s);
@@ -253,7 +209,7 @@ TransactionEngine::applyTransaction (
}
}
mNodes.clear ();
mNodes = boost::none;
if (!(params & tapOPEN_LEDGER) && isTemMalformed (terResult))
{

View File

@@ -21,11 +21,13 @@
#define RIPPLE_PROTOCOL_INDEXES_H_INCLUDED
#include <ripple/protocol/LedgerFormats.h>
#include <ripple/protocol/Protocol.h>
#include <ripple/protocol/RippleAddress.h>
#include <ripple/protocol/Serializer.h>
#include <ripple/protocol/UintTypes.h>
#include <ripple/basics/base_uint.h>
#include <ripple/protocol/Book.h>
#include <cstdint>
namespace ripple {
@@ -89,6 +91,137 @@ getRippleStateIndex (Account const& a, Issue const& issue);
uint256
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

View File

@@ -20,7 +20,7 @@
#ifndef 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>
namespace ripple {
@@ -35,10 +35,21 @@ public:
using pointer = 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 (SerialIter & sit, uint256 const& index);
STLedgerEntry (LedgerEntryType type, uint256 const& index);
STLedgerEntry (const STObject & object, uint256 const& index);
STBase*
@@ -57,69 +68,81 @@ public:
{
return STI_LEDGERENTRY;
}
std::string getFullText () const override;
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&
key() const
{
return key_;
}
// DEPRECATED
uint256 const& getIndex () const
{
return mIndex;
}
void setIndex (uint256 const& i)
{
mIndex = i;
return key_;
}
void setImmutable ()
{
mMutable = false;
}
bool isMutable ()
{
return mMutable;
}
STLedgerEntry::pointer getMutable () const;
LedgerEntryType getType () const
{
return mType;
return type_;
}
std::uint16_t getVersion () const
{
return getFieldU16 (sfLedgerEntryType);
}
LedgerFormats::Item const* getFormat ()
{
return mFormat;
}
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);
private:
/** Make STObject comply with the template for this SLE type
/* Make STObject comply with the template for this SLE type
Can throw
*/
void setSLEType ();
private:
uint256 mIndex;
LedgerEntryType mType;
uint256 key_;
LedgerEntryType type_;
LedgerFormats::Item const* mFormat;
bool mMutable;
bool mMutable;
};
using SLE = STLedgerEntry;

View File

@@ -21,6 +21,7 @@
#include <ripple/basics/SHA512Half.h>
#include <ripple/protocol/Indexes.h>
#include <beast/utility/static_initializer.h>
#include <cassert>
namespace ripple {
@@ -192,4 +193,118 @@ getSignerListIndex (Account const& 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

View File

@@ -28,9 +28,24 @@
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 (
SerialIter& sit, uint256 const& index)
: STObject (sfLedgerEntry), mIndex (index), mMutable (true)
: STObject (sfLedgerEntry), key_ (index), mMutable (true)
{
set (sit);
setSLEType ();
@@ -38,7 +53,7 @@ STLedgerEntry::STLedgerEntry (
STLedgerEntry::STLedgerEntry (
const Serializer& s, uint256 const& index)
: STObject (sfLedgerEntry), mIndex (index), mMutable (true)
: STObject (sfLedgerEntry), key_ (index), mMutable (true)
{
SerialIter sit (s.slice());
set (sit);
@@ -47,7 +62,7 @@ STLedgerEntry::STLedgerEntry (
STLedgerEntry::STLedgerEntry (
const STObject & object, uint256 const& index)
: STObject (object), mIndex(index), mMutable (true)
: STObject (object), key_(index), mMutable (true)
{
setSLEType ();
}
@@ -60,7 +75,7 @@ void STLedgerEntry::setSLEType ()
if (mFormat == nullptr)
throw std::runtime_error ("invalid ledger entry type");
mType = mFormat->getType ();
type_ = mFormat->getType ();
if (!setType (mFormat->elements))
{
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 ret = "\"";
ret += to_string (mIndex);
ret += to_string (key_);
ret += "\" = { ";
ret += mFormat->getName ();
ret += ", ";
@@ -105,7 +100,7 @@ std::string STLedgerEntry::getFullText () const
std::string STLedgerEntry::getText () const
{
return str (boost::format ("{ %s, %s }")
% to_string (mIndex)
% to_string (key_)
% STObject::getText ());
}
@@ -113,7 +108,7 @@ Json::Value STLedgerEntry::getJson (int options) const
{
Json::Value ret (STObject::getJson (options));
ret[jss::index] = to_string (mIndex);
ret[jss::index] = to_string (key_);
return ret;
}
@@ -130,12 +125,12 @@ bool STLedgerEntry::isThreaded () const
bool STLedgerEntry::hasOneOwner () const
{
return (mType != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1);
return (type_ != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1);
}
bool STLedgerEntry::hasTwoOwners () const
{
return mType == ltRIPPLE_STATE;
return type_ == ltRIPPLE_STATE;
}
RippleAddress STLedgerEntry::getOwner () const

View File

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