diff --git a/src/ripple/app/consensus/RCLConsensus.cpp b/src/ripple/app/consensus/RCLConsensus.cpp index 0208592e0..94bff26ab 100644 --- a/src/ripple/app/consensus/RCLConsensus.cpp +++ b/src/ripple/app/consensus/RCLConsensus.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -441,9 +441,7 @@ RCLConsensus::Adaptor::doAccept( if (validating_) validating_ = ledgerMaster_.isCompatible( - *sharedLCL.ledger_, - app_.journal("LedgerConsensus").warn(), - "Not validating"); + *sharedLCL.ledger_, j_.warn(), "Not validating"); if (validating_ && !consensusFail && app_.getValidations().canValidateSeq(sharedLCL.seq())) @@ -631,103 +629,6 @@ RCLConsensus::Adaptor::notify( JLOG (j_.trace()) << "send status change to peer"; } -/** Apply a set of transactions to a ledger. - - Typically the txFilter is used to reject transactions - that already accepted in the prior ledger. - - @param txns set of transactions to apply - @param view ledger to apply to - @param txFilter callback, return false to reject txn - @return retriable transactions -*/ - -CanonicalTXSet -applyTransactions( - Application& app, - RCLTxSet const& txns, - OpenView& view, - std::function txFilter) -{ - auto j = app.journal("LedgerConsensus"); - - auto& set = *(txns.map_); - CanonicalTXSet retriableTxs(set.getHash().as_uint256()); - - for (auto const& item : set) - { - if (!txFilter(item.key())) - continue; - - // The transaction wan't filtered - // Add it to the set to be tried in canonical order - JLOG(j.debug()) << "Processing candidate transaction: " << item.key(); - try - { - retriableTxs.insert( - std::make_shared(SerialIter{item.slice()})); - } - catch (std::exception const&) - { - JLOG(j.warn()) << "Txn " << item.key() << " throws"; - } - } - - bool certainRetry = true; - // Attempt to apply all of the retriable transactions - for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass) - { - JLOG(j.debug()) << "Pass: " << pass << " Txns: " << retriableTxs.size() - << (certainRetry ? " retriable" : " final"); - int changes = 0; - - auto it = retriableTxs.begin(); - - while (it != retriableTxs.end()) - { - try - { - switch (applyTransaction( - app, view, *it->second, certainRetry, tapNO_CHECK_SIGN, j)) - { - case ApplyResult::Success: - it = retriableTxs.erase(it); - ++changes; - break; - - case ApplyResult::Fail: - it = retriableTxs.erase(it); - break; - - case ApplyResult::Retry: - ++it; - } - } - catch (std::exception const&) - { - JLOG(j.warn()) << "Transaction throws"; - it = retriableTxs.erase(it); - } - } - - JLOG(j.debug()) << "Pass: " << pass << " finished " << changes - << " changes"; - - // A non-retry pass made no changes - if (!changes && !certainRetry) - return retriableTxs; - - // Stop retriable passes - if (!changes || (pass >= LEDGER_RETRY_PASSES)) - certainRetry = false; - } - - // If there are any transactions left, we must have - // tried them in at least one final pass - assert(retriableTxs.empty() || !certainRetry); - return retriableTxs; -} - RCLCxLedger RCLConsensus::Adaptor::buildLCL( RCLCxLedger const& previousLedger, @@ -738,81 +639,26 @@ RCLConsensus::Adaptor::buildLCL( std::chrono::milliseconds roundTime, CanonicalTXSet& retriableTxs) { - auto replay = ledgerMaster_.releaseReplay(); - if (replay) - { - // replaying, use the time the ledger we're replaying closed - closeTime = replay->closeTime_; - closeTimeCorrect = ((replay->closeFlags_ & sLCF_NoConsensusTime) == 0); - } - - JLOG(j_.debug()) << "Report: TxSt = " << txns.id() << ", close " - << closeTime.time_since_epoch().count() - << (closeTimeCorrect ? "" : " (incorrect)"); - - // Build the new last closed ledger - auto buildLCL = - std::make_shared(*previousLedger.ledger_, closeTime); - - auto const v2_enabled = buildLCL->rules().enabled(featureSHAMapV2); - - auto v2_transition = false; - if (v2_enabled && !buildLCL->stateMap().is_v2()) - { - buildLCL->make_v2(); - v2_transition = true; - } - - // Set up to write SHAMap changes to our database, - // perform updates, extract changes - JLOG(j_.debug()) << "Applying consensus txns transactions to the" - << " last closed ledger"; - - { - OpenView accum(&*buildLCL); - assert(!accum.open()); - if (replay) + std::shared_ptr buildLCL = [&]() { + auto const replayData = ledgerMaster_.releaseReplay(); + if (replayData) { - // Special case, we are replaying a ledger close - for (auto& tx : replay->txns_) - applyTransaction( - app_, accum, *tx.second, false, tapNO_CHECK_SIGN, j_); + assert(replayData->parent()->info().hash == previousLedger.id()); + return buildLedger(*replayData, tapNO_CHECK_SIGN, app_, j_); } - else - { - // Normal case, we are not replaying a ledger close - retriableTxs = applyTransactions( - app_, txns, accum, [&buildLCL](uint256 const& txID) { - return !buildLCL->txExists(txID); - }); - } - // Update fee computations. - app_.getTxQ().processClosedLedger(app_, accum, roundTime > 5s); - accum.apply(*buildLCL); - } + return buildLedger( + previousLedger.ledger_, + closeTime, + closeTimeCorrect, + closeResolution, + *txns.map_, + app_, + retriableTxs, + j_); + }(); - // retriableTxs will include any transactions that - // made it into the consensus set but failed during application - // to the ledger. - - buildLCL->updateSkipList(); - - { - // Write the final version of all modified SHAMap - // nodes to the node store to preserve the new LCL - - int asf = buildLCL->stateMap().flushDirty( - hotACCOUNT_NODE, buildLCL->info().seq); - int tmf = buildLCL->txMap().flushDirty( - hotTRANSACTION_NODE, buildLCL->info().seq); - JLOG(j_.debug()) << "Flushed " << asf << " accounts and " << tmf - << " transaction nodes"; - } - buildLCL->unshare(); - - // Accept ledger - buildLCL->setAccepted( - closeTime, closeResolution, closeTimeCorrect, app_.config()); + // Update fee computations based on accepted txs + app_.getTxQ().processClosedLedger(app_, *buildLCL, roundTime > 5s); // And stash the ledger in the ledger master if (ledgerMaster_.storeLedger(buildLCL)) diff --git a/src/ripple/app/consensus/RCLConsensus.h b/src/ripple/app/consensus/RCLConsensus.h index 9903b69d5..6d7e32290 100644 --- a/src/ripple/app/consensus/RCLConsensus.h +++ b/src/ripple/app/consensus/RCLConsensus.h @@ -332,7 +332,7 @@ class RCLConsensus @param previousLedger Prior ledger building upon @param txns The set of transactions to apply to the ledger - @param closeTime The the ledger closed + @param closeTime The time the ledger closed @param closeTimeCorrect Whether consensus agreed on close time @param closeResolution Resolution used to determine consensus close time diff --git a/src/ripple/app/ledger/BuildLedger.h b/src/ripple/app/ledger/BuildLedger.h new file mode 100644 index 000000000..c496483c3 --- /dev/null +++ b/src/ripple/app/ledger/BuildLedger.h @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2018 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_APP_LEDGER_BUILD_LEDGER_H_INCLUDED +#define RIPPLE_APP_LEDGER_BUILD_LEDGER_H_INCLUDED + +#include +#include +#include +#include +#include + +namespace ripple { + +class Application; +class CanonicalTXSet; +class Ledger; +class LedgerReplay; +class SHAMap; + + +/** Build a new ledger by applying consensus transactions + + Build a new ledger by applying a set of transactions accepted as part of + consensus. + + @param parent The ledger to apply transactions to + @param closeTime The time the ledger closed + @param closeTimeCorrect Whether consensus agreed on close time + @param closeResolution Resolution used to determine consensus close time + @param txs The consensus transactions to attempt to apply + @param app Handle to application instance + @param retriableTxs Populate with transactions to retry in next round + @param j Journal to use for logging + @return The newly built ledger + */ +std::shared_ptr +buildLedger( + std::shared_ptr const& parent, + NetClock::time_point closeTime, + const bool closeTimeCorrect, + NetClock::duration closeResolution, + SHAMap const& txs, + Application& app, + CanonicalTXSet& retriableTxs, + beast::Journal j); + +/** Build a new ledger by replaying transactions + + Build a new ledger by replaying transactions accepted into a prior ledger. + + @param replayData Data of the ledger to replay + @param applyFlags Flags to use when applying transactions + @param app Handle to application instance + @param j Journal to use for logging + @return The newly built ledger + */ +std::shared_ptr +buildLedger( + LedgerReplay const& replayData, + ApplyFlags applyFlags, + Application& app, + beast::Journal j); + +} // namespace ripple +#endif diff --git a/src/ripple/app/ledger/LedgerMaster.h b/src/ripple/app/ledger/LedgerMaster.h index 55ab6c918..2aaa0c15d 100644 --- a/src/ripple/app/ledger/LedgerMaster.h +++ b/src/ripple/app/ledger/LedgerMaster.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -47,13 +48,7 @@ namespace ripple { class Peer; class Transaction; -struct LedgerReplay -{ - std::map< int, std::shared_ptr > txns_; - NetClock::time_point closeTime_; - int closeFlags_; - std::shared_ptr prevLedger_; -}; + // Tracks the current ledger and any ledgers in the process of closing // Tracks ledger history diff --git a/src/ripple/app/ledger/LedgerReplay.h b/src/ripple/app/ledger/LedgerReplay.h new file mode 100644 index 000000000..4491aca9e --- /dev/null +++ b/src/ripple/app/ledger/LedgerReplay.h @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2018 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_APP_LEDGER_LEDGERREPLAY_H_INCLUDED +#define RIPPLE_APP_LEDGER_LEDGERREPLAY_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +class Ledger; +class STTx; + +class LedgerReplay +{ + std::shared_ptr parent_; + std::shared_ptr replay_; + std::map> orderedTxns_; + +public: + LedgerReplay( + std::shared_ptr parent, + std::shared_ptr replay); + + /** @return The parent of the ledger to replay + */ + std::shared_ptr const& + parent() const + { + return parent_; + } + + /** @return The ledger to replay + */ + std::shared_ptr const& + replay() const + { + return replay_; + } + + /** @return Transactions in the order they should be replayed + */ + std::map> const& + orderedTxns() const + { + return orderedTxns_; + } +}; + +} // namespace ripple + +#endif diff --git a/src/ripple/app/ledger/impl/BuildLedger.cpp b/src/ripple/app/ledger/impl/BuildLedger.cpp new file mode 100644 index 000000000..55754483f --- /dev/null +++ b/src/ripple/app/ledger/impl/BuildLedger.cpp @@ -0,0 +1,235 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2018 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +/* Generic buildLedgerImpl that dispatches to ApplyTxs invocable with signature + void(OpenView&, std::shared_ptr const&) + It is responsible for adding transactions to the open view to generate the + new ledger. It is generic since the mechanics differ for consensus + generated ledgers versus replayed ledgers. +*/ +template +std::shared_ptr +buildLedgerImpl( + std::shared_ptr const& parent, + NetClock::time_point closeTime, + const bool closeTimeCorrect, + NetClock::duration closeResolution, + Application& app, + beast::Journal j, + ApplyTxs&& applyTxs) +{ + auto buildLCL = std::make_shared(*parent, closeTime); + + if (buildLCL->rules().enabled(featureSHAMapV2) && + !buildLCL->stateMap().is_v2()) + { + buildLCL->make_v2(); + } + + // Set up to write SHAMap changes to our database, + // perform updates, extract changes + + { + OpenView accum(&*buildLCL); + assert(!accum.open()); + applyTxs(accum, buildLCL); + accum.apply(*buildLCL); + } + + buildLCL->updateSkipList(); + + { + // Write the final version of all modified SHAMap + // nodes to the node store to preserve the new LCL + + int const asf = buildLCL->stateMap().flushDirty( + hotACCOUNT_NODE, buildLCL->info().seq); + int const tmf = buildLCL->txMap().flushDirty( + hotTRANSACTION_NODE, buildLCL->info().seq); + JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf + << " transaction nodes"; + } + buildLCL->unshare(); + + // Accept ledger + buildLCL->setAccepted( + closeTime, closeResolution, closeTimeCorrect, app.config()); + + return buildLCL; +} + +/** Apply a set of consensus transactions to a ledger. + + @param app Handle to application + @param txns Consensus transactions to apply + @param view Ledger to apply to + @param buildLCL Ledger to check if transaction already exists + @param j Journal for logging + @return Any retriable transactions +*/ + +CanonicalTXSet +applyTransactions( + Application& app, + SHAMap const& txns, + OpenView& view, + std::shared_ptr const& buildLCL, + beast::Journal j) +{ + CanonicalTXSet retriableTxs(txns.getHash().as_uint256()); + + for (auto const& item : txns) + { + if (buildLCL->txExists(item.key())) + continue; + + // The transaction wasn't filtered + // Add it to the set to be tried in canonical order + JLOG(j.debug()) << "Processing candidate transaction: " << item.key(); + try + { + retriableTxs.insert( + std::make_shared(SerialIter{item.slice()})); + } + catch (std::exception const&) + { + JLOG(j.warn()) << "Txn " << item.key() << " throws"; + } + } + + bool certainRetry = true; + // Attempt to apply all of the retriable transactions + for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass) + { + JLOG(j.debug()) << "Pass: " << pass << " Txns: " << retriableTxs.size() + << (certainRetry ? " retriable" : " final"); + int changes = 0; + + auto it = retriableTxs.begin(); + + while (it != retriableTxs.end()) + { + try + { + switch (applyTransaction( + app, view, *it->second, certainRetry, tapNO_CHECK_SIGN, j)) + { + case ApplyResult::Success: + it = retriableTxs.erase(it); + ++changes; + break; + + case ApplyResult::Fail: + it = retriableTxs.erase(it); + break; + + case ApplyResult::Retry: + ++it; + } + } + catch (std::exception const&) + { + JLOG(j.warn()) << "Transaction throws"; + it = retriableTxs.erase(it); + } + } + + JLOG(j.debug()) << "Pass: " << pass << " finished " << changes + << " changes"; + + // A non-retry pass made no changes + if (!changes && !certainRetry) + return retriableTxs; + + // Stop retriable passes + if (!changes || (pass >= LEDGER_RETRY_PASSES)) + certainRetry = false; + } + + // If there are any transactions left, we must have + // tried them in at least one final pass + assert(retriableTxs.empty() || !certainRetry); + return retriableTxs; +} + +// Build a ledger from consensus transactions +std::shared_ptr +buildLedger( + std::shared_ptr const& parent, + NetClock::time_point closeTime, + const bool closeTimeCorrect, + NetClock::duration closeResolution, + SHAMap const& txs, + Application& app, + CanonicalTXSet& retriableTxs, + beast::Journal j) +{ + JLOG(j.debug()) << "Report: TxSt = " << txs.getHash().as_uint256() + << ", close " << closeTime.time_since_epoch().count() + << (closeTimeCorrect ? "" : " (incorrect)"); + + return buildLedgerImpl( + parent, + closeTime, + closeTimeCorrect, + closeResolution, + app, + j, + [&](OpenView& accum, std::shared_ptr const& buildLCL) { + retriableTxs = applyTransactions(app, txs, accum, buildLCL, j); + }); +} + +// Build a ledger by replaying +std::shared_ptr +buildLedger( + LedgerReplay const& replayData, + ApplyFlags applyFlags, + Application& app, + beast::Journal j) +{ + auto const& replayLedger = replayData.replay(); + + JLOG(j.debug()) << "Report: Replay Ledger " << replayLedger->info().hash; + + return buildLedgerImpl( + replayData.parent(), + replayLedger->info().closeTime, + ((replayLedger->info().closeFlags & sLCF_NoConsensusTime) == 0), + replayLedger->info().closeTimeResolution, + app, + j, + [&](OpenView& accum, std::shared_ptr const& buildLCL) { + for (auto& tx : replayData.orderedTxns()) + applyTransaction(app, accum, *tx.second, false, applyFlags, j); + }); +} + +} // namespace ripple diff --git a/src/ripple/app/ledger/impl/LedgerReplay.cpp b/src/ripple/app/ledger/impl/LedgerReplay.cpp new file mode 100644 index 000000000..d9dfd1d7f --- /dev/null +++ b/src/ripple/app/ledger/impl/LedgerReplay.cpp @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2018 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include + +namespace ripple { + +LedgerReplay::LedgerReplay( + std::shared_ptr parent, + std::shared_ptr replay) + : parent_{std::move(parent)}, replay_{std::move(replay)} +{ + for (auto const& item : replay_->txMap()) + { + auto const txPair = replay_->txRead(item.key()); + auto const txIndex = (*txPair.second)[sfTransactionIndex]; + orderedTxns_.emplace(txIndex, std::move(txPair.first)); + } +} + +} // namespace ripple diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 960e8a8c8..b92a5bb7e 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -1793,27 +1793,20 @@ bool ApplicationImp::loadOldLedger ( { // inject transaction(s) from the replayLedger into our open ledger // and build replay structure - auto const& txns = replayLedger->txMap(); - auto replayData = std::make_unique (); + auto replayData = + std::make_unique(loadLedger, replayLedger); - replayData->prevLedger_ = replayLedger; - replayData->closeTime_ = replayLedger->info().closeTime; - replayData->closeFlags_ = replayLedger->info().closeFlags; - - for (auto const& item : txns) + for (auto const& it : replayData->orderedTxns()) { - auto txID = item.key(); - auto txPair = replayLedger->txRead (txID); - auto txIndex = (*txPair.second)[sfTransactionIndex]; + std::shared_ptr const& tx = it.second; + auto txID = tx->getTransactionID(); auto s = std::make_shared (); - txPair.first->add(*s); + tx->add(*s); forceValidity(getHashRouter(), txID, Validity::SigGoodOnly); - replayData->txns_.emplace (txIndex, txPair.first); - openLedger_->modify( [&txID, &s](OpenView& view, beast::Journal j) { diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp index 51e558015..ff89548e7 100644 --- a/src/ripple/app/misc/NetworkOPs.cpp +++ b/src/ripple/app/misc/NetworkOPs.cpp @@ -1365,8 +1365,7 @@ void NetworkOPsImp::switchLastClosedLedger ( clearNeedNetworkLedger (); // Update fee computations. - // TODO: Needs an open ledger - //app_.getTxQ().processClosedLedger(app_, *newLCL, true); + app_.getTxQ().processClosedLedger(app_, *newLCL, true); // Caller must own master lock { diff --git a/src/ripple/app/misc/TxQ.h b/src/ripple/app/misc/TxQ.h index 6b7770bd1..95e3b6a9b 100644 --- a/src/ripple/app/misc/TxQ.h +++ b/src/ripple/app/misc/TxQ.h @@ -150,7 +150,7 @@ public: */ void processClosedLedger(Application& app, - OpenView const& view, bool timeLeap); + ReadView const& view, bool timeLeap); /** Returns fee metrics in reference fee level units. diff --git a/src/ripple/app/misc/impl/TxQ.cpp b/src/ripple/app/misc/impl/TxQ.cpp index 224103bc2..a911b8599 100644 --- a/src/ripple/app/misc/impl/TxQ.cpp +++ b/src/ripple/app/misc/impl/TxQ.cpp @@ -1146,7 +1146,7 @@ TxQ::apply(Application& app, OpenView& view, */ void TxQ::processClosedLedger(Application& app, - OpenView const& view, bool timeLeap) + ReadView const& view, bool timeLeap) { auto const allowEscalation = (view.rules().enabled(featureFeeEscalation)); diff --git a/src/ripple/unity/app_ledger_impl.cpp b/src/ripple/unity/app_ledger_impl.cpp index d395451fa..e1256c0fd 100644 --- a/src/ripple/unity/app_ledger_impl.cpp +++ b/src/ripple/unity/app_ledger_impl.cpp @@ -18,11 +18,13 @@ //============================================================================== +#include #include #include #include #include #include +#include #include #include #include diff --git a/src/test/app/LedgerReplay_test.cpp b/src/test/app/LedgerReplay_test.cpp new file mode 100644 index 000000000..9bdac08b4 --- /dev/null +++ b/src/test/app/LedgerReplay_test.cpp @@ -0,0 +1,62 @@ + //------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2018 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include + +namespace ripple { +namespace test { + +struct LedgerReplay_test : public beast::unit_test::suite +{ + void run() override + { + testcase("Replay ledger"); + + using namespace jtx; + + // Build a ledger normally + auto const alice = Account("alice"); + auto const bob = Account("bob"); + + Env env(*this); + env.fund(XRP(100000), alice, bob); + env.close(); + + LedgerMaster& ledgerMaster = env.app().getLedgerMaster(); + auto const lastClosed = ledgerMaster.getClosedLedger(); + auto const lastClosedParent = + ledgerMaster.getLedgerByHash(lastClosed->info().parentHash); + + auto const replayed = buildLedger( + LedgerReplay(lastClosedParent,lastClosed), + tapNO_CHECK_SIGN, + env.app(), + env.journal); + + BEAST_EXPECT(replayed->info().hash == lastClosed->info().hash); + } +}; + +BEAST_DEFINE_TESTSUITE(LedgerReplay,app,ripple); + +} // test +} // ripple diff --git a/src/test/unity/app_test_unity1.cpp b/src/test/unity/app_test_unity1.cpp index 342cfa05e..9739a5a87 100644 --- a/src/test/unity/app_test_unity1.cpp +++ b/src/test/unity/app_test_unity1.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include