#pragma once #include #include #include #include #include #include namespace xrpl { /** * API version numbers used in later API versions * * Requests with a version number in the range * [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, * 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 * version 1. * * Command line Requests use apiCommandLineVersion. */ namespace RPC { template constexpr static std::integral_constant kAPI_VERSION = {}; constexpr static auto kAPI_INVALID_VERSION = kAPI_VERSION<0>; constexpr static auto kAPI_MINIMUM_SUPPORTED_VERSION = kAPI_VERSION<1>; constexpr static auto kAPI_MAXIMUM_SUPPORTED_VERSION = kAPI_VERSION<2>; constexpr static auto kAPI_VERSION_IF_UNSPECIFIED = kAPI_VERSION<1>; constexpr static auto kAPI_COMMAND_LINE_VERSION = kAPI_VERSION<1>; // TODO Bump to 2 later constexpr static auto kAPI_BETA_VERSION = kAPI_VERSION<3>; constexpr static auto kAPI_MAXIMUM_VALID_VERSION = kAPI_BETA_VERSION; static_assert(kAPI_INVALID_VERSION < kAPI_MINIMUM_SUPPORTED_VERSION); static_assert( kAPI_VERSION_IF_UNSPECIFIED >= kAPI_MINIMUM_SUPPORTED_VERSION && kAPI_VERSION_IF_UNSPECIFIED <= kAPI_MAXIMUM_SUPPORTED_VERSION); static_assert( kAPI_COMMAND_LINE_VERSION >= kAPI_MINIMUM_SUPPORTED_VERSION && kAPI_COMMAND_LINE_VERSION <= kAPI_MAXIMUM_SUPPORTED_VERSION); static_assert(kAPI_MAXIMUM_SUPPORTED_VERSION >= kAPI_MINIMUM_SUPPORTED_VERSION); static_assert(kAPI_BETA_VERSION >= kAPI_MAXIMUM_SUPPORTED_VERSION); static_assert(kAPI_MAXIMUM_VALID_VERSION >= kAPI_MAXIMUM_SUPPORTED_VERSION); inline void setVersion(json::Value& parent, unsigned int apiVersion, bool betaEnabled) { XRPL_ASSERT(apiVersion != kAPI_INVALID_VERSION, "xrpl::RPC::setVersion : input is valid"); auto& retObj = parent[jss::version] = json::ValueType::Object; if (apiVersion == kAPI_VERSION_IF_UNSPECIFIED) { // API version numbers used in API version 1 static beast::SemanticVersion const kFIRST_VERSION{"1.0.0"}; static beast::SemanticVersion const kGOOD_VERSION{"1.0.0"}; static beast::SemanticVersion const kLAST_VERSION{"1.0.0"}; retObj[jss::first] = kFIRST_VERSION.print(); retObj[jss::good] = kGOOD_VERSION.print(); retObj[jss::last] = kLAST_VERSION.print(); } else { retObj[jss::first] = kAPI_MINIMUM_SUPPORTED_VERSION.value; retObj[jss::last] = betaEnabled ? kAPI_BETA_VERSION : kAPI_MAXIMUM_SUPPORTED_VERSION; } } /** * Retrieve the api version number from the json value * * Note that APIInvalidVersion will be returned if * 1) the version number field has a wrong format * 2) the version number retrieved is out of the supported range * 3) the version number is unspecified and * APIVersionIfUnspecified is out of the supported range * * @param jv a Json value that may or may not specify * the api version number * @param betaEnabled if the beta API version is enabled * @return the api version number */ inline unsigned int getAPIVersionNumber(json::Value const& jv, bool betaEnabled) { static json::Value const kMIN_VERSION(RPC::kAPI_MINIMUM_SUPPORTED_VERSION); json::Value const maxVersion( betaEnabled ? RPC::kAPI_BETA_VERSION : RPC::kAPI_MAXIMUM_SUPPORTED_VERSION); if (jv.isObject()) { if (jv.isMember(jss::api_version)) { auto const specifiedVersion = jv[jss::api_version]; if (!specifiedVersion.isInt() && !specifiedVersion.isUInt()) { return RPC::kAPI_INVALID_VERSION; } auto const specifiedVersionInt = specifiedVersion.asInt(); if (specifiedVersionInt < kMIN_VERSION || specifiedVersionInt > maxVersion) { return RPC::kAPI_INVALID_VERSION; } return specifiedVersionInt; } } return RPC::kAPI_VERSION_IF_UNSPECIFIED; } } // namespace RPC template void forApiVersions(Fn const& fn, Args&&... args) requires // (MaxVer >= MinVer) && // (MinVer >= RPC::kAPI_MINIMUM_SUPPORTED_VERSION) && // (RPC::kAPI_MAXIMUM_VALID_VERSION >= MaxVer) && requires { fn(std::integral_constant{}, std::forward(args)...); fn(std::integral_constant{}, std::forward(args)...); } { constexpr auto kSIZE = MaxVer + 1 - MinVer; [&](std::index_sequence) { // NOLINTBEGIN(bugprone-use-after-move) (((void)fn( std::integral_constant{}, std::forward(args)...)), ...); // NOLINTEND(bugprone-use-after-move) }(std::make_index_sequence{}); } template void forAllApiVersions(Fn const& fn, Args&&... args) requires requires { forApiVersions( fn, std::forward(args)...); } { forApiVersions( fn, std::forward(args)...); } } // namespace xrpl