mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Tx queue enhancements and RPC info (RIPD-1205, RIPD-1206):
* Account-related queue stats (RIPD-1205). Boolean "queue" parameter to account_info only if requesting the open ledger. * Account for the TxQ when autofilling sequence in sign-and-submit (RIPD-1206) * Tweak TxQ::accept edge case when choosing which tx to try next. * Labels for experimental "x_" submit parameters use correct separator. === Release Notes === ==== New features ==== When requesting `account_info` for the open ledger, include the `queue : true` to get extra information about any queued transactions for this account. (RIPD-1205). ==== Bug fixes ==== When using sign-and-submit mode to autofill a transaction's sequence number, the logic will not reuse a sequence number that is in the queue for this account. (RIPD-1206). Labels for experimental "x_queue_okay" and "x_assume_tx" parameters to `sign` and `submit` updated to use correct separator.
This commit is contained in:
@@ -403,6 +403,33 @@ public:
|
||||
env(noop(daria), fee(7000), queued);
|
||||
env(noop(edgar), fee(7000), queued);
|
||||
checkMetrics(env, 5, boost::none, 3, 2, 256);
|
||||
{
|
||||
auto& txQ = env.app().getTxQ();
|
||||
auto aliceStat = txQ.getAccountTxs(alice.id(),
|
||||
env.app().config(), *env.current());
|
||||
if (BEAST_EXPECT(aliceStat))
|
||||
{
|
||||
BEAST_EXPECT(aliceStat->size() == 1);
|
||||
BEAST_EXPECT(aliceStat->begin()->second.feeLevel == 256);
|
||||
BEAST_EXPECT(aliceStat->begin()->second.lastValid &&
|
||||
*aliceStat->begin()->second.lastValid == 8);
|
||||
BEAST_EXPECT(!aliceStat->begin()->second.consequences);
|
||||
}
|
||||
|
||||
auto bobStat = txQ.getAccountTxs(bob.id(),
|
||||
env.app().config(), *env.current());
|
||||
if (BEAST_EXPECT(bobStat))
|
||||
{
|
||||
BEAST_EXPECT(bobStat->size() == 1);
|
||||
BEAST_EXPECT(bobStat->begin()->second.feeLevel = 7000 * 256 / 10);
|
||||
BEAST_EXPECT(!bobStat->begin()->second.lastValid);
|
||||
BEAST_EXPECT(!bobStat->begin()->second.consequences);
|
||||
}
|
||||
|
||||
auto noStat = txQ.getAccountTxs(Account::master.id(),
|
||||
env.app().config(), *env.current());
|
||||
BEAST_EXPECT(!noStat);
|
||||
}
|
||||
|
||||
env.close();
|
||||
checkMetrics(env, 1, 6, 4, 3, 256);
|
||||
@@ -719,6 +746,30 @@ public:
|
||||
++aliceSeq;
|
||||
}
|
||||
checkMetrics(env, 8, 8, 5, 4, 257);
|
||||
{
|
||||
auto& txQ = env.app().getTxQ();
|
||||
auto aliceStat = txQ.getAccountTxs(alice.id(),
|
||||
env.app().config(), *env.current());
|
||||
std::int64_t fee = 10;
|
||||
auto seq = env.seq(alice);
|
||||
if (BEAST_EXPECT(aliceStat))
|
||||
{
|
||||
BEAST_EXPECT(aliceStat->size() == 7);
|
||||
for (auto const& tx : *aliceStat)
|
||||
{
|
||||
BEAST_EXPECT(tx.first == seq);
|
||||
BEAST_EXPECT(tx.second.feeLevel == mulDiv(fee, 256, 10).second);
|
||||
BEAST_EXPECT(tx.second.lastValid);
|
||||
BEAST_EXPECT((tx.second.consequences &&
|
||||
tx.second.consequences->fee == drops(fee) &&
|
||||
tx.second.consequences->potentialSpend == drops(0) &&
|
||||
tx.second.consequences->category == TxConsequences::normal) ||
|
||||
tx.first == env.seq(alice) + 6);
|
||||
++seq;
|
||||
fee = (fee + 1) * 125 / 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alice attempts to add another item to the queue,
|
||||
// but you can't force your own earlier txn off the
|
||||
@@ -1557,11 +1608,47 @@ public:
|
||||
!RPC::contains_error(fee[jss::result])))
|
||||
{
|
||||
auto const& result = fee[jss::result];
|
||||
BEAST_EXPECT(result.isMember(jss::drops));
|
||||
BEAST_EXPECT(result.isMember(jss::levels));
|
||||
BEAST_EXPECT(result.isMember(jss::current_ledger_size));
|
||||
BEAST_EXPECT(result.isMember(jss::current_queue_size));
|
||||
BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
|
||||
BEAST_EXPECT(!result.isMember(jss::max_queue_size));
|
||||
BEAST_EXPECT(result.isMember(jss::drops));
|
||||
auto const& drops = result[jss::drops];
|
||||
BEAST_EXPECT(drops.isMember(jss::base_fee));
|
||||
BEAST_EXPECT(drops.isMember(jss::median_fee));
|
||||
BEAST_EXPECT(drops.isMember(jss::minimum_fee));
|
||||
BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
|
||||
BEAST_EXPECT(result.isMember(jss::levels));
|
||||
auto const& levels = result[jss::levels];
|
||||
BEAST_EXPECT(levels.isMember(jss::median_level));
|
||||
BEAST_EXPECT(levels.isMember(jss::minimum_level));
|
||||
BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
|
||||
BEAST_EXPECT(levels.isMember(jss::reference_level));
|
||||
}
|
||||
|
||||
env.close();
|
||||
|
||||
fee = env.rpc("fee");
|
||||
|
||||
if (BEAST_EXPECT(fee.isMember(jss::result) &&
|
||||
!RPC::contains_error(fee[jss::result])))
|
||||
{
|
||||
auto const& result = fee[jss::result];
|
||||
BEAST_EXPECT(result.isMember(jss::current_ledger_size));
|
||||
BEAST_EXPECT(result.isMember(jss::current_queue_size));
|
||||
BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
|
||||
BEAST_EXPECT(result.isMember(jss::max_queue_size));
|
||||
auto const& drops = result[jss::drops];
|
||||
BEAST_EXPECT(drops.isMember(jss::base_fee));
|
||||
BEAST_EXPECT(drops.isMember(jss::median_fee));
|
||||
BEAST_EXPECT(drops.isMember(jss::minimum_fee));
|
||||
BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
|
||||
BEAST_EXPECT(result.isMember(jss::levels));
|
||||
auto const& levels = result[jss::levels];
|
||||
BEAST_EXPECT(levels.isMember(jss::median_level));
|
||||
BEAST_EXPECT(levels.isMember(jss::minimum_level));
|
||||
BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
|
||||
BEAST_EXPECT(levels.isMember(jss::reference_level));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1668,6 +1755,422 @@ public:
|
||||
BEAST_EXPECT(env.seq(alice) == aliceSeq + 4);
|
||||
}
|
||||
|
||||
void testSignAndSubmitSequence()
|
||||
{
|
||||
testcase("Autofilled sequence should account for TxQ");
|
||||
using namespace jtx;
|
||||
Env env(*this, makeConfig({ {"minimum_txn_in_ledger_standalone", "6"} }),
|
||||
features(featureFeeEscalation));
|
||||
Env_ss envs(env);
|
||||
auto const& txQ = env.app().getTxQ();
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
env.fund(XRP(100000), alice, bob);
|
||||
|
||||
auto params = Json::Value(Json::objectValue);
|
||||
// Max fee = 50k drops
|
||||
params[jss::fee_mult_max] = 100;
|
||||
params["x_queue_okay"] = true;
|
||||
|
||||
fillQueue(env, alice);
|
||||
checkMetrics(env, 0, boost::none, 7, 6, 256);
|
||||
|
||||
// Queue up several transactions for alice sign-and-submit
|
||||
auto const aliceSeq = env.seq(alice);
|
||||
auto const lastLedgerSeq = env.current()->info().seq + 2;
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
if (i == 2)
|
||||
envs(noop(alice), fee(none), seq(none),
|
||||
json(jss::LastLedgerSequence, lastLedgerSeq),
|
||||
ter(terQUEUED))(params);
|
||||
else
|
||||
envs(noop(alice), fee(none), seq(none),
|
||||
ter(terQUEUED))(params);
|
||||
}
|
||||
checkMetrics(env, 5, boost::none, 7, 6, 256);
|
||||
{
|
||||
auto aliceStat = txQ.getAccountTxs(alice.id(),
|
||||
env.app().config(), *env.current());
|
||||
if (BEAST_EXPECT(aliceStat))
|
||||
{
|
||||
auto seq = aliceSeq;
|
||||
BEAST_EXPECT(aliceStat->size() == 5);
|
||||
for (auto const& tx : *aliceStat)
|
||||
{
|
||||
BEAST_EXPECT(tx.first == seq);
|
||||
BEAST_EXPECT(tx.second.feeLevel == 25600);
|
||||
if(seq == aliceSeq + 2)
|
||||
{
|
||||
BEAST_EXPECT(tx.second.lastValid &&
|
||||
*tx.second.lastValid == lastLedgerSeq);
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!tx.second.lastValid);
|
||||
}
|
||||
++seq;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Put some txs in the queue for bob.
|
||||
// Give them a higher fee so they'll beat alice's.
|
||||
for (int i = 0; i < 8; ++i)
|
||||
envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
|
||||
checkMetrics(env, 13, boost::none, 7, 6, 256);
|
||||
|
||||
env.close();
|
||||
checkMetrics(env, 5, 14, 8, 7, 256);
|
||||
// Put some more txs in the queue for bob.
|
||||
// Give them a higher fee so they'll beat alice's.
|
||||
fillQueue(env, bob);
|
||||
for(int i = 0; i < 9; ++i)
|
||||
envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
|
||||
checkMetrics(env, 14, 14, 8, 7, 25601);
|
||||
env.close();
|
||||
// Put some more txs in the queue for bob.
|
||||
// Give them a higher fee so they'll beat alice's.
|
||||
fillQueue(env, bob);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
|
||||
checkMetrics(env, 15, 16, 9, 8, 256);
|
||||
env.close();
|
||||
checkMetrics(env, 4, 18, 10, 9, 256);
|
||||
{
|
||||
// Bob has nothing left in the queue.
|
||||
auto bobStat = txQ.getAccountTxs(bob.id(),
|
||||
env.app().config(), *env.current());
|
||||
BEAST_EXPECT(!bobStat);
|
||||
}
|
||||
// Verify alice's tx got dropped as we BEAST_EXPECT, and that there's
|
||||
// a gap in her queued txs.
|
||||
{
|
||||
auto aliceStat = txQ.getAccountTxs(alice.id(),
|
||||
env.app().config(), *env.current());
|
||||
if (BEAST_EXPECT(aliceStat))
|
||||
{
|
||||
auto seq = aliceSeq;
|
||||
BEAST_EXPECT(aliceStat->size() == 4);
|
||||
for (auto const& tx : *aliceStat)
|
||||
{
|
||||
// Skip over the missing one.
|
||||
if (seq == aliceSeq + 2)
|
||||
++seq;
|
||||
|
||||
BEAST_EXPECT(tx.first == seq);
|
||||
BEAST_EXPECT(tx.second.feeLevel == 25600);
|
||||
BEAST_EXPECT(!tx.second.lastValid);
|
||||
++seq;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now, fill the gap.
|
||||
envs(noop(alice), fee(none), seq(none), ter(terQUEUED))(params);
|
||||
checkMetrics(env, 5, 18, 10, 9, 256);
|
||||
{
|
||||
auto aliceStat = txQ.getAccountTxs(alice.id(),
|
||||
env.app().config(), *env.current());
|
||||
if (BEAST_EXPECT(aliceStat))
|
||||
{
|
||||
auto seq = aliceSeq;
|
||||
BEAST_EXPECT(aliceStat->size() == 5);
|
||||
for (auto const& tx : *aliceStat)
|
||||
{
|
||||
BEAST_EXPECT(tx.first == seq);
|
||||
BEAST_EXPECT(tx.second.feeLevel == 25600);
|
||||
BEAST_EXPECT(!tx.second.lastValid);
|
||||
++seq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env.close();
|
||||
checkMetrics(env, 0, 20, 5, 10, 256);
|
||||
{
|
||||
// Bob's data has been cleaned up.
|
||||
auto bobStat = txQ.getAccountTxs(bob.id(),
|
||||
env.app().config(), *env.current());
|
||||
BEAST_EXPECT(!bobStat);
|
||||
}
|
||||
{
|
||||
auto aliceStat = txQ.getAccountTxs(alice.id(),
|
||||
env.app().config(), *env.current());
|
||||
BEAST_EXPECT(!aliceStat);
|
||||
}
|
||||
}
|
||||
|
||||
void testAccountInfo()
|
||||
{
|
||||
using namespace jtx;
|
||||
Env env(*this, makeConfig({ { "minimum_txn_in_ledger_standalone", "3" } }),
|
||||
features(featureFeeEscalation));
|
||||
Env_ss envs(env);
|
||||
|
||||
Account const alice{ "alice" };
|
||||
env.fund(XRP(1000000), alice);
|
||||
env.close();
|
||||
|
||||
auto const withQueue =
|
||||
R"({ "account": ")" + alice.human() +
|
||||
R"(", "queue": true })";
|
||||
auto const withoutQueue =
|
||||
R"({ "account": ")" + alice.human() +
|
||||
R"("})";
|
||||
auto const prevLedgerWithQueue =
|
||||
R"({ "account": ")" + alice.human() +
|
||||
R"(", "queue": true, "ledger_index": 3 })";
|
||||
BEAST_EXPECT(env.current()->info().seq > 3);
|
||||
|
||||
auto submitParams = Json::Value(Json::objectValue);
|
||||
// Max fee = 100 drops
|
||||
submitParams[jss::fee_mult_max] = 10;
|
||||
submitParams["x_queue_okay"] = true;
|
||||
|
||||
{
|
||||
// account_info without the "queue" argument.
|
||||
auto const info = env.rpc("json", "account_info", withoutQueue);
|
||||
BEAST_EXPECT(info.isMember(jss::result) &&
|
||||
info[jss::result].isMember(jss::account_data));
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
|
||||
}
|
||||
{
|
||||
// account_info with the "queue" argument.
|
||||
auto const info = env.rpc("json", "account_info", withQueue);
|
||||
BEAST_EXPECT(info.isMember(jss::result) &&
|
||||
info[jss::result].isMember(jss::account_data));
|
||||
auto const& result = info[jss::result];
|
||||
BEAST_EXPECT(result.isMember(jss::queue_data));
|
||||
auto const& queue_data = result[jss::queue_data];
|
||||
BEAST_EXPECT(queue_data.isObject());
|
||||
BEAST_EXPECT(queue_data.isMember(jss::txn_count));
|
||||
BEAST_EXPECT(queue_data[jss::txn_count] == 0);
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::transactions));
|
||||
}
|
||||
checkMetrics(env, 0, 6, 0, 3, 256);
|
||||
|
||||
fillQueue(env, alice);
|
||||
checkMetrics(env, 0, 6, 4, 3, 256);
|
||||
|
||||
{
|
||||
auto const info = env.rpc("json", "account_info", withQueue);
|
||||
BEAST_EXPECT(info.isMember(jss::result) &&
|
||||
info[jss::result].isMember(jss::account_data));
|
||||
auto const& result = info[jss::result];
|
||||
BEAST_EXPECT(result.isMember(jss::queue_data));
|
||||
auto const& queue_data = result[jss::queue_data];
|
||||
BEAST_EXPECT(queue_data.isObject());
|
||||
BEAST_EXPECT(queue_data.isMember(jss::txn_count));
|
||||
BEAST_EXPECT(queue_data[jss::txn_count] == 0);
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::transactions));
|
||||
}
|
||||
|
||||
envs(noop(alice), fee(none), seq(none), ter(terQUEUED))(submitParams);
|
||||
envs(noop(alice), fee(none), seq(none), ter(terQUEUED))(submitParams);
|
||||
envs(noop(alice), fee(none), seq(none), ter(terQUEUED))(submitParams);
|
||||
envs(noop(alice), fee(none), seq(none), ter(terQUEUED))(submitParams);
|
||||
checkMetrics(env, 4, 6, 4, 3, 256);
|
||||
|
||||
{
|
||||
auto const info = env.rpc("json", "account_info", withQueue);
|
||||
BEAST_EXPECT(info.isMember(jss::result) &&
|
||||
info[jss::result].isMember(jss::account_data));
|
||||
auto const& result = info[jss::result];
|
||||
auto const& data = result[jss::account_data];
|
||||
BEAST_EXPECT(result.isMember(jss::queue_data));
|
||||
auto const& queue_data = result[jss::queue_data];
|
||||
BEAST_EXPECT(queue_data.isObject());
|
||||
BEAST_EXPECT(queue_data.isMember(jss::txn_count));
|
||||
BEAST_EXPECT(queue_data[jss::txn_count] == 4);
|
||||
BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
|
||||
BEAST_EXPECT(queue_data[jss::lowest_sequence] == data[jss::Sequence]);
|
||||
BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
|
||||
BEAST_EXPECT(queue_data[jss::highest_sequence] ==
|
||||
data[jss::Sequence].asUInt() +
|
||||
queue_data[jss::txn_count].asUInt() - 1);
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
|
||||
BEAST_EXPECT(queue_data.isMember(jss::transactions));
|
||||
auto const& queued = queue_data[jss::transactions];
|
||||
BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
|
||||
for (unsigned i = 0; i < queued.size(); ++i)
|
||||
{
|
||||
auto const& item = queued[i];
|
||||
BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
|
||||
BEAST_EXPECT(item[jss::fee_level] == "2560");
|
||||
BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
|
||||
|
||||
if (i == queued.size() - 1)
|
||||
{
|
||||
BEAST_EXPECT(!item.isMember(jss::fee));
|
||||
BEAST_EXPECT(!item.isMember(jss::max_spend_drops));
|
||||
BEAST_EXPECT(!item.isMember(jss::auth_change));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(item.isMember(jss::fee));
|
||||
BEAST_EXPECT(item[jss::fee] == "100");
|
||||
BEAST_EXPECT(item.isMember(jss::max_spend_drops));
|
||||
BEAST_EXPECT(item[jss::max_spend_drops] == "100");
|
||||
BEAST_EXPECT(item.isMember(jss::auth_change));
|
||||
BEAST_EXPECT(!item[jss::auth_change].asBool());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Queue up a blocker
|
||||
envs(fset(alice, asfAccountTxnID), fee(none), seq(none),
|
||||
json(jss::LastLedgerSequence, 10),
|
||||
ter(terQUEUED))(submitParams);
|
||||
checkMetrics(env, 5, 6, 4, 3, 256);
|
||||
|
||||
{
|
||||
auto const info = env.rpc("json", "account_info", withQueue);
|
||||
BEAST_EXPECT(info.isMember(jss::result) &&
|
||||
info[jss::result].isMember(jss::account_data));
|
||||
auto const& result = info[jss::result];
|
||||
auto const& data = result[jss::account_data];
|
||||
BEAST_EXPECT(result.isMember(jss::queue_data));
|
||||
auto const& queue_data = result[jss::queue_data];
|
||||
BEAST_EXPECT(queue_data.isObject());
|
||||
BEAST_EXPECT(queue_data.isMember(jss::txn_count));
|
||||
BEAST_EXPECT(queue_data[jss::txn_count] == 5);
|
||||
BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
|
||||
BEAST_EXPECT(queue_data[jss::lowest_sequence] == data[jss::Sequence]);
|
||||
BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
|
||||
BEAST_EXPECT(queue_data[jss::highest_sequence] ==
|
||||
data[jss::Sequence].asUInt() +
|
||||
queue_data[jss::txn_count].asUInt() - 1);
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
|
||||
BEAST_EXPECT(queue_data.isMember(jss::transactions));
|
||||
auto const& queued = queue_data[jss::transactions];
|
||||
BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
|
||||
for (unsigned i = 0; i < queued.size(); ++i)
|
||||
{
|
||||
auto const& item = queued[i];
|
||||
BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
|
||||
BEAST_EXPECT(item[jss::fee_level] == "2560");
|
||||
|
||||
if (i == queued.size() - 1)
|
||||
{
|
||||
BEAST_EXPECT(!item.isMember(jss::fee));
|
||||
BEAST_EXPECT(!item.isMember(jss::max_spend_drops));
|
||||
BEAST_EXPECT(!item.isMember(jss::auth_change));
|
||||
BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
|
||||
BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(item.isMember(jss::fee));
|
||||
BEAST_EXPECT(item[jss::fee] == "100");
|
||||
BEAST_EXPECT(item.isMember(jss::max_spend_drops));
|
||||
BEAST_EXPECT(item[jss::max_spend_drops] == "100");
|
||||
BEAST_EXPECT(item.isMember(jss::auth_change));
|
||||
BEAST_EXPECT(!item[jss::auth_change].asBool());
|
||||
BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
envs(noop(alice), fee(none), seq(none), ter(telCAN_NOT_QUEUE))(submitParams);
|
||||
checkMetrics(env, 5, 6, 4, 3, 256);
|
||||
|
||||
{
|
||||
auto const info = env.rpc("json", "account_info", withQueue);
|
||||
BEAST_EXPECT(info.isMember(jss::result) &&
|
||||
info[jss::result].isMember(jss::account_data));
|
||||
auto const& result = info[jss::result];
|
||||
auto const& data = result[jss::account_data];
|
||||
BEAST_EXPECT(result.isMember(jss::queue_data));
|
||||
auto const& queue_data = result[jss::queue_data];
|
||||
BEAST_EXPECT(queue_data.isObject());
|
||||
BEAST_EXPECT(queue_data.isMember(jss::txn_count));
|
||||
BEAST_EXPECT(queue_data[jss::txn_count] == 5);
|
||||
BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
|
||||
BEAST_EXPECT(queue_data[jss::lowest_sequence] == data[jss::Sequence]);
|
||||
BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
|
||||
BEAST_EXPECT(queue_data[jss::highest_sequence] ==
|
||||
data[jss::Sequence].asUInt() +
|
||||
queue_data[jss::txn_count].asUInt() - 1);
|
||||
BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
|
||||
BEAST_EXPECT(queue_data[jss::auth_change_queued].asBool());
|
||||
BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
|
||||
BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "500");
|
||||
BEAST_EXPECT(queue_data.isMember(jss::transactions));
|
||||
auto const& queued = queue_data[jss::transactions];
|
||||
BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
|
||||
for (unsigned i = 0; i < queued.size(); ++i)
|
||||
{
|
||||
auto const& item = queued[i];
|
||||
BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
|
||||
BEAST_EXPECT(item[jss::fee_level] == "2560");
|
||||
|
||||
if (i == queued.size() - 1)
|
||||
{
|
||||
BEAST_EXPECT(item.isMember(jss::fee));
|
||||
BEAST_EXPECT(item[jss::fee] == "100");
|
||||
BEAST_EXPECT(item.isMember(jss::max_spend_drops));
|
||||
BEAST_EXPECT(item[jss::max_spend_drops] == "100");
|
||||
BEAST_EXPECT(item.isMember(jss::auth_change));
|
||||
BEAST_EXPECT(item[jss::auth_change].asBool());
|
||||
BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
|
||||
BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(item.isMember(jss::fee));
|
||||
BEAST_EXPECT(item[jss::fee] == "100");
|
||||
BEAST_EXPECT(item.isMember(jss::max_spend_drops));
|
||||
BEAST_EXPECT(item[jss::max_spend_drops] == "100");
|
||||
BEAST_EXPECT(item.isMember(jss::auth_change));
|
||||
BEAST_EXPECT(!item[jss::auth_change].asBool());
|
||||
BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const info = env.rpc("json", "account_info", prevLedgerWithQueue);
|
||||
BEAST_EXPECT(info.isMember(jss::result) &&
|
||||
RPC::contains_error(info[jss::result]));
|
||||
}
|
||||
|
||||
env.close();
|
||||
checkMetrics(env, 1, 8, 5, 4, 256);
|
||||
env.close();
|
||||
checkMetrics(env, 0, 10, 1, 5, 256);
|
||||
|
||||
{
|
||||
auto const info = env.rpc("json", "account_info", withQueue);
|
||||
BEAST_EXPECT(info.isMember(jss::result) &&
|
||||
info[jss::result].isMember(jss::account_data));
|
||||
auto const& result = info[jss::result];
|
||||
BEAST_EXPECT(result.isMember(jss::queue_data));
|
||||
auto const& queue_data = result[jss::queue_data];
|
||||
BEAST_EXPECT(queue_data.isObject());
|
||||
BEAST_EXPECT(queue_data.isMember(jss::txn_count));
|
||||
BEAST_EXPECT(queue_data[jss::txn_count] == 0);
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
|
||||
BEAST_EXPECT(!queue_data.isMember(jss::transactions));
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
testQueue();
|
||||
@@ -1687,6 +2190,8 @@ public:
|
||||
testConsequences();
|
||||
testRPC();
|
||||
testExpirationReplacement();
|
||||
testSignAndSubmitSequence();
|
||||
testAccountInfo();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user