Improved human readable JSON-RPC error messages

This commit is contained in:
Vinnie Falco
2013-12-12 21:17:54 -05:00
parent ef7810bc95
commit 9d07ddeae1
22 changed files with 1682 additions and 839 deletions

View File

@@ -90,53 +90,56 @@ int LegacyPathFind::maxInProgress (2);
Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool bFailHard, Application::ScopedLockType& mlh)
{
if (getApp().getFeeTrack().isLoadedCluster() && (mRole != Config::ADMIN))
return rpcError(rpcTOO_BUSY);
Json::Value jvResult;
RippleAddress naSeed;
RippleAddress raSrcAddressID;
bool bOffline = params.isMember ("offline") && params["offline"].asBool ();
Json::Value jvResult;
WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("transactionSign: %s") % params);
if (!bOffline && !getConfig ().RUN_STANDALONE && (getApp().getLedgerMaster().getValidatedLedgerAge() > 120))
{
if (! params.isMember ("secret"))
return RPC::missing_field_error ("secret");
if (! params.isMember ("tx_json"))
return RPC::missing_field_error ("tx_json");
RippleAddress naSeed;
if (! naSeed.setSeedGeneric (params["secret"].asString ()))
return RPC::make_error (rpcBAD_SEED,
RPC::invalid_field_message ("secret"));
Json::Value tx_json (params ["tx_json"]);
if (! tx_json.isObject ())
return RPC::object_field_error ("tx_json");
if (! tx_json.isMember ("TransactionType"))
return RPC::missing_field_error ("tx_json.TransactionType");
std::string const sType = tx_json ["TransactionType"].asString ();
if (! tx_json.isMember ("Account"))
return RPC::make_error (rpcSRC_ACT_MISSING,
RPC::missing_field_message ("tx_json.Account"));
RippleAddress raSrcAddressID;
if (! raSrcAddressID.setAccountID (tx_json["Account"].asString ()))
return RPC::make_error (rpcSRC_ACT_MALFORMED,
RPC::invalid_field_message ("tx_json.Account"));
bool const bOffline (
params.isMember ("offline") && params["offline"].asBool ());
if (! tx_json.isMember ("Sequence") && bOffline)
return RPC::missing_field_error ("tx_json.Sequence");
// Check for current ledger
if (!bOffline && !getConfig ().RUN_STANDALONE &&
(getApp().getLedgerMaster().getValidatedLedgerAge() > 120))
return rpcError (rpcNO_CURRENT);
}
if (!params.isMember ("secret") || !params.isMember ("tx_json"))
{
return rpcError (rpcINVALID_PARAMS);
}
Json::Value txJSON = params["tx_json"];
if (!txJSON.isObject ())
{
return rpcError (rpcINVALID_PARAMS);
}
if (!naSeed.setSeedGeneric (params["secret"].asString ()))
{
return rpcError (rpcBAD_SEED);
}
if (!txJSON.isMember ("Account"))
{
return rpcError (rpcSRC_ACT_MISSING);
}
if (!raSrcAddressID.setAccountID (txJSON["Account"].asString ()))
{
return rpcError (rpcSRC_ACT_MALFORMED);
}
if (!txJSON.isMember ("TransactionType"))
{
return rpcError (rpcINVALID_PARAMS);
}
std::string sType = txJSON["TransactionType"].asString ();
// Check for load
if (getApp().getFeeTrack().isLoadedCluster() && (mRole != Config::ADMIN))
return rpcError(rpcTOO_BUSY);
Ledger::pointer lSnapshot = mNetOps->getCurrentLedger ();
AccountState::pointer asSrc = bOffline
@@ -153,40 +156,41 @@ Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool
return rpcError (rpcSRC_ACT_NOT_FOUND);
}
if (!txJSON.isMember ("Fee")
&& (
"AccountSet" == sType
|| "Payment" == sType
|| "OfferCreate" == sType
|| "OfferCancel" == sType
|| "TrustSet" == sType))
if (! tx_json.isMember ("Fee") && (
"AccountSet" == sType
|| "Payment" == sType
|| "OfferCreate" == sType
|| "OfferCancel" == sType
|| "TrustSet" == sType))
{
// VFALCO TODO This needs to be fixed
// feeReq = lSnapshot->scaleFeeLoad(,
txJSON["Fee"] = (int) getConfig ().FEE_DEFAULT;
tx_json["Fee"] = (int) getConfig ().FEE_DEFAULT;
}
if ("Payment" == sType)
{
RippleAddress dstAccountID;
if (!txJSON.isMember ("Destination"))
{
return rpcError (rpcDST_ACT_MISSING);
}
if (! tx_json.isMember ("Amount"))
return RPC::missing_field_error ("tx_json.Amount");
if (!dstAccountID.setAccountID (txJSON["Destination"].asString ()))
{
return rpcError (rpcDST_ACT_MALFORMED);
}
STAmount amount;
if (txJSON.isMember ("Paths") && params.isMember ("build_path"))
{
// Asking to build a path when providing one is an error.
return rpcError (rpcINVALID_PARAMS);
}
if (! amount.bSetJson (tx_json ["Amount"]))
return RPC::invalid_field_error ("tx_json.Amount");
if (!txJSON.isMember ("Paths") && txJSON.isMember ("Amount") && params.isMember ("build_path"))
if (!tx_json.isMember ("Destination"))
return RPC::missing_field_error ("tx_json.Destination");
if (!dstAccountID.setAccountID (tx_json["Destination"].asString ()))
return RPC::invalid_field_error ("tx_json.Destination");
if (tx_json.isMember ("Paths") && params.isMember ("build_path"))
return RPC::make_error (rpcINVALID_PARAMS,
"Cannot specify both 'tx_json.Paths' and 'tx_json.build_path'");
if (!tx_json.isMember ("Paths") && tx_json.isMember ("Amount") && params.isMember ("build_path"))
{
// Need a ripple path.
STPathSet spsPaths;
@@ -194,29 +198,22 @@ Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool
uint160 uSrcIssuerID;
STAmount saSendMax;
STAmount saSend;
if (!txJSON.isMember ("Amount") // Amount required.
|| !saSend.bSetJson (txJSON["Amount"])) // Must be valid.
return rpcError (rpcDST_AMT_MALFORMED);
if (txJSON.isMember ("SendMax"))
if (tx_json.isMember ("SendMax"))
{
if (!saSendMax.bSetJson (txJSON["SendMax"]))
return rpcError (rpcINVALID_PARAMS);
if (!saSendMax.bSetJson (tx_json ["SendMax"]))
return RPC::invalid_field_error ("tx_json.SendMax");
}
else
{
// If no SendMax, default to Amount with sender as issuer.
saSendMax = saSend;
saSendMax = amount;
saSendMax.setIssuer (raSrcAddressID.getAccountID ());
}
if (saSendMax.isNative () && saSend.isNative ())
{
// Asking to build a path for XRP to XRP is an error.
return rpcError (rpcINVALID_PARAMS);
}
if (saSendMax.isNative () && amount.isNative ())
return RPC::make_error (rpcINVALID_PARAMS,
"Cannot build XRP to XRP paths.");
{
LegacyPathFind lpf (mRole == Config::ADMIN);
@@ -226,7 +223,7 @@ Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool
bool bValid;
RippleLineCache::pointer cache = boost::make_shared<RippleLineCache> (lSnapshot);
Pathfinder pf (cache, raSrcAddressID, dstAccountID,
saSendMax.getCurrency (), saSendMax.getIssuer (), saSend, bValid);
saSendMax.getCurrency (), saSendMax.getIssuer (), amount, bValid);
STPath extraPath;
if (!bValid || !pf.findPaths (getConfig ().PATH_SEARCH_OLD, 4, spsPaths, extraPath))
@@ -242,23 +239,23 @@ Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool
if (!spsPaths.isEmpty ())
{
txJSON["Paths"] = spsPaths.getJson (0);
tx_json["Paths"] = spsPaths.getJson (0);
}
}
}
}
if (!txJSON.isMember ("Fee")
if (!tx_json.isMember ("Fee")
&& (
"AccountSet" == txJSON["TransactionType"].asString ()
|| "OfferCreate" == txJSON["TransactionType"].asString ()
|| "OfferCancel" == txJSON["TransactionType"].asString ()
|| "TrustSet" == txJSON["TransactionType"].asString ()))
"AccountSet" == tx_json["TransactionType"].asString ()
|| "OfferCreate" == tx_json["TransactionType"].asString ()
|| "OfferCancel" == tx_json["TransactionType"].asString ()
|| "TrustSet" == tx_json["TransactionType"].asString ()))
{
txJSON["Fee"] = (int) getConfig ().FEE_DEFAULT;
tx_json["Fee"] = (int) getConfig ().FEE_DEFAULT;
}
if (!txJSON.isMember ("Sequence"))
if (!tx_json.isMember ("Sequence"))
{
if (bOffline)
{
@@ -267,11 +264,11 @@ Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool
}
else
{
txJSON["Sequence"] = asSrc->getSeq ();
tx_json["Sequence"] = asSrc->getSeq ();
}
}
if (!txJSON.isMember ("Flags")) txJSON["Flags"] = 0;
if (!tx_json.isMember ("Flags")) tx_json["Flags"] = 0;
if (!bOffline)
{
@@ -334,16 +331,21 @@ Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool
std::unique_ptr<STObject> sopTrans;
try
{
sopTrans = STObject::parseJson (txJSON);
}
catch (std::exception& e)
{
jvResult["error"] = "malformedTransaction";
jvResult["error_exception"] = e.what ();
return jvResult;
STParsedJSON parsed ("tx_json", tx_json);
if (parsed.object.get() != nullptr)
{
// VFALCO NOTE No idea why this doesn't compile.
//sopTrans = parsed.object;
sopTrans.reset (parsed.object.release());
}
else
{
jvResult ["error"] = parsed.error ["error"];
jvResult ["error_code"] = parsed.error ["error_code"];
jvResult ["error_message"] = parsed.error ["error_message"];
return jvResult;
}
}
sopTrans->setFieldVL (sfSigningPubKey, naAccountPublic.getAccountPublic ());
@@ -634,24 +636,29 @@ Json::Value RPCHandler::accountFromString (Ledger::ref lrLedger, RippleAddress&
Json::Value RPCHandler::doAccountCurrencies (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder)
{
masterLockHolder.unlock ();
Ledger::pointer lpLedger;
Json::Value jvResult = lookupLedger (params, lpLedger);
// Get the current ledger
Ledger::pointer lpLedger;
Json::Value jvResult (lookupLedger (params, lpLedger));
if (!lpLedger)
return jvResult;
if (!params.isMember ("account") && !params.isMember ("ident"))
return rpcError (rpcINVALID_PARAMS);
if (! params.isMember ("account") && ! params.isMember ("ident"))
return RPC::missing_field_error ("account");
std::string strIdent = params.isMember ("account") ? params["account"].asString () : params["ident"].asString ();
bool bIndex;
int iIndex = params.isMember ("account_index") ? params["account_index"].asUInt () : 0;
bool bStrict = params.isMember ("strict") && params["strict"].asBool ();
RippleAddress naAccount;
std::string const strIdent (params.isMember ("account")
? params["account"].asString ()
: params["ident"].asString ());
int const iIndex (params.isMember ("account_index")
? params["account_index"].asUInt ()
: 0);
bool const bStrict (params.isMember ("strict") && params["strict"].asBool ());
// Get info on account.
Json::Value jvAccepted = accountFromString (lpLedger, naAccount, bIndex, strIdent, iIndex, bStrict);
bool bIndex; // out param
RippleAddress naAccount; // out param
Json::Value jvAccepted (accountFromString (
lpLedger, naAccount, bIndex, strIdent, iIndex, bStrict));
if (!jvAccepted.empty ())
return jvAccepted;
@@ -707,7 +714,7 @@ Json::Value RPCHandler::doAccountInfo (Json::Value params, Resource::Charge& loa
return jvResult;
if (!params.isMember ("account") && !params.isMember ("ident"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("account");
std::string strIdent = params.isMember ("account") ? params["account"].asString () : params["ident"].asString ();
bool bIndex;
@@ -759,7 +766,7 @@ Json::Value RPCHandler::doConnect (Json::Value params, Resource::Charge& loadTyp
return "cannot connect in standalone mode";
if (!params.isMember ("ip"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("ip");
std::string strIp = params["ip"].asString ();
int iPort = params.isMember ("port") ? params["port"].asInt () : -1;
@@ -777,7 +784,7 @@ Json::Value RPCHandler::doConnect (Json::Value params, Resource::Charge& loadTyp
Json::Value RPCHandler::doDataDelete (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder)
{
if (!params.isMember ("key"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("key");
std::string strKey = params["key"].asString ();
@@ -803,7 +810,7 @@ Json::Value RPCHandler::doDataDelete (Json::Value params, Resource::Charge& load
Json::Value RPCHandler::doDataFetch (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder)
{
if (!params.isMember ("key"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("key");
std::string strKey = params["key"].asString ();
std::string strValue;
@@ -827,8 +834,9 @@ Json::Value RPCHandler::doDataFetch (Json::Value params, Resource::Charge& loadT
Json::Value RPCHandler::doDataStore (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder)
{
if (!params.isMember ("key")
|| !params.isMember ("value"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("key");
if (!params.isMember ("value")
return RPC::missing_field_error ("value");
std::string strKey = params["key"].asString ();
std::string strValue = params["value"].asString ();
@@ -888,7 +896,7 @@ Json::Value RPCHandler::doNicknameInfo (Json::Value params)
Json::Value RPCHandler::doOwnerInfo (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder)
{
if (!params.isMember ("account") && !params.isMember ("ident"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("account");
std::string strIdent = params.isMember ("account") ? params["account"].asString () : params["ident"].asString ();
bool bIndex;
@@ -1051,12 +1059,12 @@ Json::Value RPCHandler::doProofCreate (Json::Value params, Resource::Charge& loa
if (params.isMember ("difficulty"))
{
if (!params["difficulty"].isIntegral ())
return rpcError (rpcINVALID_PARAMS);
return RPC::invalid_field_error ("difficulty");
int iDifficulty = params["difficulty"].asInt ();
int const iDifficulty (params["difficulty"].asInt ());
if (iDifficulty < 0 || iDifficulty > ProofOfWorkFactory::kMaxDifficulty)
return rpcError (rpcINVALID_PARAMS);
return RPC::invalid_field_error ("difficulty");
pgGen->setDifficulty (iDifficulty);
}
@@ -1088,12 +1096,12 @@ Json::Value RPCHandler::doProofSolve (Json::Value params, Resource::Charge& load
Json::Value jvResult;
if (!params.isMember ("token"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("token");
std::string strToken = params["token"].asString ();
if (!ProofOfWork::validateToken (strToken))
return rpcError (rpcINVALID_PARAMS);
return RPC::invalid_field_error ("token");
ProofOfWork powProof (strToken);
uint256 uSolution = powProof.solve ();
@@ -1119,10 +1127,10 @@ Json::Value RPCHandler::doProofVerify (Json::Value params, Resource::Charge& loa
Json::Value jvResult;
if (!params.isMember ("token"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("token");
if (!params.isMember ("solution"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("solution");
std::string strToken = params["token"].asString ();
uint256 uSolution (params["solution"].asString ());
@@ -1137,12 +1145,12 @@ Json::Value RPCHandler::doProofVerify (Json::Value params, Resource::Charge& loa
if (params.isMember ("difficulty"))
{
if (!params["difficulty"].isIntegral ())
return rpcError (rpcINVALID_PARAMS);
return RPC::invalid_field_error ("difficulty");
int iDifficulty = params["difficulty"].asInt ();
if (iDifficulty < 0 || iDifficulty > ProofOfWorkFactory::kMaxDifficulty)
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("difficulty");
pgGen->setDifficulty (iDifficulty);
}
@@ -1192,7 +1200,7 @@ Json::Value RPCHandler::doAccountLines (Json::Value params, Resource::Charge& lo
return jvResult;
if (!params.isMember ("account"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("account");
std::string strIdent = params["account"].asString ();
bool bIndex = params.isMember ("account_index");
@@ -1303,7 +1311,7 @@ Json::Value RPCHandler::doAccountOffers (Json::Value params, Resource::Charge& l
return jvResult;
if (!params.isMember ("account"))
return rpcError (rpcINVALID_PARAMS);
return RPC::missing_field_error ("account");
std::string strIdent = params["account"].asString ();
bool bIndex = params.isMember ("account_index");
@@ -1334,6 +1342,33 @@ Json::Value RPCHandler::doAccountOffers (Json::Value params, Resource::Charge& l
return jvResult;
}
template <class UnsignedInteger>
inline bool is_xrp (UnsignedInteger const& value)
{
return value.isZero();
}
template <class UnsignedInteger>
inline bool is_not_xrp (UnsignedInteger const& value)
{
return ! is_xrp (value);
}
inline uint160 const& xrp_issuer ()
{
return ACCOUNT_XRP;
}
inline uint160 const& xrp_currency ()
{
return CURRENCY_XRP;
}
inline uint160 const& neutral_issuer ()
{
return ACCOUNT_ONE;
}
// {
// "ledger_hash" : ledger, // Optional.
// "ledger_index" : ledger_index, // Optional.
@@ -1348,94 +1383,164 @@ Json::Value RPCHandler::doBookOffers (Json::Value params, Resource::Charge& load
{
masterLockHolder.unlock ();
// VFALCO TODO Here is a terrible place for this kind of business
// logic. It needs to be moved elsewhere and documented,
// and encapsulated into a function.
if (getApp().getJobQueue ().getJobCountGE (jtCLIENT) > 200)
{
return rpcError (rpcTOO_BUSY);
}
Ledger::pointer lpLedger;
Json::Value jvResult = lookupLedger (params, lpLedger);
Ledger::pointer lpLedger;
Json::Value jvResult (lookupLedger (params, lpLedger));
if (!lpLedger)
return jvResult;
if (!params.isMember ("taker_pays") || !params.isMember ("taker_gets") || !params["taker_pays"].isObject () || !params["taker_gets"].isObject ())
return rpcError (rpcINVALID_PARAMS);
if (!params.isMember ("taker_pays"))
return RPC::missing_field_error ("taker_pays");
uint160 uTakerPaysCurrencyID;
uint160 uTakerPaysIssuerID;
const Json::Value& jvTakerPays = params["taker_pays"];
if (!params.isMember ("taker_gets"))
return RPC::missing_field_error ("taker_gets");
// Parse mandatory currency.
if (!jvTakerPays.isMember ("currency")
|| !STAmount::currencyFromString (uTakerPaysCurrencyID, jvTakerPays["currency"].asString ()))
if (!params["taker_pays"].isObject ())
return RPC::object_field_error ("taker_pays");
if (!params["taker_gets"].isObject ())
return RPC::object_field_error ("taker_gets");
Json::Value const& taker_pays (params["taker_pays"]);
if (!taker_pays.isMember ("currency"))
return RPC::missing_field_error ("taker_pays.currency");
if (! taker_pays ["currency"].isString ())
return RPC::expected_field_error ("taker_pays.currency", "string");
Json::Value const& taker_gets = params["taker_gets"];
if (! taker_gets.isMember ("currency"))
return RPC::missing_field_error ("taker_gets.currency");
if (! taker_gets ["currency"].isString ())
return RPC::expected_field_error ("taker_gets.currency", "string");
uint160 pay_currency;
if (! STAmount::currencyFromString (
pay_currency, taker_pays ["currency"].asString ()))
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
return rpcError (rpcSRC_CUR_MALFORMED);
return RPC::make_error (rpcSRC_CUR_MALFORMED,
"Invalid field 'taker_pays.currency', bad currency.");
}
// Parse optional issuer.
else if (((jvTakerPays.isMember ("issuer"))
&& (!jvTakerPays["issuer"].isString ()
|| !STAmount::issuerFromString (uTakerPaysIssuerID, jvTakerPays["issuer"].asString ())))
// Don't allow illegal issuers.
|| (!uTakerPaysCurrencyID != !uTakerPaysIssuerID)
|| ACCOUNT_ONE == uTakerPaysIssuerID)
uint160 get_currency;
if (! STAmount::currencyFromString (
get_currency, taker_gets ["currency"].asString ()))
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays issuer.";
return rpcError (rpcSRC_ISR_MALFORMED);
WriteLog (lsINFO, RPCHandler) << "Bad taker_gets currency.";
return RPC::make_error (rpcDST_AMT_MALFORMED,
"Invalid field 'taker_gets.currency', bad currency.");
}
uint160 uTakerGetsCurrencyID;
uint160 uTakerGetsIssuerID;
const Json::Value& jvTakerGets = params["taker_gets"];
uint160 pay_issuer;
// Parse mandatory currency.
if (!jvTakerGets.isMember ("currency")
|| !STAmount::currencyFromString (uTakerGetsCurrencyID, jvTakerGets["currency"].asString ()))
if (taker_pays.isMember ("issuer"))
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
if (! taker_pays ["issuer"].isString())
return RPC::expected_field_error ("taker_pays.issuer", "string");
return rpcError (rpcSRC_CUR_MALFORMED);
if (! STAmount::issuerFromString (
pay_issuer, taker_pays ["issuer"].asString ()))
return RPC::make_error (rpcSRC_ISR_MALFORMED,
"Invalid field 'taker_pays.issuer', bad issuer.");
if (pay_issuer == neutral_issuer ())
return RPC::make_error (rpcSRC_ISR_MALFORMED,
"Invalid field 'taker_pays.issuer', bad issuer account one.");
}
// Parse optional issuer.
else if (((jvTakerGets.isMember ("issuer"))
&& (!jvTakerGets["issuer"].isString ()
|| !STAmount::issuerFromString (uTakerGetsIssuerID, jvTakerGets["issuer"].asString ())))
// Don't allow illegal issuers.
|| (!uTakerGetsCurrencyID != !uTakerGetsIssuerID)
|| ACCOUNT_ONE == uTakerGetsIssuerID)
else
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_gets issuer.";
return rpcError (rpcDST_ISR_MALFORMED);
pay_issuer = xrp_issuer ();
}
if (uTakerPaysCurrencyID == uTakerGetsCurrencyID
&& uTakerPaysIssuerID == uTakerGetsIssuerID)
if (is_xrp (pay_currency) && ! is_xrp (pay_issuer))
return RPC::make_error (rpcSRC_ISR_MALFORMED,
"Unneeded field 'taker_pays.issuer' for XRP currency specification.");
if (is_not_xrp (pay_currency) && is_xrp (pay_issuer))
return RPC::make_error (rpcSRC_ISR_MALFORMED,
"Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
uint160 get_issuer;
if (taker_gets.isMember ("issuer"))
{
WriteLog (lsINFO, RPCHandler) << "taker_gets same as taker_pays.";
if (! taker_gets ["issuer"].isString())
return RPC::expected_field_error ("taker_gets.issuer", "string");
return rpcError (rpcBAD_MARKET);
if (! STAmount::issuerFromString (
get_issuer, taker_gets ["issuer"].asString ()))
return RPC::make_error (rpcDST_ISR_MALFORMED,
"Invalid field 'taker_gets.issuer', bad issuer.");
if (get_issuer == neutral_issuer ())
return RPC::make_error (rpcDST_ISR_MALFORMED,
"Invalid field 'taker_gets.issuer', bad issuer account one.");
}
else
{
get_issuer = xrp_issuer ();
}
RippleAddress raTakerID;
if (!params.isMember ("taker"))
if (is_xrp (get_currency) && ! is_xrp (get_issuer))
return RPC::make_error (rpcDST_ISR_MALFORMED,
"Unneeded field 'taker_gets.issuer' for XRP currency specification.");
if (is_not_xrp (get_currency) && is_xrp (get_issuer))
return RPC::make_error (rpcDST_ISR_MALFORMED,
"Invalid field 'taker_gets.issuer', expected non-XRP issuer.");
RippleAddress raTakerID;
if (params.isMember ("taker"))
{
if (! params ["taker"].isString ())
return RPC::expected_field_error ("taker", "string");
if (! raTakerID.setAccountID (params ["taker"].asString ()))
return RPC::invalid_field_error ("taker");
}
else
{
raTakerID.setAccountID (ACCOUNT_ONE);
}
else if (!raTakerID.setAccountID (params["taker"].asString ()))
if (pay_currency == get_currency && pay_issuer == get_issuer)
{
return rpcError (rpcBAD_ISSUER);
WriteLog (lsINFO, RPCHandler) << "taker_gets same as taker_pays.";
return RPC::make_error (rpcBAD_MARKET);
}
const bool bProof = params.isMember ("proof");
const unsigned int iLimit = params.isMember ("limit") ? params["limit"].asUInt () : 0;
const Json::Value jvMarker = params.isMember ("marker") ? params["marker"] : Json::Value (Json::nullValue);
if (params.isMember ("limit") && ! params ["limit"].isUInt())
return RPC::expected_field_error (
"taker_pays.currency", "unsigned integer");
unsigned int const iLimit (params.isMember ("limit")
? params ["limit"].asUInt ()
: 0);
bool const bProof (params.isMember ("proof"));
Json::Value const jvMarker (params.isMember ("marker")
? params["marker"]
: Json::Value (Json::nullValue));
mNetOps->getBookPage (lpLedger, pay_currency, pay_issuer,
get_currency, get_issuer, raTakerID.getAccountID (),
bProof, iLimit, jvMarker, jvResult);
mNetOps->getBookPage (lpLedger, uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID, raTakerID.getAccountID (), bProof, iLimit, jvMarker, jvResult);
loadType = Resource::feeMediumBurdenRPC;
return jvResult;
@@ -3573,33 +3678,35 @@ Json::Value RPCHandler::doSubscribe (Json::Value params, Resource::Charge& loadT
|| !jvSubRequest["taker_gets"].isObject ())
return rpcError (rpcINVALID_PARAMS);
RippleCurrency uTakerPaysCurrencyID;
RippleIssuer uTakerPaysIssuerID;
RippleCurrency uTakerGetsCurrencyID;
RippleIssuer uTakerGetsIssuerID;
// VFALCO TODO Use RippleAsset here
RippleCurrency pay_currency;
RippleIssuer pay_issuer;
RippleCurrency get_currency;
RippleIssuer get_issuer;
bool bBoth = (jvSubRequest.isMember ("both") && jvSubRequest["both"].asBool ())
|| (jvSubRequest.isMember ("both_sides") && jvSubRequest["both_sides"].asBool ()); // DEPRECATED
bool bSnapshot = (jvSubRequest.isMember ("snapshot") && jvSubRequest["snapshot"].asBool ())
|| (jvSubRequest.isMember ("state_now") && jvSubRequest["state_now"].asBool ()); // DEPRECATED
Json::Value jvTakerPays = jvSubRequest["taker_pays"];
Json::Value jvTakerGets = jvSubRequest["taker_gets"];
Json::Value taker_pays = jvSubRequest["taker_pays"];
Json::Value taker_gets = jvSubRequest["taker_gets"];
// Parse mandatory currency.
if (!jvTakerPays.isMember ("currency")
|| !STAmount::currencyFromString (uTakerPaysCurrencyID, jvTakerPays["currency"].asString ()))
if (!taker_pays.isMember ("currency")
|| !STAmount::currencyFromString (pay_currency, taker_pays["currency"].asString ()))
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
return rpcError (rpcSRC_CUR_MALFORMED);
}
// Parse optional issuer.
else if (((jvTakerPays.isMember ("issuer"))
&& (!jvTakerPays["issuer"].isString ()
|| !STAmount::issuerFromString (uTakerPaysIssuerID, jvTakerPays["issuer"].asString ())))
else if (((taker_pays.isMember ("issuer"))
&& (!taker_pays["issuer"].isString ()
|| !STAmount::issuerFromString (pay_issuer, taker_pays["issuer"].asString ())))
// Don't allow illegal issuers.
|| (!uTakerPaysCurrencyID != !uTakerPaysIssuerID)
|| ACCOUNT_ONE == uTakerPaysIssuerID)
|| (!pay_currency != !pay_issuer)
|| ACCOUNT_ONE == pay_issuer)
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays issuer.";
@@ -3607,28 +3714,28 @@ Json::Value RPCHandler::doSubscribe (Json::Value params, Resource::Charge& loadT
}
// Parse mandatory currency.
if (!jvTakerGets.isMember ("currency")
|| !STAmount::currencyFromString (uTakerGetsCurrencyID, jvTakerGets["currency"].asString ()))
if (!taker_gets.isMember ("currency")
|| !STAmount::currencyFromString (get_currency, taker_gets["currency"].asString ()))
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
return rpcError (rpcSRC_CUR_MALFORMED);
}
// Parse optional issuer.
else if (((jvTakerGets.isMember ("issuer"))
&& (!jvTakerGets["issuer"].isString ()
|| !STAmount::issuerFromString (uTakerGetsIssuerID, jvTakerGets["issuer"].asString ())))
else if (((taker_gets.isMember ("issuer"))
&& (!taker_gets["issuer"].isString ()
|| !STAmount::issuerFromString (get_issuer, taker_gets["issuer"].asString ())))
// Don't allow illegal issuers.
|| (!uTakerGetsCurrencyID != !uTakerGetsIssuerID)
|| ACCOUNT_ONE == uTakerGetsIssuerID)
|| (!get_currency != !get_issuer)
|| ACCOUNT_ONE == get_issuer)
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_gets issuer.";
return rpcError (rpcDST_ISR_MALFORMED);
}
if (uTakerPaysCurrencyID == uTakerGetsCurrencyID
&& uTakerPaysIssuerID == uTakerGetsIssuerID)
if (pay_currency == get_currency
&& pay_issuer == get_issuer)
{
WriteLog (lsINFO, RPCHandler) << "taker_gets same as taker_pays.";
@@ -3646,17 +3753,17 @@ Json::Value RPCHandler::doSubscribe (Json::Value params, Resource::Charge& loadT
return rpcError (rpcBAD_ISSUER);
}
if (!Ledger::isValidBook (uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID))
if (!Ledger::isValidBook (pay_currency, pay_issuer, get_currency, get_issuer))
{
WriteLog (lsWARNING, RPCHandler) << "Bad market: " <<
uTakerPaysCurrencyID << ":" << uTakerPaysIssuerID << " -> " <<
uTakerGetsCurrencyID << ":" << uTakerGetsIssuerID;
pay_currency << ":" << pay_issuer << " -> " <<
get_currency << ":" << get_issuer;
return rpcError (rpcBAD_MARKET);
}
mNetOps->subBook (ispSub, uTakerPaysCurrencyID, uTakerGetsCurrencyID, uTakerPaysIssuerID, uTakerGetsIssuerID);
mNetOps->subBook (ispSub, pay_currency, get_currency, pay_issuer, get_issuer);
if (bBoth) mNetOps->subBook (ispSub, uTakerGetsCurrencyID, uTakerPaysCurrencyID, uTakerGetsIssuerID, uTakerPaysIssuerID);
if (bBoth) mNetOps->subBook (ispSub, get_currency, pay_currency, get_issuer, pay_issuer);
if (bSnapshot)
{
@@ -3673,17 +3780,17 @@ Json::Value RPCHandler::doSubscribe (Json::Value params, Resource::Charge& loadT
Json::Value jvBids (Json::objectValue);
Json::Value jvAsks (Json::objectValue);
mNetOps->getBookPage (lpLedger, uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID, raTakerID.getAccountID (), false, 0, jvMarker, jvBids);
mNetOps->getBookPage (lpLedger, pay_currency, pay_issuer, get_currency, get_issuer, raTakerID.getAccountID (), false, 0, jvMarker, jvBids);
if (jvBids.isMember ("offers")) jvResult["bids"] = jvBids["offers"];
mNetOps->getBookPage (lpLedger, uTakerGetsCurrencyID, uTakerGetsIssuerID, uTakerPaysCurrencyID, uTakerPaysIssuerID, raTakerID.getAccountID (), false, 0, jvMarker, jvAsks);
mNetOps->getBookPage (lpLedger, get_currency, get_issuer, pay_currency, pay_issuer, raTakerID.getAccountID (), false, 0, jvMarker, jvAsks);
if (jvAsks.isMember ("offers")) jvResult["asks"] = jvAsks["offers"];
}
else
{
mNetOps->getBookPage (lpLedger, uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID, raTakerID.getAccountID (), false, 0, jvMarker, jvResult);
mNetOps->getBookPage (lpLedger, pay_currency, pay_issuer, get_currency, get_issuer, raTakerID.getAccountID (), false, 0, jvMarker, jvResult);
}
}
}
@@ -3811,31 +3918,31 @@ Json::Value RPCHandler::doUnsubscribe (Json::Value params, Resource::Charge& loa
|| !jvSubRequest["taker_gets"].isObject ())
return rpcError (rpcINVALID_PARAMS);
uint160 uTakerPaysCurrencyID;
uint160 uTakerPaysIssuerID;
uint160 uTakerGetsCurrencyID;
uint160 uTakerGetsIssuerID;
uint160 pay_currency;
uint160 pay_issuer;
uint160 get_currency;
uint160 get_issuer;
bool bBoth = (jvSubRequest.isMember ("both") && jvSubRequest["both"].asBool ())
|| (jvSubRequest.isMember ("both_sides") && jvSubRequest["both_sides"].asBool ()); // DEPRECATED
Json::Value jvTakerPays = jvSubRequest["taker_pays"];
Json::Value jvTakerGets = jvSubRequest["taker_gets"];
Json::Value taker_pays = jvSubRequest["taker_pays"];
Json::Value taker_gets = jvSubRequest["taker_gets"];
// Parse mandatory currency.
if (!jvTakerPays.isMember ("currency")
|| !STAmount::currencyFromString (uTakerPaysCurrencyID, jvTakerPays["currency"].asString ()))
if (!taker_pays.isMember ("currency")
|| !STAmount::currencyFromString (pay_currency, taker_pays["currency"].asString ()))
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
return rpcError (rpcSRC_CUR_MALFORMED);
}
// Parse optional issuer.
else if (((jvTakerPays.isMember ("issuer"))
&& (!jvTakerPays["issuer"].isString ()
|| !STAmount::issuerFromString (uTakerPaysIssuerID, jvTakerPays["issuer"].asString ())))
else if (((taker_pays.isMember ("issuer"))
&& (!taker_pays["issuer"].isString ()
|| !STAmount::issuerFromString (pay_issuer, taker_pays["issuer"].asString ())))
// Don't allow illegal issuers.
|| (!uTakerPaysCurrencyID != !uTakerPaysIssuerID)
|| ACCOUNT_ONE == uTakerPaysIssuerID)
|| (!pay_currency != !pay_issuer)
|| ACCOUNT_ONE == pay_issuer)
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays issuer.";
@@ -3843,37 +3950,37 @@ Json::Value RPCHandler::doUnsubscribe (Json::Value params, Resource::Charge& loa
}
// Parse mandatory currency.
if (!jvTakerGets.isMember ("currency")
|| !STAmount::currencyFromString (uTakerGetsCurrencyID, jvTakerGets["currency"].asString ()))
if (!taker_gets.isMember ("currency")
|| !STAmount::currencyFromString (get_currency, taker_gets["currency"].asString ()))
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
return rpcError (rpcSRC_CUR_MALFORMED);
}
// Parse optional issuer.
else if (((jvTakerGets.isMember ("issuer"))
&& (!jvTakerGets["issuer"].isString ()
|| !STAmount::issuerFromString (uTakerGetsIssuerID, jvTakerGets["issuer"].asString ())))
else if (((taker_gets.isMember ("issuer"))
&& (!taker_gets["issuer"].isString ()
|| !STAmount::issuerFromString (get_issuer, taker_gets["issuer"].asString ())))
// Don't allow illegal issuers.
|| (!uTakerGetsCurrencyID != !uTakerGetsIssuerID)
|| ACCOUNT_ONE == uTakerGetsIssuerID)
|| (!get_currency != !get_issuer)
|| ACCOUNT_ONE == get_issuer)
{
WriteLog (lsINFO, RPCHandler) << "Bad taker_gets issuer.";
return rpcError (rpcDST_ISR_MALFORMED);
}
if (uTakerPaysCurrencyID == uTakerGetsCurrencyID
&& uTakerPaysIssuerID == uTakerGetsIssuerID)
if (pay_currency == get_currency
&& pay_issuer == get_issuer)
{
WriteLog (lsINFO, RPCHandler) << "taker_gets same as taker_pays.";
return rpcError (rpcBAD_MARKET);
}
mNetOps->unsubBook (ispSub->getSeq (), uTakerPaysCurrencyID, uTakerGetsCurrencyID, uTakerPaysIssuerID, uTakerGetsIssuerID);
mNetOps->unsubBook (ispSub->getSeq (), pay_currency, get_currency, pay_issuer, get_issuer);
if (bBoth) mNetOps->unsubBook (ispSub->getSeq (), uTakerGetsCurrencyID, uTakerPaysCurrencyID, uTakerGetsIssuerID, uTakerPaysIssuerID);
if (bBoth) mNetOps->unsubBook (ispSub->getSeq (), get_currency, pay_currency, get_issuer, pay_issuer);
}
}
@@ -3889,12 +3996,12 @@ Json::Value RPCHandler::doRpcCommand (const std::string& strMethod, Json::Value
WriteLog (lsTRACE, RPCHandler) << "doRpcCommand:" << strMethod << ":" << jvParams;
if (!jvParams.isArray () || jvParams.size () > 1)
return rpcError (rpcINVALID_PARAMS);
return logRPCError (rpcError (rpcINVALID_PARAMS));
Json::Value params = jvParams.size () ? jvParams[0u] : Json::Value (Json::objectValue);
if (!params.isObject ())
return rpcError (rpcINVALID_PARAMS);
return logRPCError (rpcError (rpcINVALID_PARAMS));
// Provide the JSON-RPC method as the field "command" in the request.
params["command"] = strMethod;
@@ -3922,7 +4029,7 @@ Json::Value RPCHandler::doRpcCommand (const std::string& strMethod, Json::Value
jvResult["status"] = "success";
}
return jvResult;
return logRPCError (jvResult);
}
Json::Value RPCHandler::doInternal (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder)