From 7877ed970404de69a9f4b4a2975029fd58104fdf Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Wed, 17 Jan 2024 18:07:05 +0000 Subject: [PATCH 1/2] debug txn injector --- src/ripple/app/misc/TxQ.h | 8 ++++++ src/ripple/app/misc/impl/TxQ.cpp | 37 ++++++++++++++++++++++++ src/ripple/protocol/jss.h | 1 + src/ripple/rpc/handlers/Handlers.h | 2 ++ src/ripple/rpc/handlers/Submit.cpp | 46 ++++++++++++++++++++++++++++++ src/ripple/rpc/impl/Handler.cpp | 1 + 6 files changed, 95 insertions(+) diff --git a/src/ripple/app/misc/TxQ.h b/src/ripple/app/misc/TxQ.h index ae35dd1f6..cccb4bd2a 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..c49716fd7 100644 --- a/src/ripple/app/misc/impl/TxQ.cpp +++ b/src/ripple/app/misc/impl/TxQ.cpp @@ -93,6 +93,14 @@ 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 +1452,35 @@ 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..dd853203b 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -353,6 +353,7 @@ JSS(ident); // in: AccountCurrencies, AccountInfo, // OwnerInfo JSS(ignore_default); // in: AccountLines JSS(inLedger); // out: tx/Transaction +JSS(in_queue); JSS(inbound); // out: PeerImp JSS(index); // in: LedgerEntry, DownloadShard // out: STLedgerEntry, 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..d3f4b329f 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.params.isMember(jss::tx_blob)) + return RPC::make_error( + rpcINVALID_PARAMS, "Need tx_blob"); + + 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), From fdf7ea41744bc2813acee254d1d1823125128879 Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Wed, 17 Jan 2024 18:14:51 +0000 Subject: [PATCH 2/2] dbg inject clang + permission check --- src/ripple/app/misc/TxQ.h | 2 +- src/ripple/app/misc/impl/TxQ.cpp | 16 ++++++---------- src/ripple/protocol/jss.h | 10 +++++----- src/ripple/rpc/handlers/Submit.cpp | 14 +++++++------- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/ripple/app/misc/TxQ.h b/src/ripple/app/misc/TxQ.h index cccb4bd2a..5a43ac81b 100644 --- a/src/ripple/app/misc/TxQ.h +++ b/src/ripple/app/misc/TxQ.h @@ -60,8 +60,8 @@ class TxQ private: std::mutex debugTxInjectMutex; std::vector debugTxInjectQueue; -public: +public: void debugTxInject(STTx const& txn); diff --git a/src/ripple/app/misc/impl/TxQ.cpp b/src/ripple/app/misc/impl/TxQ.cpp index c49716fd7..379eb1ee1 100644 --- a/src/ripple/app/misc/impl/TxQ.cpp +++ b/src/ripple/app/misc/impl/TxQ.cpp @@ -100,7 +100,6 @@ TxQ::debugTxInject(STTx const& txn) debugTxInjectQueue.push_back(txn); } - std::size_t TxQ::FeeMetrics::update( Application& app, @@ -1454,26 +1453,23 @@ TxQ::accept(Application& app, OpenView& view) // 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()) + 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(); + const_cast(txn).downcast(); auto s = std::make_shared(); emitted.add(*s); - view.rawTxInsert( - txnHash, - std::move(s), - nullptr); + view.rawTxInsert(txnHash, std::move(s), nullptr); ledgerChanged = true; } diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index dd853203b..2847af8ad 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -354,11 +354,11 @@ JSS(ident); // in: AccountCurrencies, AccountInfo, JSS(ignore_default); // in: AccountLines JSS(inLedger); // out: tx/Transaction JSS(in_queue); -JSS(inbound); // out: PeerImp -JSS(index); // in: LedgerEntry, DownloadShard - // out: STLedgerEntry, - // LedgerEntry, TxHistory, LedgerData -JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo +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/Submit.cpp b/src/ripple/rpc/handlers/Submit.cpp index d3f4b329f..42897bf71 100644 --- a/src/ripple/rpc/handlers/Submit.cpp +++ b/src/ripple/rpc/handlers/Submit.cpp @@ -40,7 +40,6 @@ getFailHard(RPC::JsonContext const& context) context.params["fail_hard"].asBool()); } - // { // tx_blob: serialized tx // } @@ -48,9 +47,11 @@ getFailHard(RPC::JsonContext const& context) Json::Value doInject(RPC::JsonContext& context) { - if (!context.params.isMember(jss::tx_blob)) - return RPC::make_error( - rpcINVALID_PARAMS, "Need tx_blob"); + 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; @@ -78,11 +79,10 @@ doInject(RPC::JsonContext& context) context.app.getTxQ().debugTxInject(*stpTrans); - jvResult[jss::tx_json] = stpTrans->getJson(JsonOptions::none); jvResult[jss::in_queue] = true; - - return jvResult; + + return jvResult; } // {