Compare commits

...

1 Commits

Author SHA1 Message Date
vjkhannaripple
5f4da531e1 fix(rpc): standardize error codes in doTransactionEntry (RIPD-7750)
Replace 4 ad-hoc jvResult[jss::error] string assignments with
rpc::injectError() calls using registered error codes. Responses
now include numeric error_code and error_message fields consistent
with all other RPC handlers.

Mapping:
  "fieldNotFoundTransaction" → RpcInvalidParams (missing tx_hash)
  "notYetImplemented"        → RpcNotImpl       (current ledger)
  "malformedRequest"         → RpcInvalidParams (bad hex)
  "transactionNotFound"      → RpcTxnNotFound   (tx absent)

Add <xrpl/protocol/ErrorCodes.h> include. Remove stale XXX comments.
Update TransactionEntry_test to assert error_code numerically.

Closes: https://github.com/XRPLF/rippled/issues/6798
RIPD-7750

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-25 15:11:32 -04:00
2 changed files with 22 additions and 14 deletions

View File

@@ -36,9 +36,10 @@ class TransactionEntry_test : public beast::unit_test::Suite
})}; })};
{ {
// no params // no params — AC-1: missing tx_hash → invalidParams
auto const result = env.client().invoke("transaction_entry", {})[jss::result]; auto const result = env.client().invoke("transaction_entry", {})[jss::result];
BEAST_EXPECT(result[jss::error] == "fieldNotFoundTransaction"); BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::status] == "error"); BEAST_EXPECT(result[jss::status] == "error");
} }
@@ -51,21 +52,25 @@ class TransactionEntry_test : public beast::unit_test::Suite
} }
{ {
// AC-2: current ledger (no closed ledger) → notImpl
json::Value params{json::ValueType::Object}; json::Value params{json::ValueType::Object};
params[jss::ledger] = "current"; params[jss::ledger] = "current";
params[jss::tx_hash] = "DEADBEEF"; params[jss::tx_hash] = "DEADBEEF";
auto const result = env.client().invoke("transaction_entry", params)[jss::result]; auto const result = env.client().invoke("transaction_entry", params)[jss::result];
BEAST_EXPECT(result[jss::error] == "notYetImplemented"); BEAST_EXPECT(result[jss::error] == "notImpl");
BEAST_EXPECT(result[jss::error_code] == RpcNotImpl);
BEAST_EXPECT(result[jss::status] == "error"); BEAST_EXPECT(result[jss::status] == "error");
} }
{ {
// AC-3: tx_hash is not valid hex → invalidParams
json::Value params{json::ValueType::Object}; json::Value params{json::ValueType::Object};
params[jss::ledger] = "closed"; params[jss::ledger] = "closed";
params[jss::tx_hash] = "DEADBEEF"; params[jss::tx_hash] = "DEADBEEF";
auto const result = env.client().invoke("transaction_entry", params)[jss::result]; auto const result = env.client().invoke("transaction_entry", params)[jss::result];
BEAST_EXPECT(!result[jss::ledger_hash].asString().empty()); BEAST_EXPECT(!result[jss::ledger_hash].asString().empty());
BEAST_EXPECT(result[jss::error] == "malformedRequest"); BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::status] == "error"); BEAST_EXPECT(result[jss::status] == "error");
} }
@@ -126,8 +131,10 @@ class TransactionEntry_test : public beast::unit_test::Suite
{ {
// Valid structure, but transaction not found. // Valid structure, but transaction not found.
json::Value const result{env.rpc("transaction_entry", txHash, "closed")}; json::Value const result{env.rpc("transaction_entry", txHash, "closed")};
// AC-4: valid hex but tx not in ledger → txnNotFound
BEAST_EXPECT(!result[jss::result][jss::ledger_hash].asString().empty()); BEAST_EXPECT(!result[jss::result][jss::ledger_hash].asString().empty());
BEAST_EXPECT(result[jss::result][jss::error] == "transactionNotFound"); BEAST_EXPECT(result[jss::result][jss::error] == "txnNotFound");
BEAST_EXPECT(result[jss::result][jss::error_code] == RpcTxnNotFound);
BEAST_EXPECT(result[jss::result][jss::status] == "error"); BEAST_EXPECT(result[jss::result][jss::status] == "error");
} }
} }

View File

@@ -7,6 +7,7 @@
#include <xrpl/basics/chrono.h> #include <xrpl/basics/chrono.h>
#include <xrpl/json/json_value.h> #include <xrpl/json/json_value.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/jss.h> #include <xrpl/protocol/jss.h>
#include <memory> #include <memory>
@@ -18,7 +19,7 @@ namespace xrpl {
// ledger_index : <ledger_index> // ledger_index : <ledger_index>
// } // }
// //
// XXX In this case, not specify either ledger does not mean ledger current. It // Note: not specifying either ledger does not mean ledger current — it
// means any ledger. // means any ledger.
json::Value json::Value
doTransactionEntry(rpc::JsonContext& context) doTransactionEntry(rpc::JsonContext& context)
@@ -31,30 +32,30 @@ doTransactionEntry(rpc::JsonContext& context)
if (!context.params.isMember(jss::tx_hash)) if (!context.params.isMember(jss::tx_hash))
{ {
jvResult[jss::error] = "fieldNotFoundTransaction"; // AC-1: missing tx_hash parameter
rpc::injectError(RpcInvalidParams, jvResult);
} }
else if (jvResult.get(jss::ledger_hash, json::ValueType::Null).isNull()) else if (jvResult.get(jss::ledger_hash, json::ValueType::Null).isNull())
{ {
// We don't work on ledger current. // We don't work on ledger current.
// AC-2: no closed ledger specified
// XXX We don't support any transaction yet. rpc::injectError(RpcNotImpl, jvResult);
jvResult[jss::error] = "notYetImplemented";
} }
else else
{ {
uint256 uTransID; uint256 uTransID;
// XXX Relying on trusted WSS client. Would be better to have a strict
// routine, returning success or failure.
if (!uTransID.parseHex(context.params[jss::tx_hash].asString())) if (!uTransID.parseHex(context.params[jss::tx_hash].asString()))
{ {
jvResult[jss::error] = "malformedRequest"; // AC-3: tx_hash is not valid hex
rpc::injectError(RpcInvalidParams, jvResult);
return jvResult; return jvResult;
} }
auto [sttx, stobj] = lpLedger->txRead(uTransID); auto [sttx, stobj] = lpLedger->txRead(uTransID);
if (!sttx) if (!sttx)
{ {
jvResult[jss::error] = "transactionNotFound"; // AC-4: transaction not found in ledger
rpc::injectError(RpcTxnNotFound, jvResult);
} }
else else
{ {