diff --git a/modules/ripple_app/data/ripple_DatabaseCon.cpp b/modules/ripple_app/data/ripple_DatabaseCon.cpp index 44535fa74a..844be511f0 100644 --- a/modules/ripple_app/data/ripple_DatabaseCon.cpp +++ b/modules/ripple_app/data/ripple_DatabaseCon.cpp @@ -14,7 +14,8 @@ DatabaseCon::DatabaseCon (const std::string& strName, const char* initStrings[], // responsibility to pass in the path. Add a member function to Application // or Config to compute this path. // - boost::filesystem::path pPath = (theConfig.RUN_STANDALONE && (theConfig.START_UP != Config::LOAD)) + boost::filesystem::path pPath = (theConfig.RUN_STANDALONE && + ((theConfig.START_UP != Config::LOAD) && (theConfig.START_UP != Config::REPLAY))) ? "" // Use temporary files. : (theConfig.DATA_DIR / strName); // Use regular db files. diff --git a/modules/ripple_core/functional/ripple_Config.h b/modules/ripple_core/functional/ripple_Config.h index 47b2f7d0df..47ecf9a5b9 100644 --- a/modules/ripple_core/functional/ripple_Config.h +++ b/modules/ripple_core/functional/ripple_Config.h @@ -101,6 +101,7 @@ public: FRESH, NORMAL, LOAD, + REPLAY, NETWORK }; StartUpType START_UP; diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 6149e80c74..3329e05cab 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -1132,6 +1132,10 @@ Json::Value RPCHandler::doAccountLines (Json::Value params, LoadType* loadType, jPeer["limit_peer"] = saLimitPeer.getText (); jPeer["quality_in"] = static_cast (line->getQualityIn ()); jPeer["quality_out"] = static_cast (line->getQualityOut ()); + if (line->getAuth()) + jPeer["authorized"] = true; + if (line->getAuthPeer()) + jPeer["peer_authorized"] = true; } } @@ -3681,7 +3685,7 @@ Json::Value RPCHandler::doCommand (const Json::Value& params, int iRole, LoadTyp return rpcError (rpcNO_NETWORK); } - if ((commandsA[i].iOptions & optCurrent) && (getApp().getLedgerMaster().getValidatedLedgerAge() > 120)) + if (!theConfig.RUN_STANDALONE && (commandsA[i].iOptions & optCurrent) && (getApp().getLedgerMaster().getValidatedLedgerAge() > 120)) { return rpcError (rpcNO_CURRENT); } diff --git a/src/cpp/ripple/ripple_Application.cpp b/src/cpp/ripple/ripple_Application.cpp index 5fbaadf846..0b147fc6ff 100644 --- a/src/cpp/ripple/ripple_Application.cpp +++ b/src/cpp/ripple/ripple_Application.cpp @@ -281,7 +281,7 @@ public: private: void updateTables (); void startNewLedger (); - bool loadOldLedger (const std::string&); + bool loadOldLedger (const std::string&, bool); private: boost::asio::io_service mIOService; @@ -478,11 +478,11 @@ void ApplicationImp::setup () startNewLedger (); } - else if (theConfig.START_UP == Config::LOAD) + else if ((theConfig.START_UP == Config::LOAD) || (theConfig.START_UP == Config::REPLAY)) { WriteLog (lsINFO, Application) << "Loading specified Ledger"; - if (!loadOldLedger (theConfig.START_LEDGER)) + if (!loadOldLedger (theConfig.START_LEDGER, theConfig.START_UP == Config::REPLAY)) { getApp().stop (); exit (-1); @@ -733,11 +733,11 @@ void ApplicationImp::startNewLedger () } } -bool ApplicationImp::loadOldLedger (const std::string& l) +bool ApplicationImp::loadOldLedger (const std::string& l, bool bReplay) { try { - Ledger::pointer loadLedger; + Ledger::pointer loadLedger, replayLedger; if (l.empty () || (l == "latest")) loadLedger = Ledger::getLastFullLedger (); @@ -757,6 +757,18 @@ bool ApplicationImp::loadOldLedger (const std::string& l) return false; } + if (bReplay) + { // Replay a ledger close with same prior ledger and transactions + replayLedger = loadLedger; // this ledger holds the transactions we want to replay + loadLedger = Ledger::loadByIndex (replayLedger->getLedgerSeq() - 1); // this is the prior ledger + if (!loadLedger || (replayLedger->getParentHash() != loadLedger->getHash())) + { + WriteLog (lsFATAL, Application) << "Replay ledger missing/damaged"; + assert (false); + return false; + } + } + loadLedger->setClosed (); WriteLog (lsINFO, Application) << "Loading ledger " << loadLedger->getHash () << " seq:" << loadLedger->getLedgerSeq (); @@ -785,6 +797,24 @@ bool ApplicationImp::loadOldLedger (const std::string& l) Ledger::pointer openLedger = boost::make_shared (false, boost::ref (*loadLedger)); mLedgerMaster.switchLedgers (loadLedger, openLedger); mNetOps.setLastCloseTime (loadLedger->getCloseTimeNC ()); + + if (bReplay) + { // inject transaction from replayLedger into consensus set + SHAMap::ref txns = replayLedger->peekTransactionMap(); + Ledger::ref cur = getLedgerMaster().getCurrentLedger(); + + for (SHAMapItem::pointer it = txns->peekFirstItem(); it != nullptr; it = txns->peekNextItem(it->getTag())) + { + Transaction::pointer txn = replayLedger->getTransaction(it->getTag()); + WriteLog (lsINFO, Application) << txn->getJson(0); + Serializer s; + txn->getSTransaction()->add(s); + if (!cur->addTransaction(it->getTag(), s)) + { + WriteLog (lsWARNING, Application) << "Unable to add transaction " << it->getTag(); + } + } + } } catch (SHAMapMissingNode&) { diff --git a/src/cpp/ripple/ripple_Main.cpp b/src/cpp/ripple/ripple_Main.cpp index 65f9d79ece..606453a4fd 100644 --- a/src/cpp/ripple/ripple_Main.cpp +++ b/src/cpp/ripple/ripple_Main.cpp @@ -237,6 +237,7 @@ int rippleMain (int argc, char** argv) ("quiet,q", "Reduce diagnotics.") ("verbose,v", "Verbose logging.") ("load", "Load the current ledger from the local DB.") + ("replay","Replay a ledger close.") ("ledger", po::value (), "Load the specified ledger and start from .") ("start", "Start from a fresh Ledger.") ("net", "Get the initial ledger from the network.") @@ -356,7 +357,10 @@ int rippleMain (int argc, char** argv) if (vm.count ("ledger")) { theConfig.START_LEDGER = vm["ledger"].as (); - theConfig.START_UP = Config::LOAD; + if (vm.count("replay")) + theConfig.START_UP = Config::REPLAY; + else + theConfig.START_UP = Config::LOAD; } else if (vm.count ("load")) {