Update TxQ developer docs:

* Rename a couple of member variables for clarity.
This commit is contained in:
Edward Hennis
2016-12-28 19:33:13 -05:00
committed by Nik Bougalis
parent cd1c5a30dd
commit e14f913244
9 changed files with 362 additions and 93 deletions

View File

@@ -105,6 +105,9 @@ WARN_LOGFILE =
#---------------------------------------------------------------------------
INPUT = \
\
../src/ripple/app/misc/TxQ.h \
../src/ripple/app/tx/apply.h \
../src/ripple/app/tx/applySteps.h \
../src/ripple/protocol/STObject.h \
../src/ripple/protocol/JsonFields.h \
../src/test/jtx/AbstractClient.h \

View File

@@ -1609,8 +1609,8 @@ NetworkOPsImp::ServerFeeSummary::operator !=(NetworkOPsImp::ServerFeeSummary con
if(em && b.em)
{
return (em->minFeeLevel != b.em->minFeeLevel ||
em->expFeeLevel != b.em->expFeeLevel ||
return (em->minProcessingFeeLevel != b.em->minProcessingFeeLevel ||
em->openLedgerFeeLevel != b.em->openLedgerFeeLevel ||
em->referenceFeeLevel != b.em->referenceFeeLevel);
}
@@ -1653,12 +1653,12 @@ void NetworkOPsImp::pubServer ()
{
auto const loadFactor =
std::max(static_cast<std::uint64_t>(f.loadFactorServer),
mulDiv(f.em->expFeeLevel, f.loadBaseServer,
mulDiv(f.em->openLedgerFeeLevel, f.loadBaseServer,
f.em->referenceFeeLevel).second);
jvObj [jss::load_factor] = clamp(loadFactor);
jvObj [jss::load_factor_fee_escalation] = clamp(f.em->expFeeLevel);
jvObj [jss::load_factor_fee_queue] = clamp(f.em->minFeeLevel);
jvObj [jss::load_factor_fee_escalation] = clamp(f.em->openLedgerFeeLevel);
jvObj [jss::load_factor_fee_queue] = clamp(f.em->minProcessingFeeLevel);
jvObj [jss::load_factor_fee_reference]
= clamp(f.em->referenceFeeLevel);
@@ -2195,7 +2195,7 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin, bool counters)
auto const loadFactorServer = app_.getFeeTrack().getLoadFactor();
auto const loadBaseServer = app_.getFeeTrack().getLoadBase();
auto const loadFactorFeeEscalation = escalationMetrics ?
escalationMetrics->expFeeLevel : 1;
escalationMetrics->openLedgerFeeLevel : 1;
auto const loadBaseFeeEscalation = escalationMetrics ?
escalationMetrics->referenceFeeLevel : 1;
@@ -2221,7 +2221,7 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin, bool counters)
max32, loadFactorFeeEscalation));
info[jss::load_factor_fee_queue] =
static_cast<std::uint32_t> (std::min(
max32, escalationMetrics->minFeeLevel));
max32, escalationMetrics->minProcessingFeeLevel));
info[jss::load_factor_fee_reference] =
static_cast<std::uint32_t> (std::min(
max32, loadBaseFeeEscalation));
@@ -2258,11 +2258,12 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin, bool counters)
info[jss::load_factor_fee_escalation] =
static_cast<double> (loadFactorFeeEscalation) /
escalationMetrics->referenceFeeLevel;
if (escalationMetrics->minFeeLevel !=
if (escalationMetrics->minProcessingFeeLevel !=
escalationMetrics->referenceFeeLevel)
info[jss::load_factor_fee_queue] =
static_cast<double> (escalationMetrics->minFeeLevel) /
escalationMetrics->referenceFeeLevel;
static_cast<double> (
escalationMetrics->minProcessingFeeLevel) /
escalationMetrics->referenceFeeLevel;
}
}

View File

@@ -39,7 +39,7 @@ class Config;
Once enough transactions are added to the open ledger, the required
fee will jump dramatically. If additional transactions are added,
the fee will grow exponentially.
the fee will grow exponentially from there.
Transactions that don't have a high enough fee to be applied to
the ledger are added to the queue in order from highest fee level to
@@ -47,30 +47,95 @@ class Config;
are first applied from the queue to the open ledger in fee level order
until either all transactions are applied or the fee again jumps
too high for the remaining transactions.
For further information and a high-level overview of how transactions
are processed with the `TxQ`, see FeeEscalation.md
*/
class TxQ
{
public:
/// Fee level for single-signed reference transaction.
static constexpr std::uint64_t baseLevel = 256;
/**
Structure used to customize @ref TxQ behavior.
*/
struct Setup
{
/// Default constructor
explicit Setup() = default;
/** Number of ledgers' worth of transactions to allow
in the queue. For example, if the last ledger had
150 transactions, then up to 3000 transactions can
be queued.
Can be overridden by @ref queueSizeMin
*/
std::size_t ledgersInQueue = 20;
/** The smallest limit the queue is allowed.
Will allow more than `ledgersInQueue` in the queue
if ledgers are small.
*/
std::size_t queueSizeMin = 2000;
/** Extra percentage required on the fee level of a queued
transaction to replace that transaction with another
with the same sequence number.
If queued transaction for account "Alice" with seq 45
has a fee level of 512, a replacement transaction for
"Alice" with seq 45 must have a fee level of at least
512 * (1 + 0.25) = 640 to be considered.
*/
std::uint32_t retrySequencePercent = 25;
// TODO: eahennis. Can we remove the multi tx factor?
/** Extra percentage required on the fee level of a
queued transaction to queue the transaction with
the next sequence number.
If queued transaction for account "Alice" with seq 45
has a fee level of 512, a transaction with seq 46 must
have a fee level of at least
512 * (1 + -0.90) = 51.2 ~= 52 to
be considered.
@todo eahennis. Can we remove the multi tx factor?
*/
std::int32_t multiTxnPercent = -90;
/// Minimum value of the escalation multiplier, regardless
/// of the prior ledger's median fee level.
std::uint32_t minimumEscalationMultiplier = baseLevel * 500;
/// Minimum number of transactions to allow into the ledger
/// before escalation, regardless of the prior ledger's size.
std::uint32_t minimumTxnInLedger = 5;
/// Like @ref minimumTxnInLedger for standalone mode.
/// Primarily so that tests don't need to worry about queuing.
std::uint32_t minimumTxnInLedgerSA = 1000;
/// Number of transactions per ledger that fee escalation "works
/// towards".
std::uint32_t targetTxnInLedger = 50;
/** Optional maximum allowed value of transactions per ledger before
fee escalation kicks in. By default, the maximum is an emergent
property of network, validator, and consensus performance. This
setting can override that behavior to prevent fee escalation from
allowing more than `maximumTxnInLedger` "cheap" transactions into
the open ledger.
@todo eahennis. This setting seems to go against our goals and
values. Can it be removed?
*/
boost::optional<std::uint32_t> maximumTxnInLedger;
/// Maximum number of transactions that can be queued by one account.
std::uint32_t maximumTxnPerAccount = 10;
/** Minimum difference between the current ledger sequence and a
transaction's `LastLedgerSequence` for the transaction to be
queueable. Decreases the chance a transaction will get queued
and broadcast only to expire before it gets a chance to be
processed.
*/
std::uint32_t minimumLastLedgerBuffer = 2;
/* So we don't deal with infinite fee levels, treat
any transaction with a 0 base fee (ie. SetRegularKey
/** So we don't deal with "infinite" fee levels, treat
any transaction with a 0 base fee (ie SetRegularKey
password recovery) as having this fee level.
Should the network behavior change in the future such
that these transactions are unable to be processed,
@@ -78,56 +143,115 @@ public:
bikeshedding for now.
*/
std::uint64_t zeroBaseFeeTransactionFeeLevel = 256000;
/// Use standalone mode behavior.
bool standAlone = false;
};
/**
Structure returned by @ref TxQ::getMetrics, expressed in
reference fee level units.
*/
struct Metrics
{
/// Default constructor
explicit Metrics() = default;
std::size_t txCount; // Transactions in the queue
boost::optional<std::size_t> txQMaxSize; // Max txns in queue
std::size_t txInLedger; // Amount currently in the ledger
std::size_t txPerLedger; // Amount expected per ledger
std::uint64_t referenceFeeLevel; // Reference transaction fee level
std::uint64_t minFeeLevel; // Minimum fee level to get in the queue
std::uint64_t medFeeLevel; // Median fee level of the last ledger
std::uint64_t expFeeLevel; // Estimated fee level to get in next ledger
/// Number of transactions in the queue
std::size_t txCount;
/// Max transactions currently allowed in queue
boost::optional<std::size_t> txQMaxSize;
/// Number of transactions currently in the open ledger
std::size_t txInLedger;
/// Number of transactions expected per ledger
std::size_t txPerLedger;
/// Reference transaction fee level
std::uint64_t referenceFeeLevel;
/// Minimum fee level for a transaction to be considered for
/// the open ledger or the queue
std::uint64_t minProcessingFeeLevel;
/// Median fee level of the last ledger
std::uint64_t medFeeLevel;
/// Minimum fee level to get into the current open ledger,
/// bypassing the queue
std::uint64_t openLedgerFeeLevel;
};
/**
Structure returned by @ref TxQ::getAccountTxs to describe
transactions in the queue for an account.
*/
struct AccountTxDetails
{
/// Default constructor
explicit AccountTxDetails() = default;
/// Fee level of the queued transaction
uint64_t feeLevel;
/// LastValidLedger field of the queued transaction, if any
boost::optional<LedgerIndex const> lastValid;
/** Potential @ref TxConsequences of applying the queued transaction
to the open ledger, if known.
@note `consequences` is lazy-computed, so may not be known at any
given time.
*/
boost::optional<TxConsequences const> consequences;
};
/**
Structure that describes a transaction in the queue
waiting to be applied to the current open ledger.
A collection of these is returned by @ref TxQ::getTxs.
*/
struct TxDetails : AccountTxDetails
{
/// Default constructor
explicit TxDetails() = default;
/// The account the transaction is queued for
AccountID account;
/// The full transaction
std::shared_ptr<STTx const> txn;
/** Number of times the transactor can return a retry / `ter` result
when attempting to apply this transaction to the open ledger
from the queue. If the transactor returns `ter` and no retries are
left, this transaction will be dropped.
*/
int retriesRemaining;
/** The *intermediate* result returned by @ref preflight before
this transaction was queued, or after it is queued, but before
a failed attempt to `apply` it to the open ledger. This will
usually be `tesSUCCESS`, but there are some edge cases where
it has another value. Those edge cases are interesting enough
that this value is made available here. Specifically, if the
`rules` change between attempts, `preflight` will be run again
in `TxQ::MaybeTx::apply`.
*/
TER preflightResult;
/** If the transactor attempted to apply the transaction to the open
ledger from the queue and *failed*, then this is the transactor
result from the last attempt. Should never be a `tec`, `tef`,
`tem`, or `tesSUCCESS`, because those results cause the
transaction to be removed from the queue.
*/
boost::optional<TER> lastResult;
};
/// Constructor
TxQ(Setup const& setup,
beast::Journal j);
/// Destructor
virtual ~TxQ();
/**
Add a new transaction to the open ledger, hold it in the queue,
or reject it.
@return A pair with the TER and a bool indicating
whether or not the transaction was applied.
If the transaction is queued, will return
{ terQUEUED, false }.
@return A pair with the `TER` and a `bool` indicating
whether or not the transaction was applied to
the open ledger. If the transaction is queued,
will return `{ terQUEUED, false }`.
*/
std::pair<TER, bool>
apply(Application& app, OpenView& view,
@@ -136,17 +260,29 @@ public:
/**
Fill the new open ledger with transactions from the queue.
As we apply more transactions to the ledger, the required
fee will increase.
@return Whether any txs were added to the view.
@note As more transactions are applied to the ledger, the
required fee may increase. The required fee may rise above
the fee level of the queued items before the queue is emptied,
which will end the process, leaving those in the queue for
the next open ledger.
@return Whether any transactions were added to the `view`.
*/
bool
accept(Application& app, OpenView& view);
/**
Update stats and clean up the queue in preparation for
Update fee metrics and clean up the queue in preparation for
the next ledger.
@note Fee metrics are updated based on the fee levels of the
txs in the validated ledger and whether consensus is slow.
Maximum queue size is adjusted to be enough to hold
`ledgersInQueue` ledgers or `queueSizeMin` transactions.
Any transactions for which the `LastLedgerSequence` has
passed are removed from the queue, and any account objects
that have no candidates under them are removed.
*/
void
processClosedLedger(Application& app,
@@ -154,8 +290,8 @@ public:
/** Returns fee metrics in reference fee level units.
@returns Uninitialized @ref optional if the FeeEscalation
amendment is not enabled.
@returns Uninitialized boost::optional if the
FeeEscalation amendment is not enabled.
*/
boost::optional<Metrics>
getMetrics(OpenView const& view,
@@ -164,9 +300,9 @@ public:
/** Returns information about the transactions currently
in the queue for the account.
@returns Uninitialized @ref optional if the FeeEscalation
amendment is not enabled, OR if the account has no transactions
in the queue.
@returns Empty `map` if the
FeeEscalation amendment is not enabled, OR if the
account has no transactions in the queue.
*/
std::map<TxSeq, AccountTxDetails const>
getAccountTxs(AccountID const& account, ReadView const& view) const;
@@ -174,46 +310,53 @@ public:
/** Returns information about all transactions currently
in the queue.
@returns Uninitialized @ref optional if the FeeEscalation
@returns Empty `vector` if the FeeEscalation
amendment is not enabled, OR if there are no transactions
in the queue.
*/
std::vector<TxDetails>
getTxs(ReadView const& view) const;
/** Packages up fee metrics for the `fee` RPC command.
/** Summarize current fee metrics for the `fee` RPC command.
@returns a `Json objectvalue`
*/
Json::Value
doRPC(Application& app) const;
private:
/**
Track and use the fee escalation metrics of the
current open ledger. Does the work of scaling fees
as the open ledger grows.
*/
class FeeMetrics
{
private:
// Fee escalation
// Minimum value of txnsExpected.
/// Minimum value of txnsExpected.
std::size_t const minimumTxnCount_;
// Limit of the txnsExpected value after a
// time leap.
/// Number of transactions per ledger that fee escalation "works
/// towards".
std::size_t const targetTxnCount_;
// Maximum value of txnsExpected
/// Maximum value of txnsExpected
boost::optional<std::size_t> const maximumTxnCount_;
// Number of transactions expected per ledger.
// One more than this value will be accepted
// before escalation kicks in.
/// Number of transactions expected per ledger.
/// One more than this value will be accepted
/// before escalation kicks in.
std::size_t txnsExpected_;
// Recent history of transaction counts that
// exceed the targetTxnCount_
/// Recent history of transaction counts that
/// exceed the targetTxnCount_
boost::circular_buffer<std::size_t> recentTxnCounts_;
// Minimum value of escalationMultiplier.
/// Minimum value of escalationMultiplier.
std::uint64_t const minimumMultiplier_;
// Based on the median fee of the LCL. Used
// when fee escalation kicks in.
/// Based on the median fee of the LCL. Used
/// when fee escalation kicks in.
std::uint64_t escalationMultiplier_;
/// Journal
beast::Journal j_;
public:
/// Constructor
FeeMetrics(Setup const& setup, beast::Journal j)
: minimumTxnCount_(setup.standAlone ?
setup.minimumTxnInLedgerSA :
@@ -236,9 +379,11 @@ private:
Updates fee metrics based on the transactions in the ReadView
for use in fee escalation calculations.
@param app Rippled Application object.
@param view View of the LCL that was just closed or received.
@param timeLeap Indicates that rippled is under load so fees
should grow faster.
@param setup Customization params.
*/
std::size_t
update(Application& app,
@@ -258,6 +403,7 @@ private:
std::uint64_t const escalationMultiplier;
};
/// Get the current @ref Snapshot
Snapshot
getSnapshot() const
{
@@ -267,19 +413,54 @@ private:
};
}
/** Use the number of transactions in the current open ledger
to compute the fee level a transaction must pay to bypass the
queue.
@param view Current open ledger.
@param txCountPadding Optional number of "extra" transactions
to assume are in the ledger. Can be used to determine a
padded fee, so a transaction can pay more if the user is
concerned that more transactions will get into the open
ledger between the time this fee is computed and the
transaction is submitted.
@return A fee level value.
*/
static
std::uint64_t
scaleFeeLevel(Snapshot const& snapshot, OpenView const& view,
std::uint32_t txCountPadding = 0);
/**
Returns the total fee level for all transactions in a series.
Assumes that there are already more than txnsExpected_ txns in
the view. If there aren't, the math still works, but the level
will be high.
Computes the total fee level for all transactions in a series.
Assumes that there are already more than @ref txnsExpected_ txns
between the view and `extraCount`. If there aren't, the result
will be sensible (e.g. there won't be any underflows or
overflows), but the level will be higher than actually required.
Returns: A `std::pair` as returned from `mulDiv` indicating whether
the calculation result is safe.
@note A "series" is a set of transactions for the same account
with sequential sequence numbers. In the context of this
function, the series is already in the queue, and the series
starts with the account's current sequence number. This
function is called by @ref tryClearAccountQueue to figure
out if a newly submitted transaction is paying enough to
get all of the queued transactions plus itself out of the
queue and into the open ledger while accounting for the
escalating fee as each one is processed. The idea is that
if a series of transactions are taking too long to get out
of the queue, a user can "rescue" them without having to
resubmit each one with an individually higher fee.
@param view Current open / working ledger. (May be a sandbox.)
@param extraCount Number of additional transactions to count as
in the ledger. (If `view` is a sandbox, should be the number of
transactions in the parent ledger.)
@param seriesSize Total number of transactions in the series to be
processed.
@return A `std::pair` as returned from @ref `mulDiv` indicating
whether the calculation result overflows.
*/
static
std::pair<bool, std::uint64_t>
@@ -287,34 +468,65 @@ private:
std::size_t extraCount, std::size_t seriesSize);
};
/**
Represents transactions in the queue which may be applied
later to the open ledger.
*/
class MaybeTx
{
public:
// Used by the TxQ::FeeHook and TxQ::FeeMultiSet below
// to put each MaybeTx object into more than one
// set without copies, pointers, etc.
/// Used by the TxQ::FeeHook and TxQ::FeeMultiSet below
/// to put each MaybeTx object into more than one
/// set without copies, pointers, etc.
boost::intrusive::set_member_hook<> byFeeListHook;
/// The complete transaction.
std::shared_ptr<STTx const> txn;
/// Potential @ref TxConsequences of applying this transaction
/// to the open ledger.
boost::optional<TxConsequences const> consequences;
/// Computed fee level that the transaction will pay.
uint64_t const feeLevel;
/// Transaction ID.
TxID const txID;
/// Prior transaction ID (`sfAccountTxnID` field).
boost::optional<TxID> priorTxID;
/// Account submitting the transaction.
AccountID const account;
/// Expiration ledger for the transaction
/// (`sfLastLedgerSequence` field).
boost::optional<LedgerIndex> lastValid;
/**
A transaction at the front of the queue will be given
several attempts to succeed before being dropped from
the queue. If dropped, one of the account's penalty
flags will be set, and other transactions may have
their `retriesRemaining` forced down as part of the
penalty.
*/
int retriesRemaining;
/// Transaction sequence number (`sfSequence` field).
TxSeq const sequence;
/// Flags provided to `apply`. If the transaction is later
/// attempted with different flags, it will need to be
/// `preflight`ed again.
ApplyFlags const flags;
boost::optional<TER> lastResult;
// Invariant: pfresult is never allowed to be empty. The
// boost::optional is leveraged to allow `emplace`d
// construction and replacement without a copy
// assignment operation.
/** Cached result of the `preflight` operation. Because
`preflight` is expensive, minimize the number of times
it needs to be done.
@invariant `pfresult` is never allowed to be empty. The
`boost::optional` is leveraged to allow `emplace`d
construction and replacement without a copy
assignment operation.
*/
boost::optional<PreflightResult const> pfresult;
/* In TxQ::accept, the required fee level may be low
/** Starting retry count for newly queued transactions.
In TxQ::accept, the required fee level may be low
enough that this transaction gets a chance to apply
to the ledger, but it may get a retry ter result for
another reason (eg. insufficient balance). When that
@@ -329,33 +541,42 @@ private:
static constexpr int retriesAllowed = 10;
public:
/// Constructor
MaybeTx(std::shared_ptr<STTx const> const&,
TxID const& txID, std::uint64_t feeLevel,
ApplyFlags const flags,
PreflightResult const& pfresult);
/// Attempt to apply the queued transaction to the open ledger.
std::pair<TER, bool>
apply(Application& app, OpenView& view, beast::Journal j);
};
/// Used for sorting @ref MaybeTx by `feeLevel`
class GreaterFee
{
public:
/// Default constructor
explicit GreaterFee() = default;
/// Is the fee level of `lhs` greater than the fee level of `rhs`?
bool operator()(const MaybeTx& lhs, const MaybeTx& rhs) const
{
return lhs.feeLevel > rhs.feeLevel;
}
};
/** Used to represent an account to the queue, and stores the
transactions queued for that account by sequence.
*/
class TxQAccount
{
public:
using TxMap = std::map <TxSeq, MaybeTx>;
/// The account
AccountID const account;
// Sequence number will be used as the key.
/// Sequence number will be used as the key.
TxMap transactions;
/* If this account has had any transaction retry more than
`retriesAllowed` times so that it was dropped from the
@@ -373,24 +594,34 @@ private:
bool dropPenalty = false;
public:
/// Construct from a transaction
explicit TxQAccount(std::shared_ptr<STTx const> const& txn);
/// Construct from an account
explicit TxQAccount(const AccountID& account);
/// Return the number of transactions currently queued for this account
std::size_t
getTxnCount() const
{
return transactions.size();
}
/// Checks if this account has no transactions queued
bool
empty() const
{
return !getTxnCount();
}
/// Add a transaction candidate to this account for queuing
MaybeTx&
add(MaybeTx&&);
/** Remove the candidate with given sequence number from this
account.
@return Whether a candidate was removed
*/
bool
remove(TxSeq const& sequence);
};
@@ -405,41 +636,68 @@ private:
using AccountMap = std::map <AccountID, TxQAccount>;
/// Setup parameters used to control the behavior of the queue
Setup const setup_;
/// Journal
beast::Journal j_;
// These members must always and only be accessed under
// locked mutex_
/** Tracks the current state of the queue.
@note This member must always and only be accessed under
locked mutex_
*/
FeeMetrics feeMetrics_;
/** The queue itself: the collection of transactions ordered
by fee level.
@note This member must always and only be accessed under
locked mutex_
*/
FeeMultiSet byFee_;
/** All of the accounts which currently have any transactions
in the queue. Entries are created and destroyed dynamically
as transactions are added and removed.
@note This member must always and only be accessed under
locked mutex_
*/
AccountMap byAccount_;
/** Maximum number of transactions allowed in the queue based
on the current metrics. If uninitialized, there is no limit,
but that condition cannot last for long in practice.
@note This member must always and only be accessed under
locked mutex_
*/
boost::optional<size_t> maxSize_;
// Most queue operations are done under the master lock,
// but use this mutex for the RPC "fee" command, which isn't.
/** Most queue operations are done under the master lock,
but use this mutex for the RPC "fee" command, which isn't.
*/
std::mutex mutable mutex_;
private:
/// Is the queue at least `fillPercentage` full?
template<size_t fillPercentage = 100>
bool
isFull() const;
/** Checks if the indicated transaction fits the conditions
for being stored in the queue.
*/
bool canBeHeld(STTx const&, OpenView const&,
AccountMap::iterator,
boost::optional<FeeMultiSet::iterator>);
// Erase and return the next entry in byFee_ (lower fee level)
/// Erase and return the next entry in byFee_ (lower fee level)
FeeMultiSet::iterator_type erase(FeeMultiSet::const_iterator_type);
// Erase and return the next entry for the account (if fee level
// is higher), or next entry in byFee_ (lower fee level).
// Used to get the next "applyable" MaybeTx for accept().
/** Erase and return the next entry for the account (if fee level
is higher), or next entry in byFee_ (lower fee level).
Used to get the next "applyable" MaybeTx for accept().
*/
FeeMultiSet::iterator_type eraseAndAdvance(FeeMultiSet::const_iterator_type);
// Erase a range of items, based on TxQAccount::TxMap iterators
/// Erase a range of items, based on TxQAccount::TxMap iterators
TxQAccount::TxMap::iterator
erase(TxQAccount& txQAccount, TxQAccount::TxMap::const_iterator begin,
TxQAccount::TxMap::const_iterator end);
/*
/**
All-or-nothing attempt to try to apply all the queued txs for `accountIter`
up to and including `tx`.
*/
@@ -454,9 +712,15 @@ private:
};
/**
Build a @ref TxQ::Setup object from application configuration.
*/
TxQ::Setup
setup_TxQ(Config const&);
/**
@ref TxQ object factory.
*/
std::unique_ptr<TxQ>
make_TxQ(TxQ::Setup const&, beast::Journal);

View File

@@ -1389,10 +1389,10 @@ TxQ::getMetrics(OpenView const& view, std::uint32_t txCountPadding) const
result.txInLedger = view.txCount();
result.txPerLedger = snapshot.txnsExpected;
result.referenceFeeLevel = baseLevel;
result.minFeeLevel = isFull() ? byFee_.rbegin()->feeLevel + 1 :
result.minProcessingFeeLevel = isFull() ? byFee_.rbegin()->feeLevel + 1 :
baseLevel;
result.medFeeLevel = snapshot.escalationMultiplier;
result.expFeeLevel = FeeMetrics::scaleFeeLevel(snapshot, view,
result.openLedgerFeeLevel = FeeMetrics::scaleFeeLevel(snapshot, view,
txCountPadding);
return result;
@@ -1496,9 +1496,9 @@ TxQ::doRPC(Application& app) const
ret[jss::max_queue_size] = to_string(*metrics->txQMaxSize);
levels[jss::reference_level] = to_string(metrics->referenceFeeLevel);
levels[jss::minimum_level] = to_string(metrics->minFeeLevel);
levels[jss::minimum_level] = to_string(metrics->minProcessingFeeLevel);
levels[jss::median_level] = to_string(metrics->medFeeLevel);
levels[jss::open_ledger_level] = to_string(metrics->expFeeLevel);
levels[jss::open_ledger_level] = to_string(metrics->openLedgerFeeLevel);
auto const baseFee = view->fees().base;
auto& drops = ret[jss::drops] = Json::Value();
@@ -1508,16 +1508,16 @@ TxQ::doRPC(Application& app) const
metrics->referenceFeeLevel, baseFee,
metrics->referenceFeeLevel).second);
drops[jss::minimum_fee] = to_string(mulDiv(
metrics->minFeeLevel, baseFee,
metrics->minProcessingFeeLevel, baseFee,
metrics->referenceFeeLevel).second);
drops[jss::median_fee] = to_string(mulDiv(
metrics->medFeeLevel, baseFee,
metrics->referenceFeeLevel).second);
auto escalatedFee = mulDiv(
metrics->expFeeLevel, baseFee,
metrics->openLedgerFeeLevel, baseFee,
metrics->referenceFeeLevel).second;
if (mulDiv(escalatedFee, metrics->referenceFeeLevel,
baseFee).second < metrics->expFeeLevel)
baseFee).second < metrics->openLedgerFeeLevel)
++escalatedFee;
drops[jss::open_ledger_fee] = to_string(escalatedFee);

View File

@@ -707,10 +707,10 @@ Json::Value checkFee (
{
auto const baseFee = ledger->fees().base;
auto escalatedFee = mulDiv(
metrics->expFeeLevel, baseFee,
metrics->openLedgerFeeLevel, baseFee,
metrics->referenceFeeLevel).second;
if (mulDiv(escalatedFee, metrics->referenceFeeLevel,
baseFee).second < metrics->expFeeLevel)
baseFee).second < metrics->openLedgerFeeLevel)
++escalatedFee;
fee = std::max(fee, escalatedFee);
}

View File

@@ -59,13 +59,13 @@ class TxQ_test : public beast::unit_test::suite
BEAST_EXPECT(metrics.txQMaxSize == expectedMaxCount);
BEAST_EXPECT(metrics.txInLedger == expectedInLedger);
BEAST_EXPECT(metrics.txPerLedger == expectedPerLedger);
BEAST_EXPECT(metrics.minFeeLevel == expectedMinFeeLevel);
BEAST_EXPECT(metrics.minProcessingFeeLevel == expectedMinFeeLevel);
BEAST_EXPECT(metrics.medFeeLevel == expectedMedFeeLevel);
auto expectedCurFeeLevel = expectedInLedger > expectedPerLedger ?
expectedMedFeeLevel * expectedInLedger * expectedInLedger /
(expectedPerLedger * expectedPerLedger) :
metrics.referenceFeeLevel;
BEAST_EXPECT(metrics.expFeeLevel == expectedCurFeeLevel);
BEAST_EXPECT(metrics.openLedgerFeeLevel == expectedCurFeeLevel);
}
void
@@ -91,7 +91,7 @@ class TxQ_test : public beast::unit_test::suite
return fee(none);
// Don't care about the overflow flag
return fee(mulDiv(metrics->expFeeLevel,
return fee(mulDiv(metrics->openLedgerFeeLevel,
view.fees().base, metrics->referenceFeeLevel).second + 1);
}

View File

@@ -2203,7 +2203,8 @@ public:
auto metrics = env.app().getTxQ().getMetrics(*env.current());
if (!BEAST_EXPECT(metrics))
break;
if (metrics->expFeeLevel > metrics->minFeeLevel)
if (metrics->openLedgerFeeLevel >
metrics->minProcessingFeeLevel)
break;
env(noop(env.master));
}

View File

@@ -1313,7 +1313,7 @@ class LedgerRPC_test : public beast::unit_test::suite
auto metrics = env.app().getTxQ().getMetrics(*env.current());
if (! BEAST_EXPECT(metrics))
break;
if (metrics->expFeeLevel > metrics->minFeeLevel)
if (metrics->openLedgerFeeLevel > metrics->minProcessingFeeLevel)
break;
env(noop(alice));
}

View File

@@ -290,14 +290,14 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite
env.memoize(gw);
env (pay (env.master, gw, XRP(1000)),
seq (autofill),
fee (txq.getMetrics(*env.current())->expFeeLevel + 1),
fee (txq.getMetrics(*env.current())->openLedgerFeeLevel + 1),
sig (autofill));
env (fset (gw, asfDefaultRipple),
seq (autofill),
fee (txq.getMetrics(*env.current())->expFeeLevel + 1),
fee (txq.getMetrics(*env.current())->openLedgerFeeLevel + 1),
sig (autofill));
env (trust (alice, gw["USD"](10)),
fee (txq.getMetrics(*env.current())->expFeeLevel + 1));
fee (txq.getMetrics(*env.current())->openLedgerFeeLevel + 1));
env.close();
}