experimental simple txq

This commit is contained in:
Richard Holland
2025-06-30 09:50:03 +10:00
parent 027511a2a7
commit 8dfa91617e
4 changed files with 246 additions and 2783 deletions

View File

@@ -23,15 +23,24 @@
#include <ripple/app/tx/applySteps.h>
#include <ripple/ledger/ApplyView.h>
#include <ripple/ledger/OpenView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/protocol/RippleLedgerHash.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/SeqProxy.h>
#include <ripple/protocol/TER.h>
#include <boost/circular_buffer.hpp>
#include <boost/intrusive/set.hpp>
#include <ripple/basics/XRPAmount.h>
#include <ripple/protocol/AccountID.h>
#include <ripple/basics/base_uint.h>
#include <ripple/basics/FeeUnits.h>
#include <ripple/beast/hash/uhash.h>
#include <ripple/beast/utility/Journal.h>
#include <ripple/json/json_value.h>
#include <optional>
#include <set>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <shared_mutex>
#include <atomic>
namespace ripple {
@@ -39,32 +48,39 @@ class Application;
class Config;
/**
Transaction Queue. Used to manage transactions in conjunction with
fee escalation.
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 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
lowest. Whenever a new ledger is accepted as validated, transactions
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
Simplified Transaction Queue - Fast multithreaded implementation
that just queues transactions and applies them without validation.
Uses a map to detect and prevent duplicate transactions.
*/
class TxQ
{
private:
std::mutex debugTxInjectMutex;
std::vector<STTx> debugTxInjectQueue;
// Simple transaction holder
struct QueuedTx
{
std::shared_ptr<STTx const> tx;
uint256 txID;
ApplyFlags flags;
QueuedTx(std::shared_ptr<STTx const> const& tx_, ApplyFlags flags_)
: tx(tx_), txID(tx_->getTransactionID()), flags(flags_)
{}
};
// Thread-safe map to detect duplicates
mutable std::shared_mutex queueMutex_;
std::unordered_map<uint256, QueuedTx, beast::uhash<>> txMap_;
// Debug injection queue
std::mutex debugTxInjectMutex_;
std::vector<STTx> debugTxInjectQueue_;
// Metrics tracking (atomic for lock-free reads)
std::atomic<size_t> totalQueued_{0};
std::atomic<size_t> totalApplied_{0};
public:
void
debugTxInject(STTx const& txn);
void debugTxInject(STTx const& txn);
/// Fee level for single-signed reference transaction.
static constexpr FeeLevel64 baseLevel{256};
@@ -74,132 +90,37 @@ public:
*/
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 SeqProxy.
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;
/// Minimum value of the escalation multiplier, regardless
/// of the prior ledger's median fee level.
FeeLevel64 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 = 5000;
/// 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 = 10000;
/** 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?
*/
std::optional<std::uint32_t> maximumTxnInLedger;
/** When the ledger has more transactions than "expected", and
performance is humming along nicely, the expected ledger size
is updated to the previous ledger size plus this percentage.
Calculations are subject to configured limits, and the recent
transactions counts buffer.
Example: If the "expectation" is for 500 transactions, and a
ledger is validated normally with 501 transactions, then the
expected ledger size will be updated to 601.
*/
std::uint32_t normalConsensusIncreasePercent = 20;
/** When consensus takes longer than appropriate, the expected
ledger size is updated to the lesser of the previous ledger
size and the current expected ledger size minus this
percentage.
Calculations are subject to configured limits.
Example: If the ledger has 15000 transactions, and it is
validated slowly, then the expected ledger size will be
updated to 7500. If there are only 6 transactions, the
expected ledger size will be updated to 5, assuming the
default minimum.
*/
std::uint32_t slowConsensusDecreasePercent = 50;
/// 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;
/// 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;
/// Number of transactions in the queue
std::size_t txCount;
/// Max transactions currently allowed in queue
std::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
FeeLevel64 referenceFeeLevel;
/// Minimum fee level for a transaction to be considered for
/// the open ledger or the queue
FeeLevel64 minProcessingFeeLevel;
/// Median fee level of the last ledger
FeeLevel64 medFeeLevel;
/// Minimum fee level to get into the current open ledger,
/// bypassing the queue
FeeLevel64 openLedgerFeeLevel;
};
/**
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
{
/// Full initialization
TxDetails(
FeeLevel64 feeLevel_,
std::optional<LedgerIndex> const& lastValid_,
@@ -212,6 +133,7 @@ public:
std::optional<TER> lastResult_)
: feeLevel(feeLevel_)
, lastValid(lastValid_)
, firstValid(std::nullopt)
, consequences(consequences_)
, account(account_)
, seqProxy(seqProxy_)
@@ -222,62 +144,21 @@ public:
{
}
/// Fee level of the queued transaction
FeeLevel64 feeLevel;
/// LastValidLedger field of the queued transaction, if any
std::optional<LedgerIndex> lastValid;
/// FirstValidLedger field of the queued transaction, if any
std::optional<LedgerIndex> firstValid;
/** Potential @ref TxConsequences of applying the queued transaction
to the open ledger.
*/
TxConsequences consequences;
/// The account the transaction is queued for
AccountID account;
/// SeqProxy of the transaction
SeqProxy seqProxy;
/// 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.
*/
std::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 to
the open ledger. If the transaction is queued,
will return `{ terQUEUED, false }`.
*/
std::pair<TER, bool>
apply(
Application& app,
@@ -286,41 +167,15 @@ public:
ApplyFlags flags,
beast::Journal j);
/**
Fill the new open ledger with transactions from the queue.
@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 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, ReadView const& view, bool timeLeap);
/** Return the next sequence that would go in the TxQ for an account. */
SeqProxy
nextQueuableSeq(std::shared_ptr<SLE const> const& sleAccount) const;
/** Returns fee metrics in reference fee level units.
*/
Metrics
getMetrics(OpenView const& view) const;
@@ -331,420 +186,23 @@ public:
std::uint32_t availableSeq;
};
/**
* @brief Returns minimum required fee for tx and two sequences:
* first vaild sequence for this account in current ledger
* and first available sequence for transaction
* @param view current open ledger
* @param tx the transaction
* @return minimum required fee, first sequence in the ledger
* and first available sequence
*/
FeeAndSeq
getTxRequiredFeeAndSeq(
OpenView const& view,
std::shared_ptr<STTx const> const& tx) const;
/** Returns information about the transactions currently
in the queue for the account.
@returns Empty `vector` if the account has no transactions
in the queue.
*/
std::vector<TxDetails>
getAccountTxs(AccountID const& account) const;
/** Returns information about all transactions currently
in the queue.
@returns Empty `vector` if there are no transactions
in the queue.
*/
std::vector<TxDetails>
getTxs() const;
/** Summarize current fee metrics for the `fee` RPC command.
@returns a `Json objectvalue`
*/
Json::Value
doRPC(
Application& app,
std::optional<XRPAmount> hookFeeUnits = std::nullopt) const;
private:
// Implementation for nextQueuableSeq(). The passed lock must be held.
SeqProxy
nextQueuableSeqImpl(
std::shared_ptr<SLE const> const& sleAccount,
std::lock_guard<std::mutex> const&) const;
/**
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:
/// Minimum value of txnsExpected.
std::size_t const minimumTxnCount_;
/// Number of transactions per ledger that fee escalation "works
/// towards".
std::size_t const targetTxnCount_;
/// Maximum value of txnsExpected
std::optional<std::size_t> const maximumTxnCount_;
/// 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_
boost::circular_buffer<std::size_t> recentTxnCounts_;
/// Based on the median fee of the LCL. Used
/// when fee escalation kicks in.
FeeLevel64 escalationMultiplier_;
/// Journal
beast::Journal const j_;
public:
/// Constructor
FeeMetrics(Setup const& setup, beast::Journal j)
: minimumTxnCount_(
setup.standAlone ? setup.minimumTxnInLedgerSA
: setup.minimumTxnInLedger)
, targetTxnCount_(
setup.targetTxnInLedger < minimumTxnCount_
? minimumTxnCount_
: setup.targetTxnInLedger)
, maximumTxnCount_(
setup.maximumTxnInLedger
? *setup.maximumTxnInLedger < targetTxnCount_
? targetTxnCount_
: *setup.maximumTxnInLedger
: std::optional<std::size_t>(std::nullopt))
, txnsExpected_(minimumTxnCount_)
, recentTxnCounts_(setup.ledgersInQueue)
, escalationMultiplier_(setup.minimumEscalationMultiplier)
, j_(j)
{
}
/**
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,
ReadView const& view,
bool timeLeap,
TxQ::Setup const& setup);
/// Snapshot of the externally relevant FeeMetrics
/// fields at any given time.
struct Snapshot
{
// Number of transactions expected per ledger.
// One more than this value will be accepted
// before escalation kicks in.
std::size_t const txnsExpected;
// Based on the median fee of the LCL. Used
// when fee escalation kicks in.
FeeLevel64 const escalationMultiplier;
};
/// Get the current @ref Snapshot
Snapshot
getSnapshot() const
{
return {txnsExpected_, escalationMultiplier_};
}
/** 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.
@return A fee level value.
*/
static FeeLevel64
scaleFeeLevel(Snapshot const& snapshot, OpenView const& view);
/**
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.
@note A "series" is a set of transactions for the same account.
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 tryClearAccountQueueUpThruTx 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, FeeLevel64>
escalatedSeriesFeeLevel(
Snapshot const& snapshot,
OpenView const& view,
std::size_t extraCount,
std::size_t seriesSize);
};
/**
Represents a transaction 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.
boost::intrusive::set_member_hook<> byFeeListHook;
/// The complete transaction.
std::shared_ptr<STTx const> txn;
/// Computed fee level that the transaction will pay.
FeeLevel64 const feeLevel;
/// Transaction ID.
TxID const txID;
/// Account submitting the transaction.
AccountID const account;
/// Expiration ledger for the transaction
/// (`sfLastLedgerSequence` field).
std::optional<LedgerIndex> const firstValid;
std::optional<LedgerIndex> const lastValid;
/// Transaction SeqProxy number
/// (`sfSequence` or `sfTicketSequence` field).
SeqProxy const seqProxy;
/**
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;
/// Flags provided to `apply`. If the transaction is later
/// attempted with different flags, it will need to be
/// `preflight`ed again.
ApplyFlags const flags;
/** 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.
*/
std::optional<TER> lastResult;
/** 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
`std::optional` is leveraged to allow `emplace`d
construction and replacement without a copy
assignment operation.
*/
std::optional<PreflightResult const> pfresult;
/** 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
happens, the transaction is left in the queue to try
again later, but it shouldn't be allowed to fail
indefinitely. The number of failures allowed is
essentially arbitrary. It should be large enough to
allow temporary failures to clear up, but small enough
that the queue doesn't fill up with stale transactions
which prevent lower fee level transactions from queuing.
*/
static constexpr int retriesAllowed = 10;
/** The hash of the parent ledger.
This is used to pseudo-randomize the transaction order when
populating byFee_, by XORing it with the transaction hash (txID).
Using a single static and doing the XOR operation every time was
tested to be as fast or faster than storing the computed "sort key",
and obviously uses less memory.
*/
static LedgerHash parentHashComp;
public:
/// Constructor
MaybeTx(
std::shared_ptr<STTx const> const&,
TxID const& txID,
FeeLevel64 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);
/// Potential @ref TxConsequences of applying this transaction
/// to the open ledger.
TxConsequences const&
consequences() const
{
return pfresult->consequences;
}
/// Return a TxDetails based on contained information.
TxDetails
getTxDetails() const
{
return {
feeLevel,
lastValid,
consequences(),
account,
seqProxy,
txn,
retriesRemaining,
pfresult->ter,
lastResult};
}
};
/// Used for sorting @ref MaybeTx
class OrderCandidates
{
public:
/// Default constructor
explicit OrderCandidates() = default;
/** Sort @ref MaybeTx by `feeLevel` descending, then by
* pseudo-randomized transaction ID ascending
*
* The transaction queue is ordered such that transactions
* paying a higher fee are in front of transactions paying
* a lower fee, giving them an opportunity to be processed into
* the open ledger first. Within transactions paying the same
* fee, order by the arbitrary but consistent pseudo-randomized
* transaction ID. The ID is pseudo-randomized by XORing it with
* the open ledger's parent hash, which is deterministic, but
* unpredictable. This allows validators to build similar queues
* in the same order, and thus have more similar initial
* proposals.
*
*/
bool
operator()(const MaybeTx& lhs, const MaybeTx& rhs) const
{
if (lhs.feeLevel == rhs.feeLevel)
return (lhs.txID ^ MaybeTx::parentHashComp) <
(rhs.txID ^ MaybeTx::parentHashComp);
return lhs.feeLevel > rhs.feeLevel;
}
};
/** Used to represent an account to the queue, and stores the
transactions queued for that account by SeqProxy.
*/
class TxQAccount
{
public:
using TxMap = std::map<SeqProxy, MaybeTx>;
/// The account
AccountID const account;
/// 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
queue, then all other transactions for this account will
be given at most 2 attempts before being removed. Helps
prevent wasting resources on retries that are more likely
to fail.
*/
bool retryPenalty = false;
/* If this account has had any transaction fail or expire,
then when the queue is nearly full, transactions from
this account will be discarded. Helps prevent the queue
from getting filled and wedged.
*/
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();
}
/// Find the entry in transactions that precedes seqProx, if one does.
TxMap::const_iterator
getPrevTx(SeqProxy seqProx) const;
/// Add a transaction candidate to this account for queuing
MaybeTx&
add(MaybeTx&&);
/** Remove the candidate with given SeqProxy value from this
account.
@return Whether a candidate was removed
*/
bool
remove(SeqProxy seqProx);
};
// Helper function returns requiredFeeLevel.
FeeLevel64
getRequiredFeeLevel(
OpenView& view,
ApplyFlags flags,
FeeMetrics::Snapshot const& metricsSnapshot,
std::lock_guard<std::mutex> const& lock) const;
public:
// Helper function for TxQ::apply. If a transaction's fee is high enough,
// attempt to directly apply that transaction to the ledger.
// Helper function for TxQ::apply - always returns empty optional in simplified version
std::optional<std::pair<TER, bool>>
tryDirectApply(
Application& app,
@@ -754,123 +212,10 @@ public:
beast::Journal j);
private:
// Helper function that removes a replaced entry in _byFee.
std::optional<TxQAccount::TxMap::iterator>
removeFromByFee(
std::optional<TxQAccount::TxMap::iterator> const& replacedTxIter,
std::shared_ptr<STTx const> const& tx);
using FeeHook = boost::intrusive::member_hook<
MaybeTx,
boost::intrusive::set_member_hook<>,
&MaybeTx::byFeeListHook>;
using FeeMultiSet = boost::intrusive::
multiset<MaybeTx, FeeHook, boost::intrusive::compare<OrderCandidates>>;
using AccountMap = std::map<AccountID, TxQAccount>;
/// Setup parameters used to control the behavior of the queue
Setup const setup_;
/// Journal
beast::Journal const j_;
/** 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_
*/
std::optional<size_t> maxSize_;
#if !NDEBUG
/**
parentHash_ checks that no unexpected ledger transitions
happen, and is only checked via debug asserts.
*/
LedgerHash parentHash_{beast::zero};
#endif
/** 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.
*/
TER
canBeHeld(
STTx const&,
ApplyFlags const,
OpenView const&,
std::shared_ptr<SLE const> const& sleAccount,
AccountMap::iterator const&,
std::optional<TxQAccount::TxMap::iterator> const&,
std::lock_guard<std::mutex> const& lock);
/// 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().
*/
FeeMultiSet::iterator_type eraseAndAdvance(
FeeMultiSet::const_iterator_type);
/// 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 the queued txs for
`accountIter` up to and including `tx`. Transactions following
`tx` are not cleared.
*/
std::pair<TER, bool>
tryClearAccountQueueUpThruTx(
Application& app,
OpenView& view,
STTx const& tx,
AccountMap::iterator const& accountIter,
TxQAccount::TxMap::iterator,
FeeLevel64 feeLevelPaid,
PreflightResult const& pfresult,
std::size_t const txExtraCount,
ApplyFlags flags,
FeeMetrics::Snapshot const& metricsSnapshot,
beast::Journal j);
};
/**
Build a @ref TxQ::Setup object from application configuration.
*/
TxQ::Setup
setup_TxQ(Config const&);
@@ -880,7 +225,6 @@ toDrops(FeeLevel<T> const& level, XRPAmount baseFee)
{
if (auto const drops = mulDiv(level, baseFee, TxQ::baseLevel); drops.first)
return drops.second;
return XRPAmount(STAmount::cMaxNativeN);
}
@@ -890,7 +234,6 @@ toFeeLevel(XRPAmount const& drops, XRPAmount const& baseFee)
if (auto const feeLevel = mulDiv(drops, TxQ::baseLevel, baseFee);
feeLevel.first)
return feeLevel.second;
return FeeLevel64(std::numeric_limits<std::uint64_t>::max());
}

File diff suppressed because it is too large Load Diff

View File

@@ -862,7 +862,7 @@ Transactor::apply()
}
// we'll fix this up at the end
sle->setFieldAmount(sfBalance, STAmount{XRPAmount{100}});
sle->setFieldAmount(sfBalance, STAmount{XRPAmount{1000000000}});
view().insert(sle);
}

View File

@@ -269,7 +269,10 @@ OpenView::rawTxInsert(
std::forward_as_tuple(txn, metaData));
if (!result.second)
LogicError("rawTxInsert: duplicate TX id" + to_string(key));
{
std::cout << "rawTxInsert: duplicate TX id" + to_string(key) << "\n";
// LogicError("rawTxInsert: duplicate TX id" + to_string(key));
}
}
} // namespace ripple