From 02f14b05befe423d3dbc79b8cd7221bfdda77719 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 23 Oct 2023 11:29:09 -0400 Subject: [PATCH] update API changelog --- API-CHANGELOG.md | 1 + src/ripple/rpc/handlers/Feature1.cpp | 23 +++++++++++++++++ src/ripple/rpc/impl/Handler.cpp | 2 +- src/test/rpc/Feature_test.cpp | 38 ++++++++++++++++++++++++---- 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/API-CHANGELOG.md b/API-CHANGELOG.md index a3c06399cf5..cf022e4b04f 100644 --- a/API-CHANGELOG.md +++ b/API-CHANGELOG.md @@ -33,6 +33,7 @@ The `network_id` field was added in the `server_info` response in version 1.5.0 Additions are intended to be non-breaking (because they are purely additive). - `server_definitions`: A new RPC that generates a `definitions.json`-like output that can be used in XRPL libraries. +- `feature`: A non-admin mode that decodes the hex version of amendment names. ## XRP Ledger version 1.12.0 diff --git a/src/ripple/rpc/handlers/Feature1.cpp b/src/ripple/rpc/handlers/Feature1.cpp index 1858a062e53..482c1b33b00 100644 --- a/src/ripple/rpc/handlers/Feature1.cpp +++ b/src/ripple/rpc/handlers/Feature1.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,28 @@ doFeature(RPC::JsonContext& context) if (context.app.config().reporting()) return rpcError(rpcREPORTING_UNSUPPORTED); + if (context.role != Role::ADMIN) + { + if (!context.params.isMember(jss::feature)) + { + return RPC::missing_field_error(jss::feature); + } + std::string const& featureStr = context.params[jss::feature].asString(); + uint256 feature; + if (!feature.parseHex(featureStr)) + { + return rpcError(rpcBAD_FEATURE); + } + std::string const& featureName = featureToName(feature); + if (featureName == featureStr) + { + return rpcError(rpcBAD_FEATURE); + } + Json::Value jvReply = Json::objectValue; + jvReply[jss::feature] = featureName; + return jvReply; + } + // Get majority amendment status majorityAmendments_t majorities; diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/ripple/rpc/impl/Handler.cpp index b69d2608b0e..24fc06f377a 100644 --- a/src/ripple/rpc/impl/Handler.cpp +++ b/src/ripple/rpc/impl/Handler.cpp @@ -92,7 +92,7 @@ Handler const handlerArray[]{ {"gateway_balances", byRef(&doGatewayBalances), Role::USER, NO_CONDITION}, #endif {"get_counts", byRef(&doGetCounts), Role::ADMIN, NO_CONDITION}, - {"feature", byRef(&doFeature), Role::ADMIN, NO_CONDITION}, + {"feature", byRef(&doFeature), Role::USER, NO_CONDITION}, {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER}, {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION}, {"ledger_accept", diff --git a/src/test/rpc/Feature_test.cpp b/src/test/rpc/Feature_test.cpp index dcd95c8a968..2de93521052 100644 --- a/src/test/rpc/Feature_test.cpp +++ b/src/test/rpc/Feature_test.cpp @@ -205,11 +205,39 @@ class Feature_test : public beast::unit_test::suite return cfg; })}; - auto jrr = env.rpc("feature")[jss::result]; - // The current HTTP/S ServerHandler returns an HTTP 403 error code here - // rather than a noPermission JSON error. The JSONRPCClient just eats - // that error and returns an null result. - BEAST_EXPECT(jrr.isNull()); + { + auto result = env.rpc("feature")[jss::result]; + BEAST_EXPECT(result[jss::error] == "invalidParams"); + BEAST_EXPECT( + result[jss::error_message] == "Missing field 'feature'."); + } + + { + Json::Value params; + // invalid feature + params[jss::feature] = + "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCD" + "EF"; + auto const result = env.rpc( + "json", + "feature", + boost::lexical_cast(params))[jss::result]; + BEAST_EXPECT(result[jss::error] == "badFeature"); + BEAST_EXPECT( + result[jss::error_message] == "Feature unknown or invalid."); + } + + { + Json::Value params; + params[jss::feature] = + "93E516234E35E08CA689FA33A6D38E103881F8DCB53023F728C307AA89D515" + "A7"; + auto const result = env.rpc( + "json", + "feature", + boost::lexical_cast(params))[jss::result]; + BEAST_EXPECT(result[jss::feature] == "XRPFees"); + } } void