diff --git a/src/ripple/app/misc/TxQ.h b/src/ripple/app/misc/TxQ.h index ae35dd1f6..5a43ac81b 100644 --- a/src/ripple/app/misc/TxQ.h +++ b/src/ripple/app/misc/TxQ.h @@ -30,6 +30,7 @@ #include #include #include +#include namespace ripple { @@ -56,7 +57,14 @@ class Config; */ class TxQ { +private: + std::mutex debugTxInjectMutex; + std::vector debugTxInjectQueue; + public: + void + debugTxInject(STTx const& txn); + /// Fee level for single-signed reference transaction. static constexpr FeeLevel64 baseLevel{256}; diff --git a/src/ripple/app/misc/impl/TxQ.cpp b/src/ripple/app/misc/impl/TxQ.cpp index 08157c292..379eb1ee1 100644 --- a/src/ripple/app/misc/impl/TxQ.cpp +++ b/src/ripple/app/misc/impl/TxQ.cpp @@ -93,6 +93,13 @@ increase(FeeLevel64 level, std::uint32_t increasePercent) ////////////////////////////////////////////////////////////////////////// +void +TxQ::debugTxInject(STTx const& txn) +{ + const std::lock_guard _(debugTxInjectMutex); + debugTxInjectQueue.push_back(txn); +} + std::size_t TxQ::FeeMetrics::update( Application& app, @@ -1444,6 +1451,32 @@ TxQ::accept(Application& app, OpenView& view) auto const metricsSnapshot = feeMetrics_.getSnapshot(); + // try to inject any debug txns waiting in the debug queue + { + std::unique_lock trylock( + TxQ::debugTxInjectMutex, std::try_to_lock); + if (trylock.owns_lock() && !debugTxInjectQueue.empty()) + { + // pop everything + for (STTx const& txn : debugTxInjectQueue) + { + auto txnHash = txn.getTransactionID(); + app.getHashRouter().setFlags(txnHash, SF_EMITTED | SF_PRIVATE2); + + auto const& emitted = + const_cast(txn).downcast(); + + auto s = std::make_shared(); + emitted.add(*s); + + view.rawTxInsert(txnHash, std::move(s), nullptr); + ledgerChanged = true; + } + + debugTxInjectQueue.clear(); + } + } + // Inject emitted transactions if any if (view.rules().enabled(featureHooks)) do diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index 699928f7e..2847af8ad 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -353,11 +353,12 @@ JSS(ident); // in: AccountCurrencies, AccountInfo, // OwnerInfo JSS(ignore_default); // in: AccountLines JSS(inLedger); // out: tx/Transaction -JSS(inbound); // out: PeerImp -JSS(index); // in: LedgerEntry, DownloadShard - // out: STLedgerEntry, - // LedgerEntry, TxHistory, LedgerData -JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo +JSS(in_queue); +JSS(inbound); // out: PeerImp +JSS(index); // in: LedgerEntry, DownloadShard + // out: STLedgerEntry, + // LedgerEntry, TxHistory, LedgerData +JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo JSS(initial_sync_duration_us); JSS(internal_command); // in: Internal JSS(invalid_API_version); // out: Many, when a request has an invalid diff --git a/src/ripple/rpc/handlers/Handlers.h b/src/ripple/rpc/handlers/Handlers.h index bb7c6d581..739c069f3 100644 --- a/src/ripple/rpc/handlers/Handlers.h +++ b/src/ripple/rpc/handlers/Handlers.h @@ -141,6 +141,8 @@ doCrawlShards(RPC::JsonContext&); Json::Value doStop(RPC::JsonContext&); Json::Value +doInject(RPC::JsonContext&); +Json::Value doSubmit(RPC::JsonContext&); Json::Value doSubmitMultiSigned(RPC::JsonContext&); diff --git a/src/ripple/rpc/handlers/Submit.cpp b/src/ripple/rpc/handlers/Submit.cpp index 2b5c8bba9..42897bf71 100644 --- a/src/ripple/rpc/handlers/Submit.cpp +++ b/src/ripple/rpc/handlers/Submit.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,51 @@ getFailHard(RPC::JsonContext const& context) context.params["fail_hard"].asBool()); } +// { +// tx_blob: serialized tx +// } +// Only for debug use!!!! +Json::Value +doInject(RPC::JsonContext& context) +{ + if (context.role != Role::ADMIN) + return RPC::make_error( + rpcNOT_SUPPORTED, "Signing is not supported by this server."); + if (context.role != Role::ADMIN) + return rpcError(rpcNO_PERMISSION); + + Json::Value jvResult; + + auto ret = strUnHex(context.params[jss::tx_blob].asString()); + + if (!ret || !ret->size()) + return rpcError(rpcINVALID_PARAMS); + + SerialIter sitTrans(makeSlice(*ret)); + + std::shared_ptr stpTrans; + + try + { + stpTrans = std::make_shared(std::ref(sitTrans)); + } + catch (std::exception& e) + { + jvResult[jss::error] = "invalidTransaction"; + jvResult[jss::error_exception] = e.what(); + jvResult[jss::in_queue] = false; + + return jvResult; + } + + context.app.getTxQ().debugTxInject(*stpTrans); + + jvResult[jss::tx_json] = stpTrans->getJson(JsonOptions::none); + jvResult[jss::in_queue] = true; + + return jvResult; +} + // { // tx_json: , // secret: diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/ripple/rpc/impl/Handler.cpp index 9b06e9c46..473ecd769 100644 --- a/src/ripple/rpc/impl/Handler.cpp +++ b/src/ripple/rpc/impl/Handler.cpp @@ -141,6 +141,7 @@ Handler const handlerArray[]{ {"ripple_path_find", byRef(&doRipplePathFind), Role::USER, NO_CONDITION}, {"sign", byRef(&doSign), Role::USER, NO_CONDITION}, {"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION}, + {"inject", byRef(&doInject), Role::USER, NEEDS_CURRENT_LEDGER}, {"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER}, {"submit_multisigned", byRef(&doSubmitMultiSigned),