From 2eb1c6a396440d2f2692166f3d89c6190918b7e9 Mon Sep 17 00:00:00 2001 From: Peng Wang Date: Tue, 23 Jun 2020 17:47:19 -0400 Subject: [PATCH] Enable testing beta RPC API version with config --- cfg/rippled-example.cfg | 9 ++ src/ripple/app/main/Application.cpp | 2 +- src/ripple/app/reporting/P2pProxy.cpp | 3 +- src/ripple/core/Config.h | 3 + src/ripple/core/ConfigSections.h | 1 + src/ripple/core/impl/Config.cpp | 3 + src/ripple/net/impl/RPCCall.cpp | 13 +-- src/ripple/rpc/RPCHandler.h | 2 +- src/ripple/rpc/handlers/Version.h | 9 +- src/ripple/rpc/impl/Handler.cpp | 72 +++++-------- src/ripple/rpc/impl/Handler.h | 2 +- src/ripple/rpc/impl/RPCHandler.cpp | 7 +- src/ripple/rpc/impl/RPCHelpers.cpp | 11 +- src/ripple/rpc/impl/RPCHelpers.h | 51 +++++---- src/ripple/rpc/impl/ServerHandlerImp.cpp | 28 +++-- src/ripple/rpc/impl/TransactionSign.cpp | 4 +- src/test/app/Path_test.cpp | 4 +- src/test/rpc/AccountTx_test.cpp | 4 +- src/test/rpc/LedgerRequestRPC_test.cpp | 2 +- src/test/rpc/RPCCall_test.cpp | 6 +- src/test/rpc/Version_test.cpp | 132 +++++++++++++++++------ 21 files changed, 230 insertions(+), 138 deletions(-) diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index 099624c989..e5a208c561 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -1502,6 +1502,15 @@ # Enable or disable access to /vl requests. Default is '1' which # enables access. # +# [beta_rpc_api] +# +# 0 or 1. +# +# 0: Disable the beta API version for JSON-RPC and WebSocket [default] +# 1: Enable the beta API version for testing. The beta API version +# contains breaking changes that require a new API version number. +# They are not ready for public consumption. +# #------------------------------------------------------------------------------- # # 10. Example Settings diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 674811ce66..0dab388225 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -1502,7 +1502,7 @@ ApplicationImp::setup() Role::ADMIN, {}, {}, - RPC::ApiMaximumSupportedVersion}, + RPC::apiMaximumSupportedVersion}, jvCommand}; Json::Value jvResult; diff --git a/src/ripple/app/reporting/P2pProxy.cpp b/src/ripple/app/reporting/P2pProxy.cpp index af3893cfbf..8e4fc3a97a 100644 --- a/src/ripple/app/reporting/P2pProxy.cpp +++ b/src/ripple/app/reporting/P2pProxy.cpp @@ -54,7 +54,8 @@ shouldForwardToP2p(RPC::JsonContext& context) JLOG(context.j.trace()) << "COMMAND:" << strCommand; JLOG(context.j.trace()) << "REQUEST:" << params; - auto handler = RPC::getHandler(context.apiVersion, strCommand); + auto handler = RPC::getHandler( + context.apiVersion, context.app.config().BETA_RPC_API, strCommand); if (!handler) { JLOG(context.j.error()) diff --git a/src/ripple/core/Config.h b/src/ripple/core/Config.h index 850b4f813e..08615395ea 100644 --- a/src/ripple/core/Config.h +++ b/src/ripple/core/Config.h @@ -226,6 +226,9 @@ public: // How long can a peer remain in the "diverged" state std::chrono::seconds MAX_DIVERGED_TIME{300}; + // Enable the beta API version + bool BETA_RPC_API = false; + public: Config() : j_{beast::Journal::getNullSink()} { diff --git a/src/ripple/core/ConfigSections.h b/src/ripple/core/ConfigSections.h index f5244738a0..9b87dccd42 100644 --- a/src/ripple/core/ConfigSections.h +++ b/src/ripple/core/ConfigSections.h @@ -98,6 +98,7 @@ struct ConfigSection #define SECTION_VETO_AMENDMENTS "veto_amendments" #define SECTION_WORKERS "workers" #define SECTION_LEDGER_REPLAY "ledger_replay" +#define SECTION_BETA_RPC_API "beta_rpc_api" } // namespace ripple diff --git a/src/ripple/core/impl/Config.cpp b/src/ripple/core/impl/Config.cpp index fef5c2a5ae..120b0384b0 100644 --- a/src/ripple/core/impl/Config.cpp +++ b/src/ripple/core/impl/Config.cpp @@ -635,6 +635,9 @@ Config::loadFromString(std::string const& fileContents) "majority is 15 minutes"); } + if (getSingleSection(secConfig, SECTION_BETA_RPC_API, strTemp, j_)) + BETA_RPC_API = beast::lexicalCastThrow(strTemp); + // Do not load trusted validator configuration for standalone mode if (!RUN_STANDALONE) { diff --git a/src/ripple/net/impl/RPCCall.cpp b/src/ripple/net/impl/RPCCall.cpp index d688f79bb6..5c91c6e8f1 100644 --- a/src/ripple/net/impl/RPCCall.cpp +++ b/src/ripple/net/impl/RPCCall.cpp @@ -315,8 +315,8 @@ private: if (uLedgerMax != -1 && uLedgerMax < uLedgerMin) { - // The command line always follows ApiMaximumSupportedVersion - if (RPC::ApiMaximumSupportedVersion == 1) + // The command line always follows apiMaximumSupportedVersion + if (RPC::apiMaximumSupportedVersion == 1) return rpcError(rpcLGR_IDXS_INVALID); return rpcError(rpcNOT_SYNCED); } @@ -388,8 +388,8 @@ private: if (uLedgerMax != -1 && uLedgerMax < uLedgerMin) { - // The command line always follows ApiMaximumSupportedVersion - if (RPC::ApiMaximumSupportedVersion == 1) + // The command line always follows apiMaximumSupportedVersion + if (RPC::apiMaximumSupportedVersion == 1) return rpcError(rpcLGR_IDXS_INVALID); return rpcError(rpcNOT_SYNCED); } @@ -1402,7 +1402,8 @@ struct RPCCallImp // Parse reply JLOG(j.debug()) << "RPC reply: " << strData << std::endl; - if (strData.find("Unable to parse request") == 0) + if (strData.find("Unable to parse request") == 0 || + strData.find(jss::invalid_API_version.c_str()) == 0) Throw(strData); Json::Reader reader; Json::Value jvReply; @@ -1473,7 +1474,7 @@ rpcCmdLineToJson( if (jr.isObject() && !jr.isMember(jss::error) && !jr.isMember(jss::api_version)) { - jr[jss::api_version] = RPC::ApiMaximumSupportedVersion; + jr[jss::api_version] = RPC::apiMaximumSupportedVersion; } }; diff --git a/src/ripple/rpc/RPCHandler.h b/src/ripple/rpc/RPCHandler.h index fd72830642..45c737783c 100644 --- a/src/ripple/rpc/RPCHandler.h +++ b/src/ripple/rpc/RPCHandler.h @@ -35,7 +35,7 @@ Status doCommand(RPC::JsonContext&, Json::Value&); Role -roleRequired(unsigned int version, std::string const& method); +roleRequired(unsigned int version, bool betaEnabled, std::string const& method); } // namespace RPC } // namespace ripple diff --git a/src/ripple/rpc/handlers/Version.h b/src/ripple/rpc/handlers/Version.h index 640757a441..a9f42b9499 100644 --- a/src/ripple/rpc/handlers/Version.h +++ b/src/ripple/rpc/handlers/Version.h @@ -28,7 +28,8 @@ namespace RPC { class VersionHandler { public: - explicit VersionHandler(JsonContext&) + explicit VersionHandler(JsonContext& c) + : apiVersion_(c.apiVersion), betaEnabled_(c.app.config().BETA_RPC_API) { } @@ -42,7 +43,7 @@ public: void writeResult(Object& obj) { - setVersion(obj); + setVersion(obj, apiVersion_, betaEnabled_); } static char const* @@ -62,6 +63,10 @@ public: { return NO_CONDITION; } + +private: + unsigned int apiVersion_; + bool betaEnabled_; }; } // namespace RPC diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/ripple/rpc/impl/Handler.cpp index 87515d9f16..2ba1c95c8e 100644 --- a/src/ripple/rpc/impl/Handler.cpp +++ b/src/ripple/rpc/impl/Handler.cpp @@ -170,23 +170,16 @@ private: template explicit HandlerTable(const Handler (&entries)[N]) { - for (auto v = RPC::ApiMinimumSupportedVersion; - v <= RPC::ApiMaximumSupportedVersion; - ++v) + for (std::size_t i = 0; i < N; ++i) { - for (std::size_t i = 0; i < N; ++i) - { - auto& innerTable = table_[versionToIndex(v)]; - auto const& entry = entries[i]; - assert(innerTable.find(entry.name_) == innerTable.end()); - innerTable[entry.name_] = entry; - } - - // This is where the new-style handlers are added. - // This is also where different versions of handlers are added. - addHandler(v); - addHandler(v); + auto const& entry = entries[i]; + assert(table_.find(entry.name_) == table_.end()); + table_[entry.name_] = entry; } + + // This is where the new-style handlers are added. + addHandler(); + addHandler(); } public: @@ -198,43 +191,34 @@ public: } Handler const* - getHandler(unsigned version, std::string name) const + getHandler(unsigned version, bool betaEnabled, std::string name) const { - if (version > RPC::ApiMaximumSupportedVersion || - version < RPC::ApiMinimumSupportedVersion) + if (version < RPC::apiMinimumSupportedVersion || + version > (betaEnabled ? RPC::apiBetaVersion + : RPC::apiMaximumSupportedVersion)) return nullptr; - auto& innerTable = table_[versionToIndex(version)]; - auto i = innerTable.find(name); - return i == innerTable.end() ? nullptr : &i->second; + auto i = table_.find(name); + return i == table_.end() ? nullptr : &i->second; } std::vector getHandlerNames() const { - std::unordered_set name_set; - for (int index = 0; index < table_.size(); ++index) - { - for (auto const& h : table_[index]) - { - name_set.insert(h.second.name_); - } - } - return std::vector(name_set.begin(), name_set.end()); + std::vector ret; + ret.reserve(table_.size()); + for (auto const& i : table_) + ret.push_back(i.second.name_); + return ret; } private: - std::array, APINumberVersionSupported> - table_; + std::map table_; template void - addHandler(unsigned version) + addHandler() { - assert( - version >= RPC::ApiMinimumSupportedVersion && - version <= RPC::ApiMaximumSupportedVersion); - auto& innerTable = table_[versionToIndex(version)]; - assert(innerTable.find(HandlerImpl::name()) == innerTable.end()); + assert(table_.find(HandlerImpl::name()) == table_.end()); Handler h; h.name_ = HandlerImpl::name(); @@ -242,22 +226,16 @@ private: h.role_ = HandlerImpl::role(); h.condition_ = HandlerImpl::condition(); - innerTable[HandlerImpl::name()] = h; - } - - inline unsigned - versionToIndex(unsigned version) const - { - return version - RPC::ApiMinimumSupportedVersion; + table_[HandlerImpl::name()] = h; } }; } // namespace Handler const* -getHandler(unsigned version, std::string const& name) +getHandler(unsigned version, bool betaEnabled, std::string const& name) { - return HandlerTable::instance().getHandler(version, name); + return HandlerTable::instance().getHandler(version, betaEnabled, name); } std::vector diff --git a/src/ripple/rpc/impl/Handler.h b/src/ripple/rpc/impl/Handler.h index 2c867c379f..73f2232d5c 100644 --- a/src/ripple/rpc/impl/Handler.h +++ b/src/ripple/rpc/impl/Handler.h @@ -55,7 +55,7 @@ struct Handler }; Handler const* -getHandler(unsigned int version, std::string const&); +getHandler(unsigned int version, bool betaEnabled, std::string const&); /** Return a Json::objectValue with a single entry. */ template diff --git a/src/ripple/rpc/impl/RPCHandler.cpp b/src/ripple/rpc/impl/RPCHandler.cpp index b3f4e3d804..5430f3a6a5 100644 --- a/src/ripple/rpc/impl/RPCHandler.cpp +++ b/src/ripple/rpc/impl/RPCHandler.cpp @@ -156,7 +156,8 @@ fillHandler(JsonContext& context, Handler const*& result) JLOG(context.j.trace()) << "COMMAND:" << strCommand; JLOG(context.j.trace()) << "REQUEST:" << context.params; - auto handler = getHandler(context.apiVersion, strCommand); + auto handler = getHandler( + context.apiVersion, context.app.config().BETA_RPC_API, strCommand); if (!handler) return rpcUNKNOWN_COMMAND; @@ -289,9 +290,9 @@ doCommand(RPC::JsonContext& context, Json::Value& result) } Role -roleRequired(unsigned int version, std::string const& method) +roleRequired(unsigned int version, bool betaEnabled, std::string const& method) { - auto handler = RPC::getHandler(version, method); + auto handler = RPC::getHandler(version, betaEnabled, method); if (!handler) return Role::FORBID; diff --git a/src/ripple/rpc/impl/RPCHelpers.cpp b/src/ripple/rpc/impl/RPCHelpers.cpp index a483b8c7ca..8ee81df882 100644 --- a/src/ripple/rpc/impl/RPCHelpers.cpp +++ b/src/ripple/rpc/impl/RPCHelpers.cpp @@ -886,13 +886,14 @@ beast::SemanticVersion const goodVersion("1.0.0"); beast::SemanticVersion const lastVersion("1.0.0"); unsigned int -getAPIVersionNumber(Json::Value const& jv) +getAPIVersionNumber(Json::Value const& jv, bool betaEnabled) { - static Json::Value const minVersion(RPC::ApiMinimumSupportedVersion); - static Json::Value const maxVersion(RPC::ApiMaximumSupportedVersion); - static Json::Value const invalidVersion(RPC::APIInvalidVersion); + static Json::Value const minVersion(RPC::apiMinimumSupportedVersion); + static Json::Value const invalidVersion(RPC::apiInvalidVersion); - Json::Value requestedVersion(RPC::APIVersionIfUnspecified); + Json::Value const maxVersion( + betaEnabled ? RPC::apiBetaVersion : RPC::apiMaximumSupportedVersion); + Json::Value requestedVersion(RPC::apiVersionIfUnspecified); if (jv.isObject()) { requestedVersion = jv.get(jss::api_version, requestedVersion); diff --git a/src/ripple/rpc/impl/RPCHelpers.h b/src/ripple/rpc/impl/RPCHelpers.h index 11331d30ca..d2952aba27 100644 --- a/src/ripple/rpc/impl/RPCHelpers.h +++ b/src/ripple/rpc/impl/RPCHelpers.h @@ -200,38 +200,52 @@ extern beast::SemanticVersion const lastVersion; * API version numbers used in later API versions * * Requests with a version number in the range - * [ApiMinimumSupportedVersion, ApiMaximumSupportedVersion] + * [apiMinimumSupportedVersion, apiMaximumSupportedVersion] + * are supported. + * + * If [beta_rpc_api] is enabled in config, the version numbers + * in the range [apiMinimumSupportedVersion, apiBetaVersion] * are supported. * * Network Requests without explicit version numbers use - * APIVersionIfUnspecified. APIVersionIfUnspecified is 1, + * apiVersionIfUnspecified. apiVersionIfUnspecified is 1, * because all the RPC requests with a version >= 2 must * explicitly specify the version in the requests. - * Note that APIVersionIfUnspecified will be lower than - * ApiMinimumSupportedVersion when we stop supporting API + * Note that apiVersionIfUnspecified will be lower than + * apiMinimumSupportedVersion when we stop supporting API * version 1. * - * Command line Requests use ApiMaximumSupportedVersion. + * Command line Requests use apiMaximumSupportedVersion. */ -constexpr unsigned int APIInvalidVersion = 0; -constexpr unsigned int APIVersionIfUnspecified = 1; -constexpr unsigned int ApiMinimumSupportedVersion = 1; -constexpr unsigned int ApiMaximumSupportedVersion = 1; -constexpr unsigned int APINumberVersionSupported = - ApiMaximumSupportedVersion - ApiMinimumSupportedVersion + 1; +constexpr unsigned int apiInvalidVersion = 0; +constexpr unsigned int apiVersionIfUnspecified = 1; +constexpr unsigned int apiMinimumSupportedVersion = 1; +constexpr unsigned int apiMaximumSupportedVersion = 1; +constexpr unsigned int apiBetaVersion = 2; -static_assert(ApiMinimumSupportedVersion >= APIVersionIfUnspecified); -static_assert(ApiMaximumSupportedVersion >= ApiMinimumSupportedVersion); +static_assert(apiMinimumSupportedVersion >= apiVersionIfUnspecified); +static_assert(apiMaximumSupportedVersion >= apiMinimumSupportedVersion); +static_assert(apiBetaVersion >= apiMaximumSupportedVersion); template void -setVersion(Object& parent) +setVersion(Object& parent, unsigned int apiVersion, bool betaEnabled) { + assert(apiVersion != apiInvalidVersion); auto&& object = addObject(parent, jss::version); - object[jss::first] = firstVersion.print(); - object[jss::good] = goodVersion.print(); - object[jss::last] = lastVersion.print(); + if (apiVersion == apiVersionIfUnspecified) + { + object[jss::first] = firstVersion.print(); + object[jss::good] = goodVersion.print(); + object[jss::last] = lastVersion.print(); + } + else + { + object[jss::first] = apiMinimumSupportedVersion; + object[jss::last] = + betaEnabled ? apiBetaVersion : apiMaximumSupportedVersion; + } } std::pair @@ -248,10 +262,11 @@ chooseLedgerEntryType(Json::Value const& params); * * @param value a Json value that may or may not specifies * the api version number + * @param betaEnabled if the beta API version is enabled * @return the api version number */ unsigned int -getAPIVersionNumber(const Json::Value& value); +getAPIVersionNumber(const Json::Value& value, bool betaEnabled); } // namespace RPC } // namespace ripple diff --git a/src/ripple/rpc/impl/ServerHandlerImp.cpp b/src/ripple/rpc/impl/ServerHandlerImp.cpp index 9217188c72..b8d9567b02 100644 --- a/src/ripple/rpc/impl/ServerHandlerImp.cpp +++ b/src/ripple/rpc/impl/ServerHandlerImp.cpp @@ -397,8 +397,9 @@ ServerHandlerImp::processSession( Resource::Charge loadType = Resource::feeReferenceRPC; try { - auto apiVersion = RPC::getAPIVersionNumber(jv); - if (apiVersion == RPC::APIInvalidVersion || + auto apiVersion = + RPC::getAPIVersionNumber(jv, app_.config().BETA_RPC_API); + if (apiVersion == RPC::apiInvalidVersion || (!jv.isMember(jss::command) && !jv.isMember(jss::method)) || (jv.isMember(jss::command) && !jv[jss::command].isString()) || (jv.isMember(jss::method) && !jv[jss::method].isString()) || @@ -407,7 +408,7 @@ ServerHandlerImp::processSession( { jr[jss::type] = jss::response; jr[jss::status] = jss::error; - jr[jss::error] = apiVersion == RPC::APIInvalidVersion + jr[jss::error] = apiVersion == RPC::apiInvalidVersion ? jss::invalid_API_version : jss::missingCommand; jr[jss::request] = jv; @@ -426,6 +427,7 @@ ServerHandlerImp::processSession( auto required = RPC::roleRequired( apiVersion, + app_.config().BETA_RPC_API, jv.isMember(jss::command) ? jv[jss::command].asString() : jv[jss::method].asString()); auto role = requestRole( @@ -617,22 +619,24 @@ ServerHandlerImp::processRequest( continue; } - auto apiVersion = RPC::APIVersionIfUnspecified; + auto apiVersion = RPC::apiVersionIfUnspecified; if (jsonRPC.isMember(jss::params) && jsonRPC[jss::params].isArray() && jsonRPC[jss::params].size() > 0 && jsonRPC[jss::params][0u].isObject()) { - apiVersion = - RPC::getAPIVersionNumber(jsonRPC[jss::params][Json::UInt(0)]); + apiVersion = RPC::getAPIVersionNumber( + jsonRPC[jss::params][Json::UInt(0)], + app_.config().BETA_RPC_API); } - if (apiVersion == RPC::APIVersionIfUnspecified && batch) + if (apiVersion == RPC::apiVersionIfUnspecified && batch) { // for batch request, api_version may be at a different level - apiVersion = RPC::getAPIVersionNumber(jsonRPC); + apiVersion = + RPC::getAPIVersionNumber(jsonRPC, app_.config().BETA_RPC_API); } - if (apiVersion == RPC::APIInvalidVersion) + if (apiVersion == RPC::apiInvalidVersion) { if (!batch) { @@ -651,8 +655,10 @@ ServerHandlerImp::processRequest( auto role = Role::FORBID; auto required = Role::FORBID; if (jsonRPC.isMember(jss::method) && jsonRPC[jss::method].isString()) - required = - RPC::roleRequired(apiVersion, jsonRPC[jss::method].asString()); + required = RPC::roleRequired( + apiVersion, + app_.config().BETA_RPC_API, + jsonRPC[jss::method].asString()); if (jsonRPC.isMember(jss::params) && jsonRPC[jss::params].isArray() && jsonRPC[jss::params].size() > 0 && diff --git a/src/ripple/rpc/impl/TransactionSign.cpp b/src/ripple/rpc/impl/TransactionSign.cpp index 0c7871cfc5..8dff9ee62d 100644 --- a/src/ripple/rpc/impl/TransactionSign.cpp +++ b/src/ripple/rpc/impl/TransactionSign.cpp @@ -388,7 +388,7 @@ transactionPreProcessImpl( validatedLedgerAge, app.config(), app.getFeeTrack(), - getAPIVersionNumber(params)); + getAPIVersionNumber(params, app.config().BETA_RPC_API)); if (RPC::contains_error(txJsonResult)) return std::move(txJsonResult); @@ -1066,7 +1066,7 @@ transactionSubmitMultiSigned( validatedLedgerAge, app.config(), app.getFeeTrack(), - getAPIVersionNumber(jvRequest)); + getAPIVersionNumber(jvRequest, app.config().BETA_RPC_API)); if (RPC::contains_error(txJsonResult)) return std::move(txJsonResult); diff --git a/src/test/app/Path_test.cpp b/src/test/app/Path_test.cpp index 70b17e1366..32eb199058 100644 --- a/src/test/app/Path_test.cpp +++ b/src/test/app/Path_test.cpp @@ -226,7 +226,7 @@ public: Role::USER, {}, {}, - RPC::APIVersionIfUnspecified}, + RPC::apiVersionIfUnspecified}, {}, {}}; @@ -334,7 +334,7 @@ public: Role::USER, {}, {}, - RPC::APIVersionIfUnspecified}, + RPC::apiVersionIfUnspecified}, {}, {}}; Json::Value result; diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index 8734dc6fe4..91aaada4d2 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -176,7 +176,7 @@ class AccountTx_test : public beast::unit_test::suite p[jss::ledger_index_max] = 1; BEAST_EXPECT(isErr( env.rpc("json", "account_tx", to_string(p)), - (RPC::ApiMaximumSupportedVersion == 1 ? rpcLGR_IDXS_INVALID + (RPC::apiMaximumSupportedVersion == 1 ? rpcLGR_IDXS_INVALID : rpcINVALID_LGR_RANGE))); } @@ -192,7 +192,7 @@ class AccountTx_test : public beast::unit_test::suite p[jss::ledger_index_min] = env.current()->info().seq; BEAST_EXPECT(isErr( env.rpc("json", "account_tx", to_string(p)), - (RPC::ApiMaximumSupportedVersion == 1 ? rpcLGR_IDXS_INVALID + (RPC::apiMaximumSupportedVersion == 1 ? rpcLGR_IDXS_INVALID : rpcINVALID_LGR_RANGE))); } diff --git a/src/test/rpc/LedgerRequestRPC_test.cpp b/src/test/rpc/LedgerRequestRPC_test.cpp index 80b1113094..eff27fa68b 100644 --- a/src/test/rpc/LedgerRequestRPC_test.cpp +++ b/src/test/rpc/LedgerRequestRPC_test.cpp @@ -299,7 +299,7 @@ public: env.timeKeeper().adjustCloseTime(weeks{3}); result = env.rpc("ledger_request", "1")[jss::result]; BEAST_EXPECT(result[jss::status] == "error"); - if (RPC::ApiMaximumSupportedVersion == 1) + if (RPC::apiMaximumSupportedVersion == 1) { BEAST_EXPECT(result[jss::error] == "noCurrent"); BEAST_EXPECT( diff --git a/src/test/rpc/RPCCall_test.cpp b/src/test/rpc/RPCCall_test.cpp index cf4fbab1b1..d3565b9868 100644 --- a/src/test/rpc/RPCCall_test.cpp +++ b/src/test/rpc/RPCCall_test.cpp @@ -1437,7 +1437,7 @@ static RPCCallTestData const rpcCallTestArray[] = { __LINE__, {"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "580", "579"}, RPCCallTestData::no_exception, - RPC::ApiMaximumSupportedVersion == 1 ? + RPC::apiMaximumSupportedVersion == 1 ? R"({ "method" : "account_tx", "params" : [ @@ -5948,7 +5948,7 @@ static RPCCallTestData const rpcCallTestArray[] = { __LINE__, {"tx_account", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "580", "579"}, RPCCallTestData::no_exception, - RPC::ApiMaximumSupportedVersion == 1 ? + RPC::apiMaximumSupportedVersion == 1 ? R"({ "method" : "tx_account", "params" : [ @@ -6441,7 +6441,7 @@ std::string updateAPIVersionString(const char* const req) { static std::string version_str = - std::to_string(RPC::ApiMaximumSupportedVersion); + std::to_string(RPC::apiMaximumSupportedVersion); static auto place_holder = "%MAX_API_VER%"; std::string jr(req); boost::replace_all(jr, place_holder, version_str); diff --git a/src/test/rpc/Version_test.cpp b/src/test/rpc/Version_test.cpp index 78cc89ee34..360b29664a 100644 --- a/src/test/rpc/Version_test.cpp +++ b/src/test/rpc/Version_test.cpp @@ -43,7 +43,7 @@ class Version_test : public beast::unit_test::suite "json", "version", "{\"api_version\": " + - std::to_string(RPC::ApiMaximumSupportedVersion) + + std::to_string(RPC::apiMaximumSupportedVersion) + "}")[jss::result]; BEAST_EXPECT(isCorrectReply(jrr)); @@ -59,29 +59,32 @@ class Version_test : public beast::unit_test::suite using namespace test::jtx; Env env{*this}; - auto get_error_what = [](Json::Value const& re) -> std::string { + auto badVersion = [](Json::Value const& re) -> bool { if (re.isMember("error_what")) if (re["error_what"].isString()) - return re["error_what"].asString(); - return {}; + { + return re["error_what"].asString().find( + jss::invalid_API_version.c_str()) == 0; + } + return false; }; auto re = env.rpc( "json", "version", "{\"api_version\": " + - std::to_string(RPC::ApiMinimumSupportedVersion - 1) + "}"); - BEAST_EXPECT(get_error_what(re).find(jss::invalid_API_version.c_str())); + std::to_string(RPC::apiMinimumSupportedVersion - 1) + "}"); + BEAST_EXPECT(badVersion(re)); re = env.rpc( "json", "version", "{\"api_version\": " + - std::to_string(RPC::ApiMaximumSupportedVersion + 1) + "}"); - BEAST_EXPECT(get_error_what(re).find(jss::invalid_API_version.c_str())); + std::to_string(RPC::apiMaximumSupportedVersion + 1) + "}"); + BEAST_EXPECT(badVersion(re)); re = env.rpc("json", "version", "{\"api_version\": \"a\"}"); - BEAST_EXPECT(get_error_what(re).find(jss::invalid_API_version.c_str())); + BEAST_EXPECT(badVersion(re)); } void @@ -90,44 +93,56 @@ class Version_test : public beast::unit_test::suite testcase("test getAPIVersionNumber function"); unsigned int versionIfUnspecified = - RPC::APIVersionIfUnspecified < RPC::ApiMinimumSupportedVersion - ? RPC::APIInvalidVersion - : RPC::APIVersionIfUnspecified; + RPC::apiVersionIfUnspecified < RPC::apiMinimumSupportedVersion + ? RPC::apiInvalidVersion + : RPC::apiVersionIfUnspecified; Json::Value j_array = Json::Value(Json::arrayValue); Json::Value j_null = Json::Value(Json::nullValue); - BEAST_EXPECT(RPC::getAPIVersionNumber(j_array) == versionIfUnspecified); - BEAST_EXPECT(RPC::getAPIVersionNumber(j_null) == versionIfUnspecified); + BEAST_EXPECT( + RPC::getAPIVersionNumber(j_array, false) == versionIfUnspecified); + BEAST_EXPECT( + RPC::getAPIVersionNumber(j_null, false) == versionIfUnspecified); Json::Value j_object = Json::Value(Json::objectValue); BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object) == versionIfUnspecified); - j_object[jss::api_version] = RPC::APIVersionIfUnspecified; + RPC::getAPIVersionNumber(j_object, false) == versionIfUnspecified); + j_object[jss::api_version] = RPC::apiVersionIfUnspecified; BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object) == versionIfUnspecified); + RPC::getAPIVersionNumber(j_object, false) == versionIfUnspecified); - j_object[jss::api_version] = RPC::ApiMinimumSupportedVersion; + j_object[jss::api_version] = RPC::apiMinimumSupportedVersion; BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object) == - RPC::ApiMinimumSupportedVersion); - j_object[jss::api_version] = RPC::ApiMaximumSupportedVersion; + RPC::getAPIVersionNumber(j_object, false) == + RPC::apiMinimumSupportedVersion); + j_object[jss::api_version] = RPC::apiMaximumSupportedVersion; BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object) == - RPC::ApiMaximumSupportedVersion); + RPC::getAPIVersionNumber(j_object, false) == + RPC::apiMaximumSupportedVersion); - j_object[jss::api_version] = RPC::ApiMinimumSupportedVersion - 1; + j_object[jss::api_version] = RPC::apiMinimumSupportedVersion - 1; BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object) == RPC::APIInvalidVersion); - j_object[jss::api_version] = RPC::ApiMaximumSupportedVersion + 1; + RPC::getAPIVersionNumber(j_object, false) == + RPC::apiInvalidVersion); + j_object[jss::api_version] = RPC::apiMaximumSupportedVersion + 1; BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object) == RPC::APIInvalidVersion); + RPC::getAPIVersionNumber(j_object, false) == + RPC::apiInvalidVersion); + j_object[jss::api_version] = RPC::apiBetaVersion; + BEAST_EXPECT( + RPC::getAPIVersionNumber(j_object, true) == RPC::apiBetaVersion); + j_object[jss::api_version] = RPC::apiBetaVersion + 1; + BEAST_EXPECT( + RPC::getAPIVersionNumber(j_object, true) == RPC::apiInvalidVersion); - j_object[jss::api_version] = RPC::APIInvalidVersion; + j_object[jss::api_version] = RPC::apiInvalidVersion; BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object) == RPC::APIInvalidVersion); + RPC::getAPIVersionNumber(j_object, false) == + RPC::apiInvalidVersion); j_object[jss::api_version] = "a"; BEAST_EXPECT( - RPC::getAPIVersionNumber(j_object) == RPC::APIInvalidVersion); + RPC::getAPIVersionNumber(j_object, false) == + RPC::apiInvalidVersion); } void @@ -151,7 +166,7 @@ class Version_test : public beast::unit_test::suite "\"method\": \"version\", " "\"params\": { " "\"api_version\": " + - std::to_string(RPC::ApiMaximumSupportedVersion) + "}}"; + std::to_string(RPC::apiMaximumSupportedVersion) + "}}"; auto re = env.rpc( "json2", '[' + without_api_verion + ", " + with_api_verion + ']'); @@ -188,7 +203,7 @@ class Version_test : public beast::unit_test::suite "\"method\": \"version\", " "\"params\": { " "\"api_version\": " + - std::to_string(RPC::ApiMaximumSupportedVersion + 1) + "}}"; + std::to_string(RPC::apiMaximumSupportedVersion + 1) + "}}"; auto re = env.rpc( "json2", '[' + without_api_verion + ", " + with_wrong_api_verion + ']'); @@ -203,6 +218,57 @@ class Version_test : public beast::unit_test::suite BEAST_EXPECT(re[1u].isMember(jss::error)); } + void + testConfig() + { + testcase("config test"); + { + Config c; + BEAST_EXPECT(c.BETA_RPC_API == false); + } + + { + Config c; + c.loadFromString("\n[beta_rpc_api]\n1\n"); + BEAST_EXPECT(c.BETA_RPC_API == true); + } + + { + Config c; + c.loadFromString("\n[beta_rpc_api]\n0\n"); + BEAST_EXPECT(c.BETA_RPC_API == false); + } + } + + void + testVersionRPCV2() + { + testcase("test version RPC with api_version >= 2"); + + using namespace test::jtx; + Env env{*this, envconfig([](std::unique_ptr c) { + c->loadFromString("\n[beta_rpc_api]\n1\n"); + return c; + })}; + if (!BEAST_EXPECT(env.app().config().BETA_RPC_API == true)) + return; + + auto jrr = env.rpc( + "json", + "version", + "{\"api_version\": " + std::to_string(RPC::apiBetaVersion) + + "}")[jss::result]; + + if (!BEAST_EXPECT(jrr.isMember(jss::version))) + return; + if (!BEAST_EXPECT(jrr[jss::version].isMember(jss::first)) && + jrr[jss::version].isMember(jss::last)) + return; + BEAST_EXPECT( + jrr[jss::version][jss::first] == RPC::apiMinimumSupportedVersion); + BEAST_EXPECT(jrr[jss::version][jss::last] == RPC::apiBetaVersion); + } + public: void run() override @@ -212,6 +278,8 @@ public: testGetAPIVersionNumber(); testBatch(); testBatchFail(); + testConfig(); + testVersionRPCV2(); } };