Consolidate "Not Synced" error messages:

Work on a version 2 of the XRP Network API has begun. The new
API returns:

* `notSynced` in place of `noClosed`, `noCurrent`, and `noNetwork`;
* `invalidParams` in place of `lgrIdxInvalid`.

The new version 2 API cannot be selected yet, as it remains a work
in progress.

Fixes #3269
This commit is contained in:
Howard Hinnant
2020-05-27 17:44:20 -04:00
committed by Nik Bougalis
parent 0214d83aa5
commit 1067086f71
21 changed files with 169 additions and 47 deletions

View File

@@ -7,6 +7,11 @@ This document contains the release notes for `rippled`, the reference server imp
Have new ideas? Need help with setting up your node? Come visit us [here](https://github.com/ripple/rippled/issues/new/choose)
# Change Log
- Work on a version 2 of the XRP Network API has begun. The new API returns the code `notSynced` in place of `noClosed`, `noCurrent`, and `noNetwork`. And `invalidLgrRange` is returned in place of `lgrIdxInvalid`.
- The version 2 API can be specified by adding "api_version" : 2 to your json request. The default version remains 1 (if unspecified), except for the command line interface which always uses the latest verison.
# Releases
## Version 1.5.0

View File

@@ -1759,9 +1759,11 @@ ApplicationImp::setup()
getOPs(),
getLedgerMaster(),
c,
Role::ADMIN},
jvCommand,
RPC::ApiMaximumSupportedVersion};
Role::ADMIN,
{},
{},
RPC::ApiMaximumSupportedVersion},
jvCommand};
Json::Value jvResult;
RPC::doCommand(context, jvResult);

View File

@@ -142,7 +142,8 @@ GRPCServerImpl::CallData<Request, Response>::process(
usage,
role,
coro,
InfoSub::pointer()},
InfoSub::pointer(),
apiVersion},
request_};
// Make sure we can currently handle the rpc

View File

@@ -105,6 +105,8 @@ private:
template <class Request, class Response>
using Handler = std::function<std::pair<Response, grpc::Status>(
RPC::GRPCContext<Request>&)>;
// This implementation is currently limited to v1 of the API
static unsigned constexpr apiVersion = 1;
public:
explicit GRPCServerImpl(Application& app);

View File

@@ -314,7 +314,10 @@ private:
if (uLedgerMax != -1 && uLedgerMax < uLedgerMin)
{
return rpcError(rpcLGR_IDXS_INVALID);
// The command line always follows ApiMaximumSupportedVersion
if (RPC::ApiMaximumSupportedVersion == 1)
return rpcError(rpcLGR_IDXS_INVALID);
return rpcError(rpcNOT_SYNCED);
}
jvRequest[jss::ledger_index_min] = jvParams[1u].asInt();
@@ -384,7 +387,10 @@ private:
if (uLedgerMax != -1 && uLedgerMax < uLedgerMin)
{
return rpcError(rpcLGR_IDXS_INVALID);
// The command line always follows ApiMaximumSupportedVersion
if (RPC::ApiMaximumSupportedVersion == 1)
return rpcError(rpcLGR_IDXS_INVALID);
return rpcError(rpcNOT_SYNCED);
}
jvRequest[jss::ledger_index_min] = jvParams[1u].asInt();

View File

@@ -64,9 +64,9 @@ enum error_code_i {
rpcNO_CLOSED = 15,
rpcNO_CURRENT = 16,
rpcNO_NETWORK = 17,
rpcNOT_SYNCED = 18,
// Ledger state
// unused 18,
rpcACT_NOT_FOUND = 19,
// unused 20,
rpcLGR_NOT_FOUND = 21,

View File

@@ -90,8 +90,9 @@ constexpr static ErrorInfo unorderedErrorInfos[]{
{rpcNOT_SUPPORTED, "notSupported", "Operation not supported."},
{rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable."},
{rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable."},
{rpcNOT_SYNCED, "notSynced", "Not synced to the network."},
{rpcNO_EVENTS, "noEvents", "Current transport does not support events."},
{rpcNO_NETWORK, "noNetwork", "Not synced to Ripple network."},
{rpcNO_NETWORK, "noNetwork", "Not synced to the network."},
{rpcNO_PERMISSION,
"noPermission",
"You don't have permission for this command."},

View File

@@ -47,6 +47,7 @@ struct Context
Role role;
std::shared_ptr<JobQueue::Coro> coro{};
InfoSub::pointer infoSub{};
unsigned int apiVersion;
};
struct JsonContext : public Context
@@ -62,7 +63,6 @@ struct JsonContext : public Context
Json::Value params;
unsigned int apiVersion;
Headers headers{};
};

View File

@@ -214,7 +214,9 @@ getLedgerRange(
if (!bValidated)
{
// Don't have a validated ledger range.
return rpcLGR_IDXS_INVALID;
if (context.apiVersion == 1)
return rpcLGR_IDXS_INVALID;
return rpcNOT_SYNCED;
}
std::uint32_t uLedgerMin = uValidatedMin;
@@ -236,7 +238,11 @@ getLedgerRange(
uLedgerMax = ls.max;
}
if (uLedgerMax < uLedgerMin)
return rpcLGR_IDXS_INVALID;
{
if (context.apiVersion == 1)
return rpcLGR_IDXS_INVALID;
return rpcINVALID_LGR_RANGE;
}
}
else
{
@@ -330,6 +336,10 @@ populateProtoResponse(
{
status = {grpc::StatusCode::NOT_FOUND, error.message()};
}
else if (error.toErrorCode() == rpcNOT_SYNCED)
{
status = {grpc::StatusCode::FAILED_PRECONDITION, error.message()};
}
else
{
status = {grpc::StatusCode::INVALID_ARGUMENT, error.message()};

View File

@@ -105,7 +105,9 @@ doAccountTxOld(RPC::JsonContext& context)
if (!bValidated && (iLedgerMin == -1 || iLedgerMax == -1))
{
// Don't have a validated ledger range.
return rpcError(rpcLGR_IDXS_INVALID);
if (context.apiVersion == 1)
return rpcError(rpcLGR_IDXS_INVALID);
return rpcError(rpcNOT_SYNCED);
}
uLedgerMin = iLedgerMin == -1 ? uValidatedMin : iLedgerMin;
@@ -113,7 +115,9 @@ doAccountTxOld(RPC::JsonContext& context)
if (uLedgerMax < uLedgerMin)
{
return rpcError(rpcLGR_IDXS_INVALID);
if (context.apiVersion == 1)
return rpcError(rpcLGR_IDXS_INVALID);
return rpcError(rpcNOT_SYNCED);
}
}
else

View File

@@ -67,7 +67,11 @@ doLedgerRequest(RPC::JsonContext& context)
// We need a validated ledger to get the hash from the sequence
if (ledgerMaster.getValidatedLedgerAge() >
RPC::Tuning::maxValidatedLedgerAge)
return rpcError(rpcNO_CURRENT);
{
if (context.apiVersion == 1)
return rpcError(rpcNO_CURRENT);
return rpcError(rpcNOT_SYNCED);
}
ledgerIndex = jsonIndex.asInt();
auto ledger = ledgerMaster.getValidatedLedger();

View File

@@ -49,7 +49,9 @@ doRipplePathFind(RPC::JsonContext& context)
if (context.app.getLedgerMaster().getValidatedLedgerAge() >
RPC::Tuning::maxValidatedLedgerAge)
{
return rpcError(rpcNO_NETWORK);
if (context.apiVersion == 1)
return rpcError(rpcNO_NETWORK);
return rpcError(rpcNOT_SYNCED);
}
PathRequest::pointer request;

View File

@@ -83,7 +83,9 @@ conditionMet(Condition condition_required, T& context)
JLOG(context.j.info()) << "Insufficient network mode for RPC: "
<< context.netOps.strOperatingMode();
return rpcNO_NETWORK;
if (context.apiVersion == 1)
return rpcNO_NETWORK;
return rpcNOT_SYNCED;
}
if (context.app.getOPs().isAmendmentBlocked() &&
@@ -99,7 +101,9 @@ conditionMet(Condition condition_required, T& context)
if (context.ledgerMaster.getValidatedLedgerAge() >
Tuning::maxValidatedLedgerAge)
{
return rpcNO_CURRENT;
if (context.apiVersion == 1)
return rpcNO_CURRENT;
return rpcNOT_SYNCED;
}
auto const cID = context.ledgerMaster.getCurrentLedgerIndex();
@@ -110,14 +114,18 @@ conditionMet(Condition condition_required, T& context)
JLOG(context.j.debug())
<< "Current ledger ID(" << cID
<< ") is less than validated ledger ID(" << vID << ")";
return rpcNO_CURRENT;
if (context.apiVersion == 1)
return rpcNO_CURRENT;
return rpcNOT_SYNCED;
}
}
if ((condition_required & NEEDS_CLOSED_LEDGER) &&
!context.ledgerMaster.getClosedLedger())
{
return rpcNO_CLOSED;
if (context.apiVersion == 1)
return rpcNO_CLOSED;
return rpcNOT_SYNCED;
}
return rpcSUCCESS;

View File

@@ -65,9 +65,16 @@ namespace {
Failure:
{
"result" : {
// api_version == 1
"error" : "noNetwork",
"error_code" : 16,
"error_message" : "Not synced to Ripple network.",
"error_code" : 17,
"error_message" : "Not synced to the network.",
// api_version == 2
"error" : "notSynced",
"error_code" : 18,
"error_message" : "Not synced to the network.",
"request" : {
"command" : "ledger",
"ledger_index" : 10300865
@@ -95,9 +102,16 @@ namespace {
Failure:
{
// api_version == 1
"error" : "noNetwork",
"error_code" : 16,
"error_message" : "Not synced to Ripple network.",
"error_code" : 17,
"error_message" : "Not synced to the network.",
// api_version == 2
"error" : "notSynced",
"error_code" : 18,
"error_message" : "Not synced to the network.",
"request" : {
"command" : "ledger",
"ledger_index" : 10300865

View File

@@ -347,7 +347,9 @@ getLedger(T& ledger, uint32_t ledgerIndex, Context& context)
isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
{
ledger.reset();
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
if (context.apiVersion == 1)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
return {rpcNOT_SYNCED, "notSynced"};
}
return Status::OK;
@@ -358,13 +360,21 @@ Status
getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
{
if (isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
{
if (context.apiVersion == 1)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
return {rpcNOT_SYNCED, "notSynced"};
}
if (shortcut == LedgerShortcut::VALIDATED)
{
ledger = context.ledgerMaster.getValidatedLedger();
if (ledger == nullptr)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
{
if (context.apiVersion == 1)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
return {rpcNOT_SYNCED, "notSynced"};
}
assert(!ledger->open());
}
@@ -386,7 +396,11 @@ getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
}
if (ledger == nullptr)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
{
if (context.apiVersion == 1)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
return {rpcNOT_SYNCED, "notSynced"};
}
static auto const minSequenceGap = 10;
@@ -394,7 +408,9 @@ getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
context.ledgerMaster.getValidLedgerIndex())
{
ledger.reset();
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
if (context.apiVersion == 1)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
return {rpcNOT_SYNCED, "notSynced"};
}
}
return Status::OK;

View File

@@ -443,9 +443,9 @@ ServerHandlerImp::processSession(
is->getConsumer(),
role,
coro,
is},
is,
apiVersion},
jv,
apiVersion,
{is->user(), is->forwarded_for()}};
RPC::doCommand(context, jr[jss::result]);
@@ -829,9 +829,9 @@ ServerHandlerImp::processRequest(
usage,
role,
coro,
InfoSub::pointer()},
InfoSub::pointer(),
apiVersion},
params,
apiVersion,
{user, forwardedFor}};
Json::Value result;
RPC::doCommand(context, result);

View File

@@ -270,7 +270,8 @@ checkTxJsonFields(
bool const verify,
std::chrono::seconds validatedLedgerAge,
Config const& config,
LoadFeeTrack const& feeTrack)
LoadFeeTrack const& feeTrack,
unsigned apiVersion)
{
std::pair<Json::Value, AccountID> ret;
@@ -308,7 +309,10 @@ checkTxJsonFields(
if (verify && !config.standalone() &&
(validatedLedgerAge > Tuning::maxValidatedLedgerAge))
{
ret.first = rpcError(rpcNO_CURRENT);
if (apiVersion == 1)
ret.first = rpcError(rpcNO_CURRENT);
else
ret.first = rpcError(rpcNOT_SYNCED);
return ret;
}
@@ -384,7 +388,8 @@ transactionPreProcessImpl(
verify,
validatedLedgerAge,
app.config(),
app.getFeeTrack());
app.getFeeTrack(),
getAPIVersionNumber(params));
if (RPC::contains_error(txJsonResult))
return std::move(txJsonResult);
@@ -1068,7 +1073,8 @@ transactionSubmitMultiSigned(
true,
validatedLedgerAge,
app.config(),
app.getFeeTrack());
app.getFeeTrack(),
getAPIVersionNumber(jvRequest));
if (RPC::contains_error(txJsonResult))
return std::move(txJsonResult);

View File

@@ -223,9 +223,11 @@ public:
app.getOPs(),
app.getLedgerMaster(),
c,
Role::USER},
Role::USER,
{},
{},
RPC::APIVersionIfUnspecified},
{},
RPC::APIVersionIfUnspecified,
{}};
Json::Value params = Json::objectValue;
@@ -329,9 +331,11 @@ public:
app.getOPs(),
app.getLedgerMaster(),
c,
Role::USER},
Role::USER,
{},
{},
RPC::APIVersionIfUnspecified},
{},
RPC::APIVersionIfUnspecified,
{}};
Json::Value result;
gate g;

View File

@@ -20,6 +20,7 @@
#include <ripple/beast/unit_test.h>
#include <ripple/protocol/ErrorCodes.h>
#include <ripple/protocol/jss.h>
#include <ripple/rpc/impl/RPCHelpers.h>
#include <test/jtx.h>
#include <boost/container/flat_set.hpp>
@@ -175,7 +176,8 @@ 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)),
rpcLGR_IDXS_INVALID));
(RPC::ApiMaximumSupportedVersion == 1 ? rpcLGR_IDXS_INVALID
: rpcINVALID_LGR_RANGE)));
}
// Ledger index min only
@@ -190,7 +192,8 @@ 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)),
rpcLGR_IDXS_INVALID));
(RPC::ApiMaximumSupportedVersion == 1 ? rpcLGR_IDXS_INVALID
: rpcINVALID_LGR_RANGE)));
}
// Ledger index max only

View File

@@ -21,6 +21,7 @@
#include <ripple/beast/unit_test.h>
#include <ripple/protocol/ErrorCodes.h>
#include <ripple/protocol/jss.h>
#include <ripple/rpc/impl/RPCHelpers.h>
#include <test/jtx.h>
namespace ripple {
@@ -297,10 +298,19 @@ public:
// date check to trigger
env.timeKeeper().adjustCloseTime(weeks{3});
result = env.rpc("ledger_request", "1")[jss::result];
BEAST_EXPECT(result[jss::error] == "noCurrent");
BEAST_EXPECT(result[jss::status] == "error");
BEAST_EXPECT(
result[jss::error_message] == "Current ledger is unavailable.");
if (RPC::ApiMaximumSupportedVersion == 1)
{
BEAST_EXPECT(result[jss::error] == "noCurrent");
BEAST_EXPECT(
result[jss::error_message] == "Current ledger is unavailable.");
}
else
{
BEAST_EXPECT(result[jss::error] == "notSynced");
BEAST_EXPECT(
result[jss::error_message] == "Not synced to the network.");
}
}
void

View File

@@ -1437,7 +1437,8 @@ static RPCCallTestData const rpcCallTestArray[] = {
__LINE__,
{"account_tx", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "580", "579"},
RPCCallTestData::no_exception,
R"({
RPC::ApiMaximumSupportedVersion == 1 ?
R"({
"method" : "account_tx",
"params" : [
{
@@ -1446,6 +1447,17 @@ static RPCCallTestData const rpcCallTestArray[] = {
"error_message" : "Ledger indexes invalid."
}
]
})"
:
R"({
"method" : "account_tx",
"params" : [
{
"error" : "notSynced",
"error_code" : 55,
"error_message" : "Not synced to the network."
}
]
})",
},
{
@@ -5905,7 +5917,8 @@ static RPCCallTestData const rpcCallTestArray[] = {
__LINE__,
{"tx_account", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "580", "579"},
RPCCallTestData::no_exception,
R"({
RPC::ApiMaximumSupportedVersion == 1 ?
R"({
"method" : "tx_account",
"params" : [
{
@@ -5914,6 +5927,17 @@ static RPCCallTestData const rpcCallTestArray[] = {
"error_message" : "Ledger indexes invalid."
}
]
})"
:
R"({
"method" : "tx_account",
"params" : [
{
"error" : "notSynced",
"error_code" : 55,
"error_message" : "Not synced to the network."
}
]
})",
},
{