mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-21 02:58:27 +00:00
Compare commits
5 Commits
develop
...
dangell7/b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f403bddd86 | ||
|
|
e87f58f9bd | ||
|
|
90ed4442d3 | ||
|
|
a775aa5fcf | ||
|
|
57e053dad0 |
@@ -40,6 +40,7 @@ Version 3.5.0 is not yet released.
|
||||
- `account_info`, `account_lines`, `account_channels`: A request with more than one problem may now report a different one of them. An invalid `ledger_hash` or `ledger_index` is reported before a missing or invalid `account`, or `ident` for `account_info`. For `account_lines`, a `peer` that is not a string, or an invalid `limit` or `marker`, is reported before `lgrNotFound`, `actNotFound` or a malformed `account`, and an invalid `limit` or `marker` also before a malformed `peer`. For `account_channels`, a malformed `account` is reported before `lgrNotFound`, and an invalid `destination_account`, `limit` or `marker` before `lgrNotFound` or `actNotFound`. A request with a single problem returns the same error as before. [#8573](https://github.com/XRPLF/rippled/pull/8573)
|
||||
- `deposit_authorized`, `nft_buy_offers`, `nft_sell_offers`: A request with more than one problem may now report a different one of them. An invalid `ledger_hash` or `ledger_index` is reported before a missing or invalid `source_account`, `destination_account` or `nft_id`, and for `nft_buy_offers` / `nft_sell_offers` also before an invalid `limit`. For `deposit_authorized`, an invalid `credentials` array is reported before `lgrNotFound`, `srcActNotFound`, `dstActNotFound` or `badCredentials`. For `nft_buy_offers` and `nft_sell_offers`, an invalid `marker` is reported before `lgrNotFound` or `objectNotFound`. A request with a single problem returns the same error as before. [#8613](https://github.com/XRPLF/rippled/pull/8613)
|
||||
- `nft_buy_offers`, `nft_sell_offers`: An `nft_id` that is an array or an object now returns an `invalidParams` error instead of an `internal` error. [#8613](https://github.com/XRPLF/rippled/pull/8613)
|
||||
- `fee`: `current_ledger_size` and `expected_ledger_size` count each Batch transaction as 1 plus its inner transactions, so the open-ledger fee escalates on Batches the way it does on the same number of separate transactions. `open_ledger_fee`, and `load_factor_fee_escalation` in `server_info`, follow from the same counts.
|
||||
|
||||
### Bugfixes in 3.5.0
|
||||
|
||||
|
||||
@@ -103,6 +103,13 @@ private:
|
||||
*/
|
||||
std::size_t baseTxCount_ = 0;
|
||||
|
||||
/**
|
||||
* Inner transactions declared by the Batch transactions inserted into
|
||||
* this view. The open ledger never applies them, so TxQ adds this to
|
||||
* txCount().
|
||||
*/
|
||||
std::size_t batchInnerCount_ = 0;
|
||||
|
||||
bool open_ = true;
|
||||
|
||||
public:
|
||||
@@ -198,12 +205,31 @@ public:
|
||||
std::size_t
|
||||
txCount() const;
|
||||
|
||||
/**
|
||||
* Return the number of inner transactions declared by the Batch
|
||||
* transactions inserted into this view.
|
||||
*/
|
||||
std::size_t
|
||||
batchInnerCount() const;
|
||||
|
||||
/**
|
||||
* Record that a Batch declaring `count` inner transactions was inserted.
|
||||
*/
|
||||
void
|
||||
rawBatchInnerAdd(std::size_t count);
|
||||
|
||||
/**
|
||||
* Apply changes.
|
||||
*/
|
||||
void
|
||||
apply(TxsRawView& to) const;
|
||||
|
||||
/**
|
||||
* Apply changes, including the Batch inner count.
|
||||
*/
|
||||
void
|
||||
apply(OpenView& to) const;
|
||||
|
||||
// ReadView
|
||||
|
||||
LedgerHeader const&
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
#include <xrpl/protocol/TxMeta.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
@@ -275,6 +276,8 @@ ApplyStateTable::apply(
|
||||
if (!isDryRun)
|
||||
{
|
||||
to.rawTxInsert(tx.getTransactionID(), sTx, sMeta);
|
||||
if (tx.getTxnType() == ttBATCH)
|
||||
to.rawBatchInnerAdd(tx.getFieldArray(sfRawTransactions).size());
|
||||
apply(to);
|
||||
}
|
||||
return metadata;
|
||||
|
||||
@@ -87,6 +87,7 @@ OpenView::OpenView(OpenView const& rhs)
|
||||
, base_{rhs.base_}
|
||||
, items_{rhs.items_}
|
||||
, hold_{rhs.hold_}
|
||||
, batchInnerCount_{rhs.batchInnerCount_}
|
||||
, open_{rhs.open_} {};
|
||||
|
||||
OpenView::OpenView(OpenLedgerT, ReadView const* base, Rules rules, std::shared_ptr<void const> hold)
|
||||
@@ -125,6 +126,18 @@ OpenView::txCount() const
|
||||
return baseTxCount_ + txs_.size();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
OpenView::batchInnerCount() const
|
||||
{
|
||||
return batchInnerCount_;
|
||||
}
|
||||
|
||||
void
|
||||
OpenView::rawBatchInnerAdd(std::size_t count)
|
||||
{
|
||||
batchInnerCount_ += count;
|
||||
}
|
||||
|
||||
void
|
||||
OpenView::apply(TxsRawView& to) const
|
||||
{
|
||||
@@ -133,6 +146,13 @@ OpenView::apply(TxsRawView& to) const
|
||||
to.rawTxInsert(item.first, item.second.txn, item.second.meta);
|
||||
}
|
||||
|
||||
void
|
||||
OpenView::apply(OpenView& to) const
|
||||
{
|
||||
apply(static_cast<TxsRawView&>(to));
|
||||
to.rawBatchInnerAdd(batchInnerCount_);
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
LedgerHeader const&
|
||||
|
||||
@@ -4896,7 +4896,7 @@ class Batch_test : public beast::unit_test::Suite
|
||||
Ter(tesSUCCESS));
|
||||
}
|
||||
|
||||
// inner batch transactions are counter towards the ledger tx count
|
||||
// inner batch transactions are counted towards the ledger tx count
|
||||
{
|
||||
Env env{
|
||||
*this,
|
||||
@@ -4933,10 +4933,10 @@ class Batch_test : public beast::unit_test::Suite
|
||||
Ter(tesSUCCESS));
|
||||
}
|
||||
|
||||
checkMetrics(*this, env, 0, std::nullopt, 3, 2);
|
||||
checkMetrics(*this, env, 0, std::nullopt, 5, 2);
|
||||
|
||||
env(noop(carol), Ter(terQUEUED));
|
||||
checkMetrics(*this, env, 1, std::nullopt, 3, 2);
|
||||
checkMetrics(*this, env, 1, std::nullopt, 5, 2);
|
||||
}
|
||||
|
||||
// A Batch is never queued, so it also cannot sit behind the account's
|
||||
@@ -4984,6 +4984,186 @@ class Batch_test : public beast::unit_test::Suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testOpenViewBatchInnerCount(FeatureBitset features)
|
||||
{
|
||||
testcase("open view batch inner count");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env{*this, features};
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
env.fund(XRP(10000), alice, bob, carol);
|
||||
env.close();
|
||||
|
||||
// The open ledger holds the Batch but never its inner transactions.
|
||||
auto const aliceSeq = env.seq(alice);
|
||||
env(batch::outer(alice, aliceSeq, batch::calcBatchFee(env, 0, 2), tfAllOrNothing),
|
||||
batch::Inner(pay(alice, bob, XRP(1)), aliceSeq + 1),
|
||||
batch::Inner(pay(alice, bob, XRP(1)), aliceSeq + 2),
|
||||
Ter(tesSUCCESS));
|
||||
BEAST_EXPECT(env.current()->txCount() == 1);
|
||||
BEAST_EXPECT(env.current()->batchInnerCount() == 2);
|
||||
|
||||
env(noop(bob));
|
||||
BEAST_EXPECT(env.current()->txCount() == 2);
|
||||
BEAST_EXPECT(env.current()->batchInnerCount() == 2);
|
||||
|
||||
// A copy keeps the count.
|
||||
OpenView copy(*env.current());
|
||||
BEAST_EXPECT(copy.batchInnerCount() == 2);
|
||||
|
||||
// A view applied into another OpenView adds its count to it.
|
||||
auto const carolSeq = env.seq(carol);
|
||||
auto const jt = env.jt(
|
||||
batch::outer(carol, carolSeq, batch::calcBatchFee(env, 0, 3), tfAllOrNothing),
|
||||
batch::Inner(pay(carol, bob, XRP(1)), carolSeq + 1),
|
||||
batch::Inner(pay(carol, bob, XRP(1)), carolSeq + 2),
|
||||
batch::Inner(pay(carol, bob, XRP(1)), carolSeq + 3));
|
||||
OpenView sandbox(kOpenLedger, ©, copy.rules());
|
||||
auto const result = xrpl::apply(env.app(), sandbox, *jt.stx, TapNone, env.journal);
|
||||
BEAST_EXPECT(result.applied && result.ter == tesSUCCESS);
|
||||
BEAST_EXPECT(sandbox.txCount() == 1);
|
||||
BEAST_EXPECT(sandbox.batchInnerCount() == 3);
|
||||
|
||||
sandbox.apply(copy);
|
||||
BEAST_EXPECT(copy.txCount() == 3);
|
||||
BEAST_EXPECT(copy.batchInnerCount() == 5);
|
||||
|
||||
// The next open ledger starts from zero.
|
||||
env.close();
|
||||
BEAST_EXPECT(env.current()->batchInnerCount() == 0);
|
||||
}
|
||||
|
||||
void
|
||||
testOpenLedgerCountsBatchInners(FeatureBitset features)
|
||||
{
|
||||
testcase("open ledger counts batch inners");
|
||||
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
Env env{
|
||||
*this,
|
||||
makeSmallQueueConfig({{Keys::kMinimumTxnInLedgerStandalone, "3"}}),
|
||||
features,
|
||||
nullptr,
|
||||
beast::Severity::Error};
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
|
||||
// Fund across several ledgers so the TxQ metrics stay restricted.
|
||||
env.fund(XRP(10000), noripple(alice, bob));
|
||||
env.close(env.now() + 5s, 10000ms);
|
||||
env.fund(XRP(10000), noripple(carol));
|
||||
env.close(env.now() + 5s, 10000ms);
|
||||
checkMetrics(*this, env, 0, std::nullopt, 0, 3);
|
||||
|
||||
// A Batch with two inner transactions reaches the target on its own.
|
||||
auto const aliceSeq = env.seq(alice);
|
||||
env(batch::outer(alice, aliceSeq, batch::calcBatchFee(env, 0, 2), tfAllOrNothing),
|
||||
batch::Inner(pay(alice, bob, XRP(1)), aliceSeq + 1),
|
||||
batch::Inner(pay(alice, bob, XRP(1)), aliceSeq + 2),
|
||||
Ter(tesSUCCESS));
|
||||
checkMetrics(*this, env, 0, std::nullopt, 3, 3);
|
||||
|
||||
env(noop(bob));
|
||||
checkMetrics(*this, env, 0, std::nullopt, 4, 3);
|
||||
|
||||
// Past the target the fee escalates, so a base-fee transaction queues.
|
||||
env(noop(carol), Ter(terQUEUED));
|
||||
checkMetrics(*this, env, 1, std::nullopt, 4, 3);
|
||||
}
|
||||
|
||||
void
|
||||
testClosedLedgerCountsBatchInners(FeatureBitset features)
|
||||
{
|
||||
testcase("closed ledger counts batch inners");
|
||||
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
Env env{
|
||||
*this,
|
||||
makeSmallQueueConfig({{Keys::kMinimumTxnInLedgerStandalone, "3"}}),
|
||||
features,
|
||||
nullptr,
|
||||
beast::Severity::Error};
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
|
||||
// Fund across several ledgers so the TxQ metrics stay restricted.
|
||||
env.fund(XRP(10000), noripple(alice, bob));
|
||||
env.close(env.now() + 5s, 10000ms);
|
||||
env.fund(XRP(10000), noripple(carol));
|
||||
env.close(env.now() + 5s, 10000ms);
|
||||
|
||||
// Both inner transactions apply.
|
||||
auto const aliceSeq = env.seq(alice);
|
||||
env(batch::outer(alice, aliceSeq, batch::calcBatchFee(env, 0, 2), tfAllOrNothing),
|
||||
batch::Inner(pay(alice, bob, XRP(1)), aliceSeq + 1),
|
||||
batch::Inner(pay(alice, bob, XRP(1)), aliceSeq + 2),
|
||||
Ter(tesSUCCESS));
|
||||
|
||||
// The second inner transaction is unfunded, so neither applies.
|
||||
auto const carolSeq = env.seq(carol);
|
||||
env(batch::outer(carol, carolSeq, batch::calcBatchFee(env, 0, 2), tfAllOrNothing),
|
||||
batch::Inner(pay(carol, bob, XRP(1)), carolSeq + 1),
|
||||
batch::Inner(pay(carol, bob, XRP(100000)), carolSeq + 2),
|
||||
Ter(tesSUCCESS));
|
||||
checkMetrics(*this, env, 0, std::nullopt, 6, 3);
|
||||
|
||||
// The closed ledger holds 4 entries: alice's Batch, its two inner
|
||||
// transactions and carol's Batch. Each Batch counts 1 + 2.
|
||||
env.close();
|
||||
checkMetrics(*this, env, 0, 12, 0, 6);
|
||||
}
|
||||
|
||||
void
|
||||
testClosedLedgerMedianSkipsInners(FeatureBitset features)
|
||||
{
|
||||
testcase("closed ledger median skips batch inners");
|
||||
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
Env env{
|
||||
*this,
|
||||
makeSmallQueueConfig({{Keys::kMinimumTxnInLedgerStandalone, "3"}}),
|
||||
features,
|
||||
nullptr,
|
||||
beast::Severity::Error};
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
|
||||
// Fund across several ledgers so the TxQ metrics stay restricted.
|
||||
env.fund(XRP(10000), noripple(alice, bob));
|
||||
env.close(env.now() + 5s, 10000ms);
|
||||
env.fund(XRP(10000), noripple(carol));
|
||||
env.close(env.now() + 5s, 10000ms);
|
||||
|
||||
// Both pay 1000 times their base fee: fee level 256,000.
|
||||
auto const aliceSeq = env.seq(alice);
|
||||
env(batch::outer(alice, aliceSeq, batch::calcBatchFee(env, 0, 2) * 1000, tfAllOrNothing),
|
||||
batch::Inner(pay(alice, bob, XRP(1)), aliceSeq + 1),
|
||||
batch::Inner(pay(alice, bob, XRP(1)), aliceSeq + 2),
|
||||
Ter(tesSUCCESS));
|
||||
env(noop(bob), Fee(env.current()->fees().base * 1000));
|
||||
|
||||
// The inner transactions pay no fee and stay out of the median.
|
||||
env.close();
|
||||
checkMetrics(*this, env, 0, 8, 0, 4, 256, 256000);
|
||||
}
|
||||
|
||||
void
|
||||
testBatchNetworkOps(FeatureBitset features)
|
||||
{
|
||||
@@ -6390,6 +6570,10 @@ class Batch_test : public beast::unit_test::Suite
|
||||
testPseudoTxn(features);
|
||||
testOpenLedger(features);
|
||||
testBatchTxQueue(features);
|
||||
testOpenViewBatchInnerCount(features);
|
||||
testOpenLedgerCountsBatchInners(features);
|
||||
testClosedLedgerCountsBatchInners(features);
|
||||
testClosedLedgerMedianSkipsInners(features);
|
||||
testBatchNetworkOps(features);
|
||||
testBatchDelegate(features);
|
||||
testBatchDelegateConsent(features);
|
||||
|
||||
@@ -52,6 +52,11 @@ How fees escalate:
|
||||
- The formula is `( lastLedgerMedianFeeLevel *
|
||||
TransactionsInOpenLedger^2 / limit^2 )`,
|
||||
and returns a [fee level](#fee-level).
|
||||
- In `TransactionsInOpenLedger` and in the limit, a Batch transaction
|
||||
counts as 1 plus its inner transactions, which every server applies
|
||||
when it builds the ledger. The inner transactions in a closed ledger
|
||||
are counted with their Batch, and are left out of the median fee
|
||||
level because they pay no fee.
|
||||
|
||||
4. That may still be pretty small, but as more transactions get
|
||||
into the ledger, the fee level increases exponentially.
|
||||
|
||||
@@ -198,11 +198,13 @@ public:
|
||||
*/
|
||||
std::optional<std::size_t> txQMaxSize;
|
||||
/**
|
||||
* Number of transactions currently in the open ledger
|
||||
* Number of transactions currently in the open ledger, counting
|
||||
* each Batch as 1 plus its inner transactions
|
||||
*/
|
||||
std::size_t txInLedger{};
|
||||
/**
|
||||
* Number of transactions expected per ledger
|
||||
* Number of transactions expected per ledger, counting each Batch
|
||||
* as 1 plus its inner transactions
|
||||
*/
|
||||
std::size_t txPerLedger{};
|
||||
/**
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/RippleLedgerHash.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
@@ -109,6 +111,16 @@ increase(FeeLevel64 level, std::uint32_t increasePercent)
|
||||
.value_or(static_cast<FeeLevel64>(xrpl::kMuldivMax));
|
||||
}
|
||||
|
||||
/**
|
||||
* Open-ledger transaction count with each Batch weighted by its inner
|
||||
* transactions, which only the ledger build applies.
|
||||
*/
|
||||
static std::size_t
|
||||
openLedgerWeight(OpenView const& view)
|
||||
{
|
||||
return view.txCount() + view.batchInnerCount();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct MultiTxn
|
||||
@@ -670,7 +682,7 @@ TxQApplyImpl::tryClearAccountQueueUpThruTx()
|
||||
prevTxs_->first,
|
||||
feeLevelPaid_,
|
||||
preflightRes_,
|
||||
view_.txCount(),
|
||||
openLedgerWeight(view_),
|
||||
flags_,
|
||||
*metricsSnapshot_,
|
||||
jExt_);
|
||||
@@ -822,11 +834,15 @@ TxQ::FeeMetrics::update(
|
||||
TxQ::Setup const& setup)
|
||||
{
|
||||
std::vector<FeeLevel64> feeLevels;
|
||||
auto const txBegin = view.txs.begin();
|
||||
auto const txEnd = view.txs.end();
|
||||
auto const size = std::distance(txBegin, txEnd);
|
||||
feeLevels.reserve(size);
|
||||
std::for_each(txBegin, txEnd, [&](auto const& tx) {
|
||||
std::size_t size = 0;
|
||||
for (auto const& tx : view.txs)
|
||||
{
|
||||
// An inner transaction is counted with its Batch, and pays no fee.
|
||||
if (tx.first->isFlag(tfInnerBatchTxn))
|
||||
continue;
|
||||
++size;
|
||||
if (tx.first->getTxnType() == ttBATCH)
|
||||
size += tx.first->getFieldArray(sfRawTransactions).size();
|
||||
auto const maybeFeeLevel = getFeeLevelPaid(view, *tx.first);
|
||||
if (maybeFeeLevel.has_value())
|
||||
{
|
||||
@@ -839,11 +855,12 @@ TxQ::FeeMetrics::update(
|
||||
<< tx.first->getTransactionID() << " in ledger " << view.header().seq
|
||||
<< ": " << transToken(maybeFeeLevel.error());
|
||||
}
|
||||
});
|
||||
}
|
||||
std::ranges::sort(feeLevels);
|
||||
|
||||
JLOG((timeLeap ? j_.warn() : j_.debug()))
|
||||
<< "Ledger " << view.header().seq << " has " << size << " transactions. "
|
||||
<< "Ledger " << view.header().seq << " has " << size
|
||||
<< " transactions, counting Batch inner transactions. "
|
||||
<< "Ledgers are processing " << (timeLeap ? "slowly" : "as expected")
|
||||
<< ". Expected transactions is currently " << txnsExpected_ << " and multiplier is "
|
||||
<< escalationMultiplier_;
|
||||
@@ -886,7 +903,8 @@ TxQ::FeeMetrics::update(
|
||||
|
||||
// The median is taken over the transactions whose fee level could be
|
||||
// computed, while txnsExpected_ above deliberately uses the full
|
||||
// transaction count.
|
||||
// transaction count. Both skip inner Batch transactions: each Batch
|
||||
// counts 1 plus its inner transactions, and inner transactions pay no fee.
|
||||
if (feeLevels.empty())
|
||||
{
|
||||
escalationMultiplier_ = setup.minimumEscalationMultiplier;
|
||||
@@ -912,7 +930,7 @@ FeeLevel64
|
||||
TxQ::FeeMetrics::scaleFeeLevel(Snapshot const& snapshot, OpenView const& view)
|
||||
{
|
||||
// Transactions in the open ledger so far
|
||||
auto const current = view.txCount();
|
||||
auto const current = openLedgerWeight(view);
|
||||
|
||||
auto const target = snapshot.txnsExpected;
|
||||
auto const multiplier = snapshot.escalationMultiplier;
|
||||
@@ -977,7 +995,7 @@ TxQ::FeeMetrics::escalatedSeriesFeeLevel(
|
||||
AKA Transactions that will be in the open ledger when
|
||||
the first tx in the series is attempted.
|
||||
*/
|
||||
auto const current = view.txCount() + extraCount;
|
||||
auto const current = openLedgerWeight(view) + extraCount;
|
||||
/* Transactions that will be in the open ledger when
|
||||
the last tx in the series is attempted.
|
||||
*/
|
||||
@@ -1611,7 +1629,7 @@ TxQApplyImpl::applyImpl()
|
||||
JLOG(j_.trace()) << "Transaction " << txID_ << " from account " << accID_
|
||||
<< " has fee level of " << feeLevelPaid_ << " needs at least "
|
||||
<< requiredFeeLevel_ << " to get in the open ledger, which has "
|
||||
<< view_.txCount() << " entries.";
|
||||
<< openLedgerWeight(view_) << " entries.";
|
||||
|
||||
// Quick heuristic check to see if it's worth checking that this tx has a high enough fee to
|
||||
// clear all the txs in front of it in the queue.
|
||||
@@ -2077,7 +2095,7 @@ TxQ::getMetrics(OpenView const& view) const
|
||||
|
||||
result.txCount = byFee_.size();
|
||||
result.txQMaxSize = maxSize_;
|
||||
result.txInLedger = view.txCount();
|
||||
result.txInLedger = openLedgerWeight(view);
|
||||
result.txPerLedger = snapshot.txnsExpected;
|
||||
result.referenceFeeLevel = kBaseLevel;
|
||||
result.minProcessingFeeLevel =
|
||||
|
||||
Reference in New Issue
Block a user