diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp index 34d1fa9b2..0ffd9e0fa 100644 --- a/src/cpp/ripple/NetworkOPs.cpp +++ b/src/cpp/ripple/NetworkOPs.cpp @@ -197,12 +197,12 @@ void NetworkOPs::submitTransaction (Job&, SerializedTransaction::pointer iTrans, // FIXME: Should submit to job queue theApp->getIOService ().post (boost::bind (&NetworkOPs::processTransaction, this, - boost::make_shared (trans, false), false, callback)); + boost::make_shared (trans, false), false, false, callback)); } // Sterilize transaction through serialization. // This is fully synchronous and deprecated -Transaction::pointer NetworkOPs::submitTransactionSync (Transaction::ref tpTrans, bool bAdmin, bool bSubmit) +Transaction::pointer NetworkOPs::submitTransactionSync (Transaction::ref tpTrans, bool bAdmin, bool bFailHard, bool bSubmit) { Serializer s; tpTrans->getSTransaction ()->add (s); @@ -217,7 +217,7 @@ Transaction::pointer NetworkOPs::submitTransactionSync (Transaction::ref tpTrans else if (tpTransNew->getSTransaction ()->isEquivalent (*tpTrans->getSTransaction ())) { if (bSubmit) - (void) NetworkOPs::processTransaction (tpTransNew, bAdmin); + (void) NetworkOPs::processTransaction (tpTransNew, bAdmin, bFailHard); } else { @@ -315,7 +315,7 @@ void NetworkOPs::runTransactionQueue () theApp->getIOService ().post (boost::bind (&NetworkOPs::runTransactionQueue, this)); } -Transaction::pointer NetworkOPs::processTransaction (Transaction::pointer trans, bool bAdmin, stCallback callback) +Transaction::pointer NetworkOPs::processTransaction (Transaction::pointer trans, bool bAdmin, bool bFailHard, stCallback callback) { LoadEvent::autoptr ev = theApp->getJobQueue ().getLoadEventAP (jtTXN_PROC, "ProcessTXN"); @@ -345,7 +345,6 @@ Transaction::pointer NetworkOPs::processTransaction (Transaction::pointer trans, } boost::recursive_mutex::scoped_lock sl (theApp->getMasterLock ()); - Transaction::pointer dbtx = theApp->getMasterTransaction ().fetch (trans->getID (), true); bool didApply; TER r = mLedgerMaster->doTransaction (trans->getSTransaction (), bAdmin ? (tapOPEN_LEDGER | tapNO_CHECK_SIGN | tapADMIN) : (tapOPEN_LEDGER | tapNO_CHECK_SIGN), didApply); @@ -386,11 +385,14 @@ Transaction::pointer NetworkOPs::processTransaction (Transaction::pointer trans, } else if (isTerRetry (r)) { - // transaction should be held - WriteLog (lsDEBUG, NetworkOPs) << "Transaction should be held: " << r; - trans->setStatus (HELD); - theApp->getMasterTransaction ().canonicalize (trans, true); - mLedgerMaster->addHeldTransaction (trans); + if (!bFailHard) + { + // transaction should be held + WriteLog (lsDEBUG, NetworkOPs) << "Transaction should be held: " << r; + trans->setStatus (HELD); + theApp->getMasterTransaction ().canonicalize (trans, true); + mLedgerMaster->addHeldTransaction (trans); + } } else { @@ -398,7 +400,7 @@ Transaction::pointer NetworkOPs::processTransaction (Transaction::pointer trans, trans->setStatus (INVALID); } - if (didApply || (mMode != omFULL)) + if (didApply || ((mMode != omFULL) && !bFailHard)) { std::set peers; diff --git a/src/cpp/ripple/NetworkOPs.h b/src/cpp/ripple/NetworkOPs.h index ef2532ec9..329acbb35 100644 --- a/src/cpp/ripple/NetworkOPs.h +++ b/src/cpp/ripple/NetworkOPs.h @@ -133,13 +133,13 @@ public: // typedef FUNCTION_TYPE stCallback; // must complete immediately void submitTransaction (Job&, SerializedTransaction::pointer, stCallback callback = stCallback ()); - Transaction::pointer submitTransactionSync (Transaction::ref tpTrans, bool bAdmin, bool bSubmit); + Transaction::pointer submitTransactionSync (Transaction::ref tpTrans, bool bAdmin, bool bFailHard, bool bSubmit); void runTransactionQueue (); - Transaction::pointer processTransaction (Transaction::pointer, bool bAdmin, stCallback); - Transaction::pointer processTransaction (Transaction::pointer transaction, bool bAdmin) + Transaction::pointer processTransaction (Transaction::pointer, bool bAdmin, bool bFailHard, stCallback); + Transaction::pointer processTransaction (Transaction::pointer transaction, bool bAdmin, bool bFailHard) { - return processTransaction (transaction, bAdmin, stCallback ()); + return processTransaction (transaction, bAdmin, bFailHard, stCallback ()); } Transaction::pointer findTransactionByID (uint256 const& transactionID); diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 715a1ab50..f2a0a5a32 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -62,7 +62,7 @@ RPCHandler::RPCHandler (NetworkOPs* netOps, InfoSub::pointer infoSub) : mNetOps ; } -Json::Value RPCHandler::transactionSign (Json::Value jvRequest, bool bSubmit, ScopedLock& mlh) +Json::Value RPCHandler::transactionSign (Json::Value jvRequest, bool bSubmit, bool bFailHard, ScopedLock& mlh) { mlh.unlock (); @@ -343,7 +343,7 @@ Json::Value RPCHandler::transactionSign (Json::Value jvRequest, bool bSubmit, Sc try { // FIXME: For performance, should use asynch interface - tpTrans = mNetOps->submitTransactionSync (tpTrans, mRole == ADMIN, bSubmit); + tpTrans = mNetOps->submitTransactionSync (tpTrans, mRole == ADMIN, bFailHard, bSubmit); if (!tpTrans) { @@ -1653,7 +1653,8 @@ Json::Value RPCHandler::doRipplePathFind (Json::Value jvRequest, int& cost, Scop Json::Value RPCHandler::doSign (Json::Value jvRequest, int& cost, ScopedLock& MasterLockHolder) { cost = rpcCOST_EXPENSIVE; - return transactionSign (jvRequest, false, MasterLockHolder); + bool bFailHard = jvRequest.isMember ("fail_hard") && jvRequest["fail_hard"].asBool (); + return transactionSign (jvRequest, false, bFailHard, MasterLockHolder); } // { @@ -1664,7 +1665,8 @@ Json::Value RPCHandler::doSubmit (Json::Value jvRequest, int& cost, ScopedLock& { if (!jvRequest.isMember ("tx_blob")) { - return transactionSign (jvRequest, true, MasterLockHolder); + bool bFailHard = jvRequest.isMember ("fail_hard") && jvRequest["fail_hard"].asBool (); + return transactionSign (jvRequest, true, bFailHard, MasterLockHolder); } Json::Value jvResult; @@ -1711,7 +1713,8 @@ Json::Value RPCHandler::doSubmit (Json::Value jvRequest, int& cost, ScopedLock& try { - (void) mNetOps->processTransaction (tpTrans, mRole == ADMIN); + (void) mNetOps->processTransaction (tpTrans, mRole == ADMIN, + jvRequest.isMember ("fail_hard") && jvRequest["fail_hard"].asBool ()); } catch (std::exception& e) { diff --git a/src/cpp/ripple/RPCHandler.h b/src/cpp/ripple/RPCHandler.h index 6d53204dd..8979b0d2f 100644 --- a/src/cpp/ripple/RPCHandler.h +++ b/src/cpp/ripple/RPCHandler.h @@ -37,7 +37,7 @@ class RPCHandler // Utilities void addSubmitPath (Json::Value& txJSON); boost::unordered_set parseAccountIds (const Json::Value& jvArray); - Json::Value transactionSign (Json::Value jvRequest, bool bSubmit, ScopedLock& mlh); + Json::Value transactionSign (Json::Value jvRequest, bool bSubmit, bool bFailHard, ScopedLock& mlh); Json::Value lookupLedger (Json::Value jvRequest, Ledger::pointer& lpLedger); diff --git a/src/cpp/ripple/ripple_Peer.cpp b/src/cpp/ripple/ripple_Peer.cpp index f4fdde050..00c0385d4 100644 --- a/src/cpp/ripple/ripple_Peer.cpp +++ b/src/cpp/ripple/ripple_Peer.cpp @@ -1081,7 +1081,7 @@ static void checkTransaction (Job&, int flags, SerializedTransaction::pointer st else theApp->getHashRouter ().setFlag (stx->getTransactionID (), SF_SIGGOOD); - theApp->getOPs ().processTransaction (tx, isSetBit (flags, SF_TRUSTED)); + theApp->getOPs ().processTransaction (tx, isSetBit (flags, SF_TRUSTED), false); #ifndef TRUST_NETWORK }