Don't use tapENABLE_TESTING for TxQ.

* Enable FeeEscalation feature in TxQ tests.
* Elapsed time for simulated consensus.
This commit is contained in:
Edward Hennis
2015-12-15 14:06:50 -05:00
committed by Vinnie Falco
parent a5583de6e6
commit 1bce85d7b6
10 changed files with 136 additions and 193 deletions

View File

@@ -70,7 +70,8 @@ public:
server in standalone mode and SHOULD NOT be used during the normal server in standalone mode and SHOULD NOT be used during the normal
consensus process. consensus process.
*/ */
virtual void simulate () = 0; virtual void simulate (
boost::optional<std::chrono::milliseconds> consensusDelay) = 0;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -902,13 +902,14 @@ bool LedgerConsensusImp::peerPosition (LedgerProposal::ref newPosition)
return true; return true;
} }
void LedgerConsensusImp::simulate () void LedgerConsensusImp::simulate (
boost::optional<std::chrono::milliseconds> consensusDelay)
{ {
std::lock_guard<std::recursive_mutex> _(lock_); std::lock_guard<std::recursive_mutex> _(lock_);
JLOG (j_.info) << "Simulating consensus"; JLOG (j_.info) << "Simulating consensus";
closeLedger (); closeLedger ();
mCurrentMSeconds = 100ms; mCurrentMSeconds = consensusDelay.value_or(100ms);
beginAccept (true); beginAccept (true);
JLOG (j_.info) << "Simulation complete"; JLOG (j_.info) << "Simulation complete";
} }

View File

@@ -150,7 +150,8 @@ public:
*/ */
bool peerPosition (LedgerProposal::ref newPosition) override; bool peerPosition (LedgerProposal::ref newPosition) override;
void simulate () override; void simulate(
boost::optional<std::chrono::milliseconds> consensusDelay) override;
private: private:
/** /**

View File

@@ -350,7 +350,8 @@ public:
Json::Value getServerInfo (bool human, bool admin) override; Json::Value getServerInfo (bool human, bool admin) override;
void clearLedgerFetch () override; void clearLedgerFetch () override;
Json::Value getLedgerFetchInfo () override; Json::Value getLedgerFetchInfo () override;
std::uint32_t acceptLedger () override; std::uint32_t acceptLedger (
boost::optional<std::chrono::milliseconds> consensusDelay) override;
uint256 getConsensusLCL () override; uint256 getConsensusLCL () override;
void reportFeeChange () override; void reportFeeChange () override;
@@ -2465,7 +2466,8 @@ bool NetworkOPsImp::unsubBook (std::uint64_t uSeq, Book const& book)
return true; return true;
} }
std::uint32_t NetworkOPsImp::acceptLedger () std::uint32_t NetworkOPsImp::acceptLedger (
boost::optional<std::chrono::milliseconds> consensusDelay)
{ {
// This code-path is exclusively used when the server is in standalone // This code-path is exclusively used when the server is in standalone
// mode via `ledger_accept` // mode via `ledger_accept`
@@ -2477,7 +2479,7 @@ std::uint32_t NetworkOPsImp::acceptLedger ()
// FIXME Could we improve on this and remove the need for a specialized // FIXME Could we improve on this and remove the need for a specialized
// API in LedgerConsensus? // API in LedgerConsensus?
beginConsensus (m_ledgerMaster.getClosedLedger ()->getHash ()); beginConsensus (m_ledgerMaster.getClosedLedger ()->getHash ());
mLedgerConsensus->simulate (); mLedgerConsensus->simulate (consensusDelay);
return m_ledgerMaster.getCurrentLedger ()->info().seq; return m_ledgerMaster.getCurrentLedger ()->info().seq;
} }

View File

@@ -190,7 +190,8 @@ public:
performs a virtual consensus round, with all the transactions we are performs a virtual consensus round, with all the transactions we are
proposing being accepted. proposing being accepted.
*/ */
virtual std::uint32_t acceptLedger () = 0; virtual std::uint32_t acceptLedger (
boost::optional<std::chrono::milliseconds> consensusDelay = boost::none) = 0;
virtual uint256 getConsensusLCL () = 0; virtual uint256 getConsensusLCL () = 0;

View File

@@ -214,8 +214,7 @@ public:
@return Whether any txs were added to the view. @return Whether any txs were added to the view.
*/ */
bool bool
accept(Application& app, OpenView& view, accept(Application& app, OpenView& view);
ApplyFlags flags = tapNONE);
/** /**
We have a new last validated ledger, update and clean up the We have a new last validated ledger, update and clean up the
@@ -233,8 +232,7 @@ public:
*/ */
void void
processValidatedLedger(Application& app, processValidatedLedger(Application& app,
OpenView const& view, bool timeLeap, OpenView const& view, bool timeLeap);
ApplyFlags flags = tapNONE);
/** Used by tests only. /** Used by tests only.
*/ */

View File

@@ -304,9 +304,8 @@ TxQ::apply(Application& app, OpenView& view,
ApplyFlags flags, beast::Journal j) ApplyFlags flags, beast::Journal j)
{ {
auto const allowEscalation = auto const allowEscalation =
(flags & tapENABLE_TESTING) || (view.rules().enabled(featureFeeEscalation,
(view.rules().enabled(featureFeeEscalation, app.config().features));
app.config().features));
if (!allowEscalation) if (!allowEscalation)
{ {
return ripple::apply(app, view, *tx, flags, j); return ripple::apply(app, view, *tx, flags, j);
@@ -502,11 +501,9 @@ TxQ::apply(Application& app, OpenView& view,
void void
TxQ::processValidatedLedger(Application& app, TxQ::processValidatedLedger(Application& app,
OpenView const& view, bool timeLeap, OpenView const& view, bool timeLeap)
ApplyFlags flags)
{ {
auto const allowEscalation = auto const allowEscalation =
(flags & tapENABLE_TESTING) ||
(view.rules().enabled(featureFeeEscalation, (view.rules().enabled(featureFeeEscalation,
app.config().features)); app.config().features));
if (!allowEscalation) if (!allowEscalation)
@@ -560,10 +557,9 @@ TxQ::processValidatedLedger(Application& app,
bool bool
TxQ::accept(Application& app, TxQ::accept(Application& app,
OpenView& view, ApplyFlags flags) OpenView& view)
{ {
auto const allowEscalation = auto const allowEscalation =
(flags & tapENABLE_TESTING) ||
(view.rules().enabled(featureFeeEscalation, (view.rules().enabled(featureFeeEscalation,
app.config().features)); app.config().features));
if (!allowEscalation) if (!allowEscalation)

View File

@@ -20,9 +20,11 @@
#include <ripple/app/main/Application.h> #include <ripple/app/main/Application.h>
#include <ripple/app/misc/TxQ.h> #include <ripple/app/misc/TxQ.h>
#include <ripple/app/ledger/LedgerConsensus.h> #include <ripple/app/ledger/LedgerConsensus.h>
#include <ripple/app/tx/apply.h>
#include <ripple/core/LoadFeeTrack.h> #include <ripple/core/LoadFeeTrack.h>
#include <ripple/basics/Log.h> #include <ripple/basics/Log.h>
#include <ripple/basics/TestSuite.h> #include <ripple/basics/TestSuite.h>
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/JsonFields.h> #include <ripple/protocol/JsonFields.h>
#include <ripple/protocol/STTx.h> #include <ripple/protocol/STTx.h>
#include <ripple/test/jtx.h> #include <ripple/test/jtx.h>
@@ -58,41 +60,6 @@ class TxQ_test : public TestSuite
expect(metrics.expFeeLevel == expectedCurFeeLevel, "expFeeLevel"); expect(metrics.expFeeLevel == expectedCurFeeLevel, "expFeeLevel");
} }
void
close(jtx::Env& env, size_t expectedTxSetSize, bool timeLeap = false)
{
{
auto const view = env.current();
expect(view->txCount() == expectedTxSetSize, "TxSet size mismatch");
}
env.close();
}
void
submit(jtx::Env& env, jtx::JTx const& jt)
{
// Env checks this, but this test shouldn't
// generate any malformed txns.
expect(jt.stx);
bool didApply;
TER ter;
env.app().openLedger().modify(
[&](OpenView& view, beast::Journal j)
{
std::tie(ter, didApply) =
env.app().getTxQ().apply(env.app(),
view, jt.stx, tapENABLE_TESTING,
env.journal);
return didApply;
}
);
env.postconditions(jt, ter, didApply);
}
static static
std::unique_ptr<Config> std::unique_ptr<Config>
makeConfig() makeConfig()
@@ -111,8 +78,9 @@ public:
void testQueue() void testQueue()
{ {
using namespace jtx; using namespace jtx;
using namespace std::chrono;
Env env(*this, makeConfig()); Env env(*this, makeConfig(), features(featureFeeEscalation));
auto& txq = env.app().getTxQ(); auto& txq = env.app().getTxQ();
txq.setMinimumTx(3); txq.setMinimumTx(3);
@@ -137,14 +105,12 @@ public:
checkMetrics(env, 0, boost::none, 4, 3, 256, 500); checkMetrics(env, 0, boost::none, 4, 3, 256, 500);
// Alice - price starts exploding: held // Alice - price starts exploding: held
submit(env, env(noop(alice), queued);
env.jt(noop(alice), queued));
checkMetrics(env, 1, boost::none, 4, 3, 256, 500); checkMetrics(env, 1, boost::none, 4, 3, 256, 500);
// Alice - Alice is already in the queue, so can't hold. // Alice - Alice is already in the queue, so can't hold.
submit(env, env(noop(alice), seq(env.seq(alice) + 1),
env.jt(noop(alice), seq(env.seq(alice) + 1), ter(telINSUF_FEE_P));
ter(telINSUF_FEE_P)));
checkMetrics(env, 1, boost::none, 4, 3, 256, 500); checkMetrics(env, 1, boost::none, 4, 3, 256, 500);
auto openLedgerFee = auto openLedgerFee =
@@ -154,22 +120,19 @@ public:
}; };
// Alice's next transaction - // Alice's next transaction -
// fails because the item in the TxQ hasn't applied. // fails because the item in the TxQ hasn't applied.
submit(env, env(noop(alice), openLedgerFee(),
env.jt(noop(alice), openLedgerFee(), seq(env.seq(alice) + 1), ter(terPRE_SEQ));
seq(env.seq(alice) + 1), ter(terPRE_SEQ)));
checkMetrics(env, 1, boost::none, 4, 3, 256, 500); checkMetrics(env, 1, boost::none, 4, 3, 256, 500);
// Bob with really high fee - applies // Bob with really high fee - applies
submit(env, env(noop(bob), openLedgerFee());
env.jt(noop(bob), openLedgerFee()));
checkMetrics(env, 1, boost::none, 5, 3, 256, 500); checkMetrics(env, 1, boost::none, 5, 3, 256, 500);
// Daria with low fee: hold // Daria with low fee: hold
submit(env, env(noop(daria), fee(1000), queued);
env.jt(noop(daria), fee(1000), queued));
checkMetrics(env, 2, boost::none, 5, 3, 256, 500); checkMetrics(env, 2, boost::none, 5, 3, 256, 500);
close(env, 5); env.close();
// Verify that the held transactions got applied // Verify that the held transactions got applied
auto lastMedian = 500; auto lastMedian = 500;
checkMetrics(env, 0, 10, 2, 5, 256, lastMedian); checkMetrics(env, 0, 10, 2, 5, 256, lastMedian);
@@ -181,27 +144,19 @@ public:
checkMetrics(env, 0, 10, 6, 5, 256, lastMedian); checkMetrics(env, 0, 10, 6, 5, 256, lastMedian);
// Now get a bunch of transactions held. // Now get a bunch of transactions held.
submit(env, env(noop(alice), fee(12), queued);
env.jt(noop(alice), fee(12), queued));
checkMetrics(env, 1, 10, 6, 5, 256, lastMedian); checkMetrics(env, 1, 10, 6, 5, 256, lastMedian);
submit(env, env(noop(bob), fee(10), queued); // won't clear the queue
env.jt(noop(bob), fee(10), queued)); // won't clear the queue env(noop(charlie), fee(20), queued);
submit(env, env(noop(daria), fee(15), queued);
env.jt(noop(charlie), fee(20), queued)); env(noop(elmo), fee(11), queued);
submit(env, env(noop(fred), fee(19), queued);
env.jt(noop(daria), fee(15), queued)); env(noop(gwen), fee(16), queued);
submit(env, env(noop(hank), fee(18), queued);
env.jt(noop(elmo), fee(11), queued));
submit(env,
env.jt(noop(fred), fee(19), queued));
submit(env,
env.jt(noop(gwen), fee(16), queued));
submit(env,
env.jt(noop(hank), fee(18), queued));
checkMetrics(env, 8, 10, 6, 5, 256, lastMedian); checkMetrics(env, 8, 10, 6, 5, 256, lastMedian);
close(env, 6); env.close();
// Verify that the held transactions got applied // Verify that the held transactions got applied
lastMedian = 500; lastMedian = 500;
checkMetrics(env, 1, 12, 7, 6, 256, lastMedian); checkMetrics(env, 1, 12, 7, 6, 256, lastMedian);
@@ -211,40 +166,35 @@ public:
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
// Hank sends another txn // Hank sends another txn
submit(env, env(noop(hank), fee(10), queued);
env.jt(noop(hank), fee(10), queued));
// But he's not going to leave it in the queue // But he's not going to leave it in the queue
checkMetrics(env, 2, 12, 7, 6, 256, lastMedian); checkMetrics(env, 2, 12, 7, 6, 256, lastMedian);
// Hank sees his txn got held and bumps the fee, // Hank sees his txn got held and bumps the fee,
// but doesn't even bump it enough to requeue // but doesn't even bump it enough to requeue
submit(env, env(noop(hank), fee(11), ter(telINSUF_FEE_P));
env.jt(noop(hank), fee(11), ter(telINSUF_FEE_P)));
checkMetrics(env, 2, 12, 7, 6, 256, lastMedian); checkMetrics(env, 2, 12, 7, 6, 256, lastMedian);
// Hank sees his txn got held and bumps the fee, // Hank sees his txn got held and bumps the fee,
// enough to requeue, but doesn't bump it enough to // enough to requeue, but doesn't bump it enough to
// apply to the ledger // apply to the ledger
submit(env, env(noop(hank), fee(6000), queued);
env.jt(noop(hank), fee(6000), queued));
// But he's not going to leave it in the queue // But he's not going to leave it in the queue
checkMetrics(env, 2, 12, 7, 6, 256, lastMedian); checkMetrics(env, 2, 12, 7, 6, 256, lastMedian);
// Hank sees his txn got held and bumps the fee, // Hank sees his txn got held and bumps the fee,
// high enough to get into the open ledger, because // high enough to get into the open ledger, because
// he doesn't want to wait. // he doesn't want to wait.
submit(env, env(noop(hank), openLedgerFee());
env.jt(noop(hank), openLedgerFee()));
checkMetrics(env, 1, 12, 8, 6, 256, lastMedian); checkMetrics(env, 1, 12, 8, 6, 256, lastMedian);
// Hank then sends another, less important txn // Hank then sends another, less important txn
// (In addition to the metrics, this will verify that // (In addition to the metrics, this will verify that
// the original txn got removed.) // the original txn got removed.)
submit(env, env(noop(hank), fee(6000), queued);
env.jt(noop(hank), fee(6000), queued));
checkMetrics(env, 2, 12, 8, 6, 256, lastMedian); checkMetrics(env, 2, 12, 8, 6, 256, lastMedian);
close(env, 8); env.close();
// Verify that bob and hank's txns were applied // Verify that bob and hank's txns were applied
lastMedian = 500; lastMedian = 500;
@@ -253,12 +203,12 @@ public:
// Close again with a simulated time leap to // Close again with a simulated time leap to
// reset the escalation limit down to minimum // reset the escalation limit down to minimum
lastMedian = 76928; lastMedian = 76928;
close(env, 2, true); env.close(env.now() + 5s, 10000ms);
checkMetrics(env, 0, 16, 0, 3, 256, lastMedian); checkMetrics(env, 0, 16, 0, 3, 256, lastMedian);
// Then close once more without the time leap // Then close once more without the time leap
// to reset the queue maxsize down to minimum // to reset the queue maxsize down to minimum
lastMedian = 500; lastMedian = 500;
close(env, 0); env.close();
checkMetrics(env, 0, 6, 0, 3, 256, lastMedian); checkMetrics(env, 0, 6, 0, 3, 256, lastMedian);
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
@@ -266,56 +216,44 @@ public:
// At this point, the queue should have a limit of 6. // At this point, the queue should have a limit of 6.
// Stuff the ledger and queue so we can verify that // Stuff the ledger and queue so we can verify that
// stuff gets kicked out. // stuff gets kicked out.
submit(env, env(noop(hank));
env.jt(noop(hank))); env(noop(gwen));
submit(env, env(noop(fred));
env.jt(noop(gwen))); env(noop(elmo));
submit(env,
env.jt(noop(fred)));
submit(env,
env.jt(noop(elmo)));
checkMetrics(env, 0, 6, 4, 3, 256, lastMedian); checkMetrics(env, 0, 6, 4, 3, 256, lastMedian);
// Use explicit fees so we can control which txn // Use explicit fees so we can control which txn
// will get dropped // will get dropped
submit(env, env(noop(alice), fee(20), queued);
env.jt(noop(alice), fee(20), queued)); env(noop(hank), fee(19), queued);
submit(env, env(noop(gwen), fee(18), queued);
env.jt(noop(hank), fee(19), queued)); env(noop(fred), fee(17), queued);
submit(env, env(noop(elmo), fee(16), queued);
env.jt(noop(gwen), fee(18), queued));
submit(env,
env.jt(noop(fred), fee(17), queued));
submit(env,
env.jt(noop(elmo), fee(16), queued));
// This one gets into the queue, but gets dropped when the // This one gets into the queue, but gets dropped when the
// higher fee one is added later. // higher fee one is added later.
submit(env, env(noop(daria), fee(15), queued);
env.jt(noop(daria), fee(15), queued));
// Queue is full now. // Queue is full now.
checkMetrics(env, 6, 6, 4, 3, 385, lastMedian); checkMetrics(env, 6, 6, 4, 3, 385, lastMedian);
// Try to add another transaction with the default (low) fee, // Try to add another transaction with the default (low) fee,
// it should fail because the queue is full. // it should fail because the queue is full.
submit(env, env(noop(charlie), ter(telINSUF_FEE_P));
env.jt(noop(charlie), ter(telINSUF_FEE_P)));
// Add another transaction, with a higher fee, // Add another transaction, with a higher fee,
// Not high enough to get into the ledger, but high // Not high enough to get into the ledger, but high
// enough to get into the queue (and kick somebody out) // enough to get into the queue (and kick somebody out)
submit(env, env(noop(charlie), fee(100), queued);
env.jt(noop(charlie), fee(100), queued));
// Queue is still full, of course, but the min fee has gone up // Queue is still full, of course, but the min fee has gone up
checkMetrics(env, 6, 6, 4, 3, 410, lastMedian); checkMetrics(env, 6, 6, 4, 3, 410, lastMedian);
close(env, 4); env.close();
lastMedian = 500; lastMedian = 500;
checkMetrics(env, 1, 8, 5, 4, 256, lastMedian); checkMetrics(env, 1, 8, 5, 4, 256, lastMedian);
lastMedian = 500; lastMedian = 500;
close(env, 5); env.close();
checkMetrics(env, 0, 10, 1, 5, 256, lastMedian); checkMetrics(env, 0, 10, 1, 5, 256, lastMedian);
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
@@ -332,13 +270,11 @@ public:
// Stuff the ledger. // Stuff the ledger.
for (int i = 0; i <= txnsNeeded; ++i) for (int i = 0; i <= txnsNeeded; ++i)
{ {
submit(env, env(noop(env.master));
env.jt(noop(env.master)));
} }
// Queue one straightforward transaction // Queue one straightforward transaction
submit(env, env(noop(env.master), fee(20), queued);
env.jt(noop(env.master), fee(20), queued));
++metrics.txCount; ++metrics.txCount;
checkMetrics(env, metrics.txCount, checkMetrics(env, metrics.txCount,
@@ -350,8 +286,9 @@ public:
void testLastLedgerSeq() void testLastLedgerSeq()
{ {
using namespace jtx; using namespace jtx;
using namespace std::chrono;
Env env(*this, makeConfig()); Env env(*this, makeConfig(), features(featureFeeEscalation));
auto& txq = env.app().getTxQ(); auto& txq = env.app().getTxQ();
txq.setMinimumTx(2); txq.setMinimumTx(2);
@@ -367,53 +304,43 @@ public:
checkMetrics(env, 0, boost::none, 0, 2, 256, 500); checkMetrics(env, 0, boost::none, 0, 2, 256, 500);
// Fund these accounts and close the ledger without // Fund across several ledgers so the TxQ metrics stay restricted.
// involving the queue, so that stats aren't affected. env.fund(XRP(1000), noripple(alice, bob));
env.fund(XRP(1000), noripple(alice, bob, charlie, daria, edgar, felicia)); env.close(env.now() + 5s, 10000ms);
env.close(); env.fund(XRP(1000), noripple(charlie, daria));
env.close(env.now() + 5s, 10000ms);
env.fund(XRP(1000), noripple(edgar, felicia));
env.close(env.now() + 5s, 10000ms);
checkMetrics(env, 0, boost::none, 0, 2, 256, 500); checkMetrics(env, 0, boost::none, 0, 2, 256, 500);
submit(env, env(noop(bob));
env.jt(noop(bob))); env(noop(charlie));
submit(env, env(noop(daria));
env.jt(noop(charlie)));
submit(env,
env.jt(noop(daria)));
checkMetrics(env, 0, boost::none, 3, 2, 256, 500); checkMetrics(env, 0, boost::none, 3, 2, 256, 500);
// Queue an item with a LastLedgerSeq. // Queue an item with a LastLedgerSeq.
submit(env, env(noop(alice), json(R"({"LastLedgerSequence":7})"),
env.jt(noop(alice), json(R"({"LastLedgerSequence":4})"), queued);
queued));
// Queue items with higher fees to force the previous // Queue items with higher fees to force the previous
// txn to wait. // txn to wait.
submit(env, env(noop(bob), fee(20), queued);
env.jt(noop(bob), fee(20), queued)); env(noop(charlie), fee(20), queued);
submit(env, env(noop(daria), fee(20), queued);
env.jt(noop(charlie), fee(20), queued)); env(noop(edgar), fee(20), queued);
submit(env,
env.jt(noop(daria), fee(20), queued));
submit(env,
env.jt(noop(edgar), fee(20), queued));
checkMetrics(env, 5, boost::none, 3, 2, 256, 500); checkMetrics(env, 5, boost::none, 3, 2, 256, 500);
close(env, 3); env.close();
checkMetrics(env, 1, 6, 4, 3, 256, 500); checkMetrics(env, 1, 6, 4, 3, 256, 500);
// Keep alice's transaction waiting. // Keep alice's transaction waiting.
submit(env, env(noop(bob), fee(20), queued);
env.jt(noop(bob), fee(20), queued)); env(noop(charlie), fee(20), queued);
submit(env, env(noop(daria), fee(20), queued);
env.jt(noop(charlie), fee(20), queued)); env(noop(edgar), fee(20), queued);
submit(env, env(noop(felicia), fee(20), queued);
env.jt(noop(daria), fee(20), queued));
submit(env,
env.jt(noop(edgar), fee(20), queued));
submit(env,
env.jt(noop(felicia), fee(20), queued));
checkMetrics(env, 6, 6, 4, 3, 257, 500); checkMetrics(env, 6, 6, 4, 3, 257, 500);
close(env, 4); env.close();
// alice's transaction expired without getting // alice's transaction expired without getting
// into the ledger, so the queue is now empty. // into the ledger, so the queue is now empty.
checkMetrics(env, 0, 8, 5, 4, 256, 512); checkMetrics(env, 0, 8, 5, 4, 256, 512);
@@ -423,8 +350,9 @@ public:
void testZeroFeeTxn() void testZeroFeeTxn()
{ {
using namespace jtx; using namespace jtx;
using namespace std::chrono;
Env env(*this, makeConfig()); Env env(*this, makeConfig(), features(featureFeeEscalation));
auto& txq = env.app().getTxQ(); auto& txq = env.app().getTxQ();
txq.setMinimumTx(2); txq.setMinimumTx(2);
@@ -439,24 +367,22 @@ public:
// Fund these accounts and close the ledger without // Fund these accounts and close the ledger without
// involving the queue, so that stats aren't affected. // involving the queue, so that stats aren't affected.
env.fund(XRP(1000), noripple(alice, bob)); env.fund(XRP(1000), noripple(alice, bob));
env.close(); env.close(env.now() + 5s, 10000ms);
// Fill the ledger // Fill the ledger
submit(env, env.jt(noop(alice))); env(noop(alice));
submit(env, env.jt(noop(alice))); env(noop(alice));
submit(env, env.jt(noop(alice))); env(noop(alice));
checkMetrics(env, 0, boost::none, 3, 2, 256, 500); checkMetrics(env, 0, boost::none, 3, 2, 256, 500);
submit(env, env(noop(bob), queued);
env.jt(noop(bob), queued));
checkMetrics(env, 1, boost::none, 3, 2, 256, 500); checkMetrics(env, 1, boost::none, 3, 2, 256, 500);
// Even though this transaction has a 0 fee, // Even though this transaction has a 0 fee,
// SetRegularKey::calculateBaseFee indicates this is // SetRegularKey::calculateBaseFee indicates this is
// a "free" transaction, so it has an "infinite" fee // a "free" transaction, so it has an "infinite" fee
// level and goes into the open ledger. // level and goes into the open ledger.
submit(env, env(regkey(alice, bob), fee(0));
env.jt(regkey(alice, bob), fee(0)));
checkMetrics(env, 1, boost::none, 4, 2, 256, 500); checkMetrics(env, 1, boost::none, 4, 2, 256, 500);
// This transaction also has an "infinite" fee level, // This transaction also has an "infinite" fee level,
@@ -465,9 +391,8 @@ public:
// with terPRE_SEQ (notably, *not* telINSUF_FEE_P). // with terPRE_SEQ (notably, *not* telINSUF_FEE_P).
// This implicitly relies on preclaim succeeding and // This implicitly relies on preclaim succeeding and
// canBeHeld failing under the hood. // canBeHeld failing under the hood.
submit(env, env(regkey(bob, alice), fee(0),
env.jt(regkey(bob, alice), fee(0), seq(env.seq(bob) + 1), ter(terPRE_SEQ));
seq(env.seq(bob) + 1), ter(terPRE_SEQ)));
checkMetrics(env, 1, boost::none, 4, 2, 256, 500); checkMetrics(env, 1, boost::none, 4, 2, 256, 500);
} }
@@ -476,7 +401,7 @@ public:
{ {
using namespace jtx; using namespace jtx;
Env env(*this, makeConfig()); Env env(*this, makeConfig(), features(featureFeeEscalation));
auto alice = Account("alice"); auto alice = Account("alice");
auto bob = Account("bob"); auto bob = Account("bob");
@@ -488,21 +413,19 @@ public:
// expected. // expected.
// Fail in preflight // Fail in preflight
submit(env, env(pay(alice, bob, XRP(-1000)),
env.jt(pay(alice, bob, XRP(-1000)), ter(temBAD_AMOUNT));
ter(temBAD_AMOUNT)));
// Fail in preclaim // Fail in preclaim
submit(env, env(noop(alice), fee(XRP(100000)),
env.jt(noop(alice), fee(XRP(100000)), ter(terINSUF_FEE_B));
ter(terINSUF_FEE_B)));
} }
void testQueuedFailure() void testQueuedFailure()
{ {
using namespace jtx; using namespace jtx;
Env env(*this, makeConfig()); Env env(*this, makeConfig(), features(featureFeeEscalation));
auto& txq = env.app().getTxQ(); auto& txq = env.app().getTxQ();
txq.setMinimumTx(2); txq.setMinimumTx(2);
@@ -519,18 +442,36 @@ public:
checkMetrics(env, 0, boost::none, 2, 2, 256, 500); checkMetrics(env, 0, boost::none, 2, 2, 256, 500);
// Fill the ledger // Fill the ledger
submit(env, env.jt(noop(alice))); env(noop(alice));
checkMetrics(env, 0, boost::none, 3, 2, 256, 500); checkMetrics(env, 0, boost::none, 3, 2, 256, 500);
// Put a transaction in the queue // Put a transaction in the queue
submit(env, env.jt(noop(alice), queued)); env(noop(alice), queued);
checkMetrics(env, 1, boost::none, 3, 2, 256, 500); checkMetrics(env, 1, boost::none, 3, 2, 256, 500);
// Now cheat, and bypass the queue. // Now cheat, and bypass the queue.
env(noop(alice)); {
auto const& jt = env.jt(noop(alice));
expect(jt.stx);
bool didApply;
TER ter;
env.app().openLedger().modify(
[&](OpenView& view, beast::Journal j)
{
std::tie(ter, didApply) =
ripple::apply(env.app(),
view, *jt.stx, tapNONE,
env.journal);
return didApply;
}
);
env.postconditions(jt, ter, didApply);
}
checkMetrics(env, 1, boost::none, 4, 2, 256, 500); checkMetrics(env, 1, boost::none, 4, 2, 256, 500);
close(env, 4); env.close();
// Alice's queued transaction failed in TxQ::accept // Alice's queued transaction failed in TxQ::accept
// with tefPAST_SEQ // with tefPAST_SEQ
checkMetrics(env, 0, 8, 0, 4, 256, 500); checkMetrics(env, 0, 8, 0, 4, 256, 500);

View File

@@ -224,7 +224,8 @@ public:
the close time of the resulting ledger. the close time of the resulting ledger.
*/ */
void void
close (NetClock::time_point closeTime); close (NetClock::time_point closeTime,
boost::optional<std::chrono::milliseconds> consensusDelay = boost::none);
/** Close and advance the ledger. /** Close and advance the ledger.

View File

@@ -28,10 +28,10 @@
#include <ripple/test/jtx/seq.h> #include <ripple/test/jtx/seq.h>
#include <ripple/test/jtx/sig.h> #include <ripple/test/jtx/sig.h>
#include <ripple/test/jtx/utility.h> #include <ripple/test/jtx/utility.h>
#include <ripple/app/tx/apply.h>
#include <ripple/app/ledger/LedgerMaster.h> #include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/app/ledger/LedgerTiming.h> #include <ripple/app/ledger/LedgerTiming.h>
#include <ripple/app/misc/NetworkOPs.h> #include <ripple/app/misc/NetworkOPs.h>
#include <ripple/app/misc/TxQ.h>
#include <ripple/basics/contract.h> #include <ripple/basics/contract.h>
#include <ripple/basics/Slice.h> #include <ripple/basics/Slice.h>
#include <ripple/core/ConfigSections.h> #include <ripple/core/ConfigSections.h>
@@ -113,12 +113,13 @@ Env::closed()
} }
void void
Env::close(NetClock::time_point closeTime) Env::close(NetClock::time_point closeTime,
boost::optional<std::chrono::milliseconds> consensusDelay)
{ {
// Round up to next distinguishable value // Round up to next distinguishable value
closeTime += closed()->info().closeTimeResolution - 1s; closeTime += closed()->info().closeTimeResolution - 1s;
bundle_.timeKeeper->set(closeTime); bundle_.timeKeeper->set(closeTime);
app().getOPs().acceptLedger(); app().getOPs().acceptLedger(consensusDelay);
bundle_.timeKeeper->set( bundle_.timeKeeper->set(
closed()->info().closeTime); closed()->info().closeTime);
} }
@@ -260,8 +261,8 @@ Env::submit (JTx const& jt)
app().openLedger().modify( app().openLedger().modify(
[&](OpenView& view, beast::Journal j) [&](OpenView& view, beast::Journal j)
{ {
std::tie(ter_, didApply) = ripple::apply( std::tie(ter_, didApply) = app().getTxQ().apply(
app(), view, *jt.stx, applyFlags(), app(), view, jt.stx, applyFlags(),
beast::Journal{}); beast::Journal{});
return didApply; return didApply;
}); });