mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Improved human readable JSON-RPC error messages
This commit is contained in:
@@ -604,6 +604,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\rpc\impl\ErrorCodes.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\rpc\impl\Handler.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -1732,6 +1738,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple_data\protocol\STParsedJSON.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple_data\protocol\TER.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -2326,6 +2338,7 @@
|
||||
<ClInclude Include="..\..\src\ripple\rocksdb\rocksdb\util\string_util.h" />
|
||||
<ClInclude Include="..\..\src\ripple\rocksdb\rocksdb\util\testharness.h" />
|
||||
<ClInclude Include="..\..\src\ripple\rocksdb\rocksdb\util\testutil.h" />
|
||||
<ClInclude Include="..\..\src\ripple\rpc\api\ErrorCodes.h" />
|
||||
<ClInclude Include="..\..\src\ripple\rpc\api\Handler.h" />
|
||||
<ClInclude Include="..\..\src\ripple\rpc\api\Manager.h" />
|
||||
<ClInclude Include="..\..\src\ripple\rpc\api\Service.h" />
|
||||
@@ -2561,6 +2574,7 @@
|
||||
<ClInclude Include="..\..\src\ripple_data\protocol\SerializedObjectTemplate.h" />
|
||||
<ClInclude Include="..\..\src\ripple_data\protocol\SerializedTypes.h" />
|
||||
<ClInclude Include="..\..\src\ripple_data\protocol\Serializer.h" />
|
||||
<ClInclude Include="..\..\src\ripple_data\protocol\STParsedJSON.h" />
|
||||
<ClInclude Include="..\..\src\ripple_data\protocol\TER.h" />
|
||||
<ClInclude Include="..\..\src\ripple_data\protocol\TxFlags.h" />
|
||||
<ClInclude Include="..\..\src\ripple_data\protocol\TxFormats.h" />
|
||||
|
||||
@@ -1437,6 +1437,12 @@
|
||||
<ClCompile Include="..\..\src\ripple_app\peers\PeerSet.cpp">
|
||||
<Filter>[2] Old Ripple\ripple_app\peers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple_data\protocol\STParsedJSON.cpp">
|
||||
<Filter>[2] Old Ripple\ripple_data\protocol</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\rpc\impl\ErrorCodes.cpp">
|
||||
<Filter>[1] Ripple\rpc\impl</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\ripple_basics\containers\KeyCache.h">
|
||||
@@ -2916,6 +2922,12 @@
|
||||
<ClInclude Include="..\..\src\ripple_app\peers\PeerSet.h">
|
||||
<Filter>[2] Old Ripple\ripple_app\peers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple_data\protocol\STParsedJSON.h">
|
||||
<Filter>[2] Old Ripple\ripple_data\protocol</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\rpc\api\ErrorCodes.h">
|
||||
<Filter>[1] Ripple\rpc\api</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\ripple_data\protocol\ripple.proto">
|
||||
|
||||
208
src/ripple/rpc/api/ErrorCodes.h
Normal file
208
src/ripple/rpc/api/ErrorCodes.h
Normal file
@@ -0,0 +1,208 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RPC_ERRORCODES_H_INCLUDED
|
||||
#define RIPPLE_RPC_ERRORCODES_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO NOTE These are outside the RPC namespace
|
||||
|
||||
enum error_code_i
|
||||
{
|
||||
rpcUNKNOWN = -1, // Represents codes not listed in this enumeration
|
||||
|
||||
rpcSUCCESS = 0,
|
||||
|
||||
rpcBAD_SYNTAX, // Must be 1 to print usage to command line.
|
||||
rpcJSON_RPC,
|
||||
rpcFORBIDDEN,
|
||||
|
||||
// Error numbers beyond this line are not stable between versions.
|
||||
// Programs should use error tokens.
|
||||
|
||||
// Misc failure
|
||||
rpcLOAD_FAILED,
|
||||
rpcNO_PERMISSION,
|
||||
rpcNO_EVENTS,
|
||||
rpcNOT_STANDALONE,
|
||||
rpcTOO_BUSY,
|
||||
rpcSLOW_DOWN,
|
||||
|
||||
// Networking
|
||||
rpcNO_CLOSED,
|
||||
rpcNO_CURRENT,
|
||||
rpcNO_NETWORK,
|
||||
|
||||
// Ledger state
|
||||
rpcACT_EXISTS,
|
||||
rpcACT_NOT_FOUND,
|
||||
rpcINSUF_FUNDS,
|
||||
rpcLGR_NOT_FOUND,
|
||||
rpcNICKNAME_MISSING,
|
||||
rpcNO_ACCOUNT,
|
||||
rpcNO_PATH,
|
||||
rpcPASSWD_CHANGED,
|
||||
rpcSRC_MISSING,
|
||||
rpcSRC_UNCLAIMED,
|
||||
rpcTXN_NOT_FOUND,
|
||||
rpcWRONG_SEED,
|
||||
|
||||
// Malformed command
|
||||
rpcINVALID_PARAMS,
|
||||
rpcUNKNOWN_COMMAND,
|
||||
rpcNO_PF_REQUEST,
|
||||
|
||||
// Bad parameter
|
||||
rpcACT_BITCOIN,
|
||||
rpcACT_MALFORMED,
|
||||
rpcQUALITY_MALFORMED,
|
||||
rpcBAD_BLOB,
|
||||
rpcBAD_FEATURE,
|
||||
rpcBAD_ISSUER,
|
||||
rpcBAD_MARKET,
|
||||
rpcBAD_SECRET,
|
||||
rpcBAD_SEED,
|
||||
rpcCOMMAND_MISSING,
|
||||
rpcDST_ACT_MALFORMED,
|
||||
rpcDST_ACT_MISSING,
|
||||
rpcDST_AMT_MALFORMED,
|
||||
rpcDST_ISR_MALFORMED,
|
||||
rpcGETS_ACT_MALFORMED,
|
||||
rpcGETS_AMT_MALFORMED,
|
||||
rpcHOST_IP_MALFORMED,
|
||||
rpcLGR_IDXS_INVALID,
|
||||
rpcLGR_IDX_MALFORMED,
|
||||
rpcNICKNAME_MALFORMED,
|
||||
rpcNICKNAME_PERM,
|
||||
rpcPAYS_ACT_MALFORMED,
|
||||
rpcPAYS_AMT_MALFORMED,
|
||||
rpcPORT_MALFORMED,
|
||||
rpcPUBLIC_MALFORMED,
|
||||
rpcSRC_ACT_MALFORMED,
|
||||
rpcSRC_ACT_MISSING,
|
||||
rpcSRC_ACT_NOT_FOUND,
|
||||
rpcSRC_AMT_MALFORMED,
|
||||
rpcSRC_CUR_MALFORMED,
|
||||
rpcSRC_ISR_MALFORMED,
|
||||
rpcATX_DEPRECATED,
|
||||
|
||||
// Internal error (should never happen)
|
||||
rpcINTERNAL, // Generic internal error.
|
||||
rpcFAIL_GEN_DECRPYT,
|
||||
rpcNOT_IMPL,
|
||||
rpcNOT_SUPPORTED,
|
||||
rpcNO_GEN_DECRPYT,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RPC {
|
||||
|
||||
/** Maps an rpc error code to its token and default message. */
|
||||
struct ErrorInfo
|
||||
{
|
||||
ErrorInfo (error_code_i code_, std::string const& token_,
|
||||
std::string const& message_)
|
||||
: code (code_)
|
||||
, token (token_)
|
||||
, message (message_)
|
||||
{ }
|
||||
|
||||
error_code_i code;
|
||||
std::string token;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
/** Returns an ErrorInfo that reflects the error code. */
|
||||
ErrorInfo const& get_error_info (error_code_i code);
|
||||
|
||||
/** Add or update the json update to reflect the error code. */
|
||||
/** @{ */
|
||||
void inject_error (error_code_i code, Json::Value& json);
|
||||
inline void inject_error (int code, Json::Value& json)
|
||||
{ inject_error (error_code_i (code), json); }
|
||||
void inject_error (error_code_i code, std::string const& message, Json::Value& json);
|
||||
/** @} */
|
||||
|
||||
/** Returns a new json object that reflects the error code. */
|
||||
/** @{ */
|
||||
Json::Value make_error (error_code_i code);
|
||||
Json::Value make_error (error_code_i code, std::string const& message);
|
||||
/** @} */
|
||||
|
||||
/** Returns a new json object that indicates invalid parameters. */
|
||||
/** @{ */
|
||||
inline Json::Value make_param_error (std::string const& message)
|
||||
{
|
||||
return make_error (rpcINVALID_PARAMS, message);
|
||||
}
|
||||
|
||||
inline std::string missing_field_message (std::string const& name)
|
||||
{
|
||||
return "Missing field '" + name + "'.";
|
||||
}
|
||||
|
||||
inline Json::Value missing_field_error (std::string const& name)
|
||||
{
|
||||
return make_param_error (missing_field_message (name));
|
||||
}
|
||||
|
||||
inline std::string object_field_message (std::string const& name)
|
||||
{
|
||||
return "Invalid field '" + name + "', not object.";
|
||||
}
|
||||
|
||||
inline Json::Value object_field_error (std::string const& name)
|
||||
{
|
||||
return make_param_error (object_field_message (name));
|
||||
}
|
||||
|
||||
inline std::string invalid_field_message (std::string const& name)
|
||||
{
|
||||
return "Invalid field '" + name + "'.";
|
||||
}
|
||||
|
||||
inline Json::Value invalid_field_error (std::string const& name)
|
||||
{
|
||||
return make_param_error (object_field_message (name));
|
||||
}
|
||||
|
||||
inline std::string expected_field_message (
|
||||
std::string const& name, std::string const& type)
|
||||
{
|
||||
return "Invalid field '" + name + "', not " + type + ".";
|
||||
}
|
||||
|
||||
inline Json::Value expected_field_error (
|
||||
std::string const& name, std::string const& type)
|
||||
{
|
||||
return make_param_error (expected_field_message (name, type));
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/** Returns `true` if the json contains an rpc error specification. */
|
||||
bool contains_error (Json::Value const& json);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
169
src/ripple/rpc/impl/ErrorCodes.cpp
Normal file
169
src/ripple/rpc/impl/ErrorCodes.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class ErrorCategory
|
||||
{
|
||||
public:
|
||||
typedef boost::unordered_map <error_code_i, ErrorInfo> Map;
|
||||
|
||||
ErrorCategory ()
|
||||
: m_unknown (rpcUNKNOWN, "unknown", "An unknown error code.")
|
||||
{
|
||||
add (rpcACT_BITCOIN, "actBitcoin", "Account is bitcoin address.");
|
||||
add (rpcACT_EXISTS, "actExists", "Account already exists.");
|
||||
add (rpcACT_MALFORMED, "actMalformed", "Account malformed.");
|
||||
add (rpcACT_NOT_FOUND, "actNotFound", "Account not found.");
|
||||
add (rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string.");
|
||||
add (rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid.");
|
||||
add (rpcBAD_ISSUER, "badIssuer", "Issuer account malformed.");
|
||||
add (rpcBAD_MARKET, "badMarket", "No such market.");
|
||||
add (rpcBAD_SECRET, "badSecret", "Secret does not match account.");
|
||||
add (rpcBAD_SEED, "badSeed", "Disallowed seed.");
|
||||
add (rpcBAD_SYNTAX, "badSyntax", "Syntax error.");
|
||||
add (rpcCOMMAND_MISSING, "commandMissing", "Missing command entry.");
|
||||
add (rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed.");
|
||||
add (rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exist.");
|
||||
add (rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed.");
|
||||
add (rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed.");
|
||||
add (rpcFORBIDDEN, "forbidden", "Bad credentials.");
|
||||
add (rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator.");
|
||||
add (rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed.");
|
||||
add (rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed.");
|
||||
add (rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed.");
|
||||
add (rpcINSUF_FUNDS, "insufFunds", "Insufficient funds.");
|
||||
add (rpcINTERNAL, "internal", "Internal error.");
|
||||
add (rpcINVALID_PARAMS, "invalidParams", "Invalid parameters.");
|
||||
add (rpcJSON_RPC, "json_rpc", "JSON-RPC transport error.");
|
||||
add (rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid.");
|
||||
add (rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed.");
|
||||
add (rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found.");
|
||||
add (rpcNICKNAME_MALFORMED, "nicknameMalformed", "Nickname is malformed.");
|
||||
add (rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist.");
|
||||
add (rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname.");
|
||||
add (rpcNOT_IMPL, "notImpl", "Not implemented.");
|
||||
add (rpcNO_ACCOUNT, "noAccount", "No such account.");
|
||||
add (rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable.");
|
||||
add (rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable.");
|
||||
add (rpcNO_EVENTS, "noEvents", "Current transport does not support events.");
|
||||
add (rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator.");
|
||||
add (rpcNO_NETWORK, "noNetwork", "Network not available.");
|
||||
add (rpcNO_PATH, "noPath", "Unable to find a ripple path.");
|
||||
add (rpcNO_PERMISSION, "noPermission", "You don't have permission for this command.");
|
||||
add (rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress.");
|
||||
add (rpcNOT_STANDALONE, "notStandAlone", "Operation valid in debug mode only.");
|
||||
add (rpcNOT_SUPPORTED, "notSupported", "Operation not supported.");
|
||||
add (rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed.");
|
||||
add (rpcPAYS_ACT_MALFORMED, "paysActMalformed", "Pays account malformed.");
|
||||
add (rpcPAYS_AMT_MALFORMED, "paysAmtMalformed", "Pays amount malformed.");
|
||||
add (rpcPORT_MALFORMED, "portMalformed", "Port is malformed.");
|
||||
add (rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed.");
|
||||
add (rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed.");
|
||||
add (rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed.");
|
||||
add (rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided.");
|
||||
add (rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found.");
|
||||
add (rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed.");
|
||||
add (rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed.");
|
||||
add (rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed.");
|
||||
add (rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed.");
|
||||
add (rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found.");
|
||||
add (rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method.");
|
||||
add (rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key.");
|
||||
add (rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now.");
|
||||
add (rpcSLOW_DOWN, "slowDown", "You are placing too much load on the server.");
|
||||
add (rpcATX_DEPRECATED, "deprecated", "Use the new API or specify a ledger range.");
|
||||
}
|
||||
|
||||
ErrorInfo const& get (error_code_i code) const
|
||||
{
|
||||
Map::const_iterator const iter (m_map.find (code));
|
||||
if (iter != m_map.end())
|
||||
return iter->second;
|
||||
return m_unknown;
|
||||
}
|
||||
|
||||
private:
|
||||
void add (error_code_i code, std::string const& token,
|
||||
std::string const& message)
|
||||
{
|
||||
std::pair <Map::iterator, bool> result (
|
||||
m_map.emplace (boost::unordered::piecewise_construct,
|
||||
boost::make_tuple (code), boost::make_tuple (
|
||||
code, token, message)));
|
||||
check_postcondition (result.second);
|
||||
}
|
||||
|
||||
private:
|
||||
Map m_map;
|
||||
ErrorInfo m_unknown;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ErrorInfo const& get_error_info (error_code_i code)
|
||||
{
|
||||
static detail::ErrorCategory category;
|
||||
return category.get (code);
|
||||
}
|
||||
|
||||
void inject_error (error_code_i code, Json::Value& json)
|
||||
{
|
||||
ErrorInfo const& info (get_error_info (code));
|
||||
json ["error"] = info.token;
|
||||
json ["error_code"] = info.code;
|
||||
json ["error_message"] = info.message;
|
||||
}
|
||||
|
||||
void inject_error (error_code_i code, std::string const& message, Json::Value& json)
|
||||
{
|
||||
ErrorInfo const& info (get_error_info (code));
|
||||
json ["error"] = info.token;
|
||||
json ["error_code"] = info.code;
|
||||
json ["error_message"] = message;
|
||||
}
|
||||
|
||||
Json::Value make_error (error_code_i code)
|
||||
{
|
||||
Json::Value json;
|
||||
inject_error (code, json);
|
||||
return json;
|
||||
}
|
||||
|
||||
Json::Value make_error (error_code_i code, std::string const& message)
|
||||
{
|
||||
Json::Value json;
|
||||
inject_error (code, message, json);
|
||||
return json;
|
||||
}
|
||||
|
||||
bool contains_error (Json::Value const& json)
|
||||
{
|
||||
if (json.isObject() && json.isMember ("error"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "beast/modules/beast_core/system/BeforeBoost.h"
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include "impl/ErrorCodes.cpp"
|
||||
# include "impl/ManagerImpl.h"
|
||||
#include "impl/Manager.cpp"
|
||||
#include "impl/Handler.cpp"
|
||||
|
||||
@@ -27,5 +27,6 @@
|
||||
# include "api/Handler.h"
|
||||
# include "api/Service.h"
|
||||
#include "api/Manager.h"
|
||||
#include "api/ErrorCodes.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -344,9 +344,11 @@ public:
|
||||
pass ();
|
||||
}
|
||||
|
||||
std::unique_ptr<STObject> new_obj = STObject::parseJson (j.getJson (0), sfGeneric);
|
||||
STParsedJSON parsed ("test", j.getJson (0));
|
||||
std::unique_ptr <STObject> new_obj (std::move (parsed.object));
|
||||
|
||||
if (new_obj.get () == NULL) fail ("Unable to build object from json");
|
||||
if (new_obj.get () == nullptr)
|
||||
fail ("Unable to build object from json");
|
||||
|
||||
if (STObject (j) != *new_obj)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#pragma warning (disable: 4309) // truncation of constant value
|
||||
#endif
|
||||
|
||||
#include "../ripple/rpc/api/ErrorCodes.h"
|
||||
|
||||
namespace ripple
|
||||
{
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
717
src/ripple_data/protocol/STParsedJSON.cpp
Normal file
717
src/ripple_data/protocol/STParsedJSON.cpp
Normal file
@@ -0,0 +1,717 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
|
||||
STParsedJSON::STParsedJSON (std::string const& name, Json::Value const& json)
|
||||
{
|
||||
parse (name, json, sfGeneric, 0, object);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::string STParsedJSON::make_name (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
if (field.empty ())
|
||||
return object;
|
||||
|
||||
return object + "." + field;
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::not_an_object (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + make_name (object, field) + "' is not a JSON object.");
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::unknown_field (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + make_name (object, field) + "' is unknown.");
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::out_of_range (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + make_name (object, field) + "' is out of range.");
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::bad_type (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + make_name (object, field) + "' has bad type.");
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::invalid_data (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + make_name (object, field) + "' has invalid data.");
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::array_expected (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + make_name (object, field) + "' must be a JSON array.");
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::string_expected (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + make_name (object, field) + "' must be a string.");
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::too_deep (std::string const& object,
|
||||
std::string const& field)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + make_name (object, field) + "' exceeds nesting depth limit.");
|
||||
}
|
||||
|
||||
Json::Value STParsedJSON::singleton_expected (std::string const& object)
|
||||
{
|
||||
return RPC::make_error (rpcINVALID_PARAMS,
|
||||
"Field '" + object +
|
||||
"' must be an object with a single key/object value.");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool STParsedJSON::parse (std::string const& json_name,
|
||||
Json::Value const& json, SField::ref inName, int depth,
|
||||
std::unique_ptr <STObject>& sub_object)
|
||||
{
|
||||
if (! json.isObject ())
|
||||
{
|
||||
error = not_an_object (json_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
SField::ptr name (&inName);
|
||||
|
||||
boost::ptr_vector<SerializedType> data;
|
||||
Json::Value::Members members (json.getMemberNames ());
|
||||
|
||||
for (Json::Value::Members::iterator it (members.begin ());
|
||||
it != members.end (); ++it)
|
||||
{
|
||||
std::string const& fieldName = *it;
|
||||
Json::Value const& value = json [fieldName];
|
||||
|
||||
SField::ref field = SField::getField (fieldName);
|
||||
|
||||
if (field == sfInvalid)
|
||||
{
|
||||
error = unknown_field (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (field.fieldType)
|
||||
{
|
||||
case STI_UINT8:
|
||||
try
|
||||
{
|
||||
if (value.isString ())
|
||||
{
|
||||
// VFALCO TODO wtf?
|
||||
}
|
||||
else if (value.isInt ())
|
||||
{
|
||||
if (value.asInt () < 0 || value.asInt () > 255)
|
||||
{
|
||||
error = out_of_range (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
data.push_back (new STUInt8 (field,
|
||||
range_check_cast <unsigned char> (
|
||||
value.asInt (), 0, 255)));
|
||||
}
|
||||
else if (value.isUInt ())
|
||||
{
|
||||
if (value.asUInt () > 255)
|
||||
{
|
||||
error = out_of_range (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
data.push_back (new STUInt8 (field,
|
||||
range_check_cast <unsigned char> (
|
||||
value.asUInt (), 0, 255)));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_UINT16:
|
||||
try
|
||||
{
|
||||
if (value.isString ())
|
||||
{
|
||||
std::string strValue = value.asString ();
|
||||
|
||||
if (! strValue.empty () &&
|
||||
((strValue[0] < '0') || (strValue[0] > '9')))
|
||||
{
|
||||
if (field == sfTransactionType)
|
||||
{
|
||||
TxType const txType (TxFormats::getInstance()->
|
||||
findTypeByName (strValue));
|
||||
|
||||
data.push_back (new STUInt16 (field,
|
||||
static_cast <uint16> (txType)));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfTransaction;
|
||||
}
|
||||
else if (field == sfLedgerEntryType)
|
||||
{
|
||||
LedgerEntryType const type (LedgerFormats::getInstance()->
|
||||
findTypeByName (strValue));
|
||||
|
||||
data.push_back (new STUInt16 (field,
|
||||
static_cast <uint16> (type)));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfLedgerEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data.push_back (new STUInt16 (field,
|
||||
lexicalCastThrow <uint16> (strValue)));
|
||||
}
|
||||
}
|
||||
else if (value.isInt ())
|
||||
{
|
||||
data.push_back (new STUInt16 (field,
|
||||
range_check_cast <uint16> (
|
||||
value.asInt (), 0, 65535)));
|
||||
}
|
||||
else if (value.isUInt ())
|
||||
{
|
||||
data.push_back (new STUInt16 (field,
|
||||
range_check_cast <uint16> (
|
||||
value.asUInt (), 0, 65535)));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_UINT32:
|
||||
try
|
||||
{
|
||||
if (value.isString ())
|
||||
{
|
||||
data.push_back (new STUInt32 (field,
|
||||
lexicalCastThrow <uint32> (value.asString ())));
|
||||
}
|
||||
else if (value.isInt ())
|
||||
{
|
||||
data.push_back (new STUInt32 (field,
|
||||
range_check_cast <uint32> (value.asInt (), 0u, 4294967295u)));
|
||||
}
|
||||
else if (value.isUInt ())
|
||||
{
|
||||
data.push_back (new STUInt32 (field,
|
||||
static_cast <uint32> (value.asUInt ())));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_UINT64:
|
||||
try
|
||||
{
|
||||
if (value.isString ())
|
||||
{
|
||||
data.push_back (new STUInt64 (field,
|
||||
uintFromHex (value.asString ())));
|
||||
}
|
||||
else if (value.isInt ())
|
||||
{
|
||||
data.push_back (new STUInt64 (field,
|
||||
range_check_cast<uint64> (
|
||||
value.asInt (), 0, 18446744073709551615ull)));
|
||||
}
|
||||
else if (value.isUInt ())
|
||||
{
|
||||
data.push_back (new STUInt64 (field,
|
||||
static_cast <uint64> (value.asUInt ())));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_HASH128:
|
||||
try
|
||||
{
|
||||
if (value.isString ())
|
||||
{
|
||||
data.push_back (new STHash128 (field, value.asString ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_HASH160:
|
||||
try
|
||||
{
|
||||
if (value.isString ())
|
||||
{
|
||||
data.push_back (new STHash160 (field, value.asString ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_HASH256:
|
||||
try
|
||||
{
|
||||
if (value.isString ())
|
||||
{
|
||||
data.push_back (new STHash256 (field, value.asString ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_VL:
|
||||
if (! value.isString ())
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data.push_back (new STVariableLength (field,
|
||||
strUnHex (value.asString ())));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_AMOUNT:
|
||||
try
|
||||
{
|
||||
data.push_back (new STAmount (field, value));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_VECTOR256:
|
||||
if (! value.isArray ())
|
||||
{
|
||||
error = array_expected (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data.push_back (new STVector256 (field));
|
||||
STVector256* tail (dynamic_cast <STVector256*> (&data.back ()));
|
||||
check_precondition (tail);
|
||||
|
||||
for (Json::UInt i = 0; !json.isValidIndex (i); ++i)
|
||||
{
|
||||
uint256 s;
|
||||
s.SetHex (json[i].asString ());
|
||||
tail->addValue (s);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_PATHSET:
|
||||
if (!value.isArray ())
|
||||
{
|
||||
error = array_expected (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data.push_back (new STPathSet (field));
|
||||
STPathSet* tail = dynamic_cast <STPathSet*> (&data.back ());
|
||||
check_precondition (tail);
|
||||
|
||||
for (Json::UInt i = 0; value.isValidIndex (i); ++i)
|
||||
{
|
||||
STPath p;
|
||||
|
||||
if (!value[i].isArray ())
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << fieldName << "[" << i << "]";
|
||||
error = array_expected (json_name, ss.str ());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Json::UInt j = 0; value[i].isValidIndex (j); ++j)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << fieldName << "[" << i << "][" << j << "]";
|
||||
std::string const element_name (
|
||||
json_name + "." + ss.str());
|
||||
|
||||
// each element in this path has some combination of account,
|
||||
// currency, or issuer
|
||||
|
||||
Json::Value pathEl = value[i][j];
|
||||
|
||||
if (!pathEl.isObject ())
|
||||
{
|
||||
error = not_an_object (element_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
const Json::Value& account = pathEl["account"];
|
||||
const Json::Value& currency = pathEl["currency"];
|
||||
const Json::Value& issuer = pathEl["issuer"];
|
||||
bool hasCurrency = false;
|
||||
uint160 uAccount, uCurrency, uIssuer;
|
||||
|
||||
if (! account.isNull ())
|
||||
{
|
||||
// human account id
|
||||
if (! account.isString ())
|
||||
{
|
||||
error = string_expected (element_name, "account");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string const strValue (account.asString ());
|
||||
|
||||
if (value.size () == 40) // 160-bit hex account value
|
||||
uAccount.SetHex (strValue);
|
||||
|
||||
{
|
||||
RippleAddress a;
|
||||
|
||||
if (! a.setAccountID (strValue))
|
||||
{
|
||||
error = invalid_data (element_name, "account");
|
||||
return false;
|
||||
}
|
||||
|
||||
uAccount = a.getAccountID ();
|
||||
}
|
||||
}
|
||||
|
||||
if (!currency.isNull ())
|
||||
{
|
||||
// human currency
|
||||
if (!currency.isString ())
|
||||
{
|
||||
error = string_expected (element_name, "currency");
|
||||
return false;
|
||||
}
|
||||
|
||||
hasCurrency = true;
|
||||
|
||||
if (currency.asString ().size () == 40)
|
||||
{
|
||||
uCurrency.SetHex (currency.asString ());
|
||||
}
|
||||
else if (!STAmount::currencyFromString (
|
||||
uCurrency, currency.asString ()))
|
||||
{
|
||||
error = invalid_data (element_name, "currency");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!issuer.isNull ())
|
||||
{
|
||||
// human account id
|
||||
if (!issuer.isString ())
|
||||
{
|
||||
error = string_expected (element_name, "issuer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (issuer.asString ().size () == 40)
|
||||
{
|
||||
uIssuer.SetHex (issuer.asString ());
|
||||
}
|
||||
else
|
||||
{
|
||||
RippleAddress a;
|
||||
|
||||
if (!a.setAccountID (issuer.asString ()))
|
||||
{
|
||||
error = invalid_data (element_name, "issuer");
|
||||
return false;
|
||||
}
|
||||
|
||||
uIssuer = a.getAccountID ();
|
||||
}
|
||||
}
|
||||
|
||||
p.addElement (STPathElement (uAccount, uCurrency, uIssuer, hasCurrency));
|
||||
}
|
||||
|
||||
tail->addPath (p);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_ACCOUNT:
|
||||
{
|
||||
if (! value.isString ())
|
||||
{
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string strValue = value.asString ();
|
||||
|
||||
try
|
||||
{
|
||||
if (value.size () == 40) // 160-bit hex account value
|
||||
{
|
||||
uint160 v;
|
||||
v.SetHex (strValue);
|
||||
data.push_back (new STAccount (field, v));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ripple address
|
||||
RippleAddress a;
|
||||
|
||||
if (!a.setAccountID (strValue))
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
data.push_back (new STAccount (field, a.getAccountID ()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_OBJECT:
|
||||
case STI_TRANSACTION:
|
||||
case STI_LEDGERENTRY:
|
||||
case STI_VALIDATION:
|
||||
if (! value.isObject ())
|
||||
{
|
||||
error = not_an_object (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (depth > 64)
|
||||
{
|
||||
error = too_deep (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::unique_ptr <STObject> sub_object_;
|
||||
bool const success (parse (json_name + "." + fieldName,
|
||||
value, field, depth + 1, sub_object_));
|
||||
if (! success)
|
||||
return false;
|
||||
data.push_back (sub_object_.release ());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_ARRAY:
|
||||
if (! value.isArray ())
|
||||
{
|
||||
error = array_expected (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data.push_back (new STArray (field));
|
||||
STArray* tail = dynamic_cast<STArray*> (&data.back ());
|
||||
check_precondition (tail);
|
||||
|
||||
for (Json::UInt i = 0; value.isValidIndex (i); ++i)
|
||||
{
|
||||
bool const isObject (value[i].isObject());
|
||||
bool const singleKey (isObject
|
||||
? value [i].size() == 1
|
||||
: true);
|
||||
|
||||
if (!isObject || !singleKey)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << json_name << "." << fieldName << "[" << i << "]";
|
||||
error = singleton_expected (ss.str ());
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: There doesn't seem to be a nice way to get just the
|
||||
// first/only key in an object without copying all keys into
|
||||
// a vector
|
||||
std::string const objectName (value[i].getMemberNames()[0]);;
|
||||
SField::ref const nameField (SField::getField(objectName));
|
||||
Json::Value const objectFields (value[i][objectName]);
|
||||
|
||||
std::unique_ptr <STObject> sub_object_;
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << json_name << "." << fieldName <<
|
||||
"[" << i << "]." << objectName;
|
||||
bool const success (parse (ss.str (), objectFields,
|
||||
nameField, depth + 1, sub_object_));
|
||||
if (! success)
|
||||
return false;
|
||||
}
|
||||
tail->push_back (*sub_object_);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
error = bad_type (json_name, fieldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sub_object.reset (new STObject (*name, data));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
84
src/ripple_data/protocol/STParsedJSON.h
Normal file
84
src/ripple_data/protocol/STParsedJSON.h
Normal file
@@ -0,0 +1,84 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_DATA_STPARSEDJSON_H
|
||||
#define RIPPLE_DATA_STPARSEDJSON_H
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Holds the serialized result of parsing input JSON.
|
||||
This does validation and checking on the provided JSON.
|
||||
*/
|
||||
class STParsedJSON
|
||||
{
|
||||
public:
|
||||
/** Parses and creates an STParsedJSON object.
|
||||
The result of the parsing is stored in object and error.
|
||||
Exceptions:
|
||||
Does not throw.
|
||||
@param name The name of the JSON field, used in diagnostics.
|
||||
@param json The JSON-RPC to parse.
|
||||
*/
|
||||
STParsedJSON (std::string const& name,
|
||||
Json::Value const& json);
|
||||
|
||||
/** The STObject if the parse was successful. */
|
||||
std::unique_ptr <STObject> object;
|
||||
|
||||
/** On failure, an appropriate set of error values. */
|
||||
Json::Value error;
|
||||
|
||||
private:
|
||||
static std::string make_name (std::string const& object,
|
||||
std::string const& field);
|
||||
|
||||
static Json::Value not_an_object (std::string const& object,
|
||||
std::string const& field = std::string());
|
||||
|
||||
static Json::Value unknown_field (std::string const& object,
|
||||
std::string const& field = std::string());
|
||||
|
||||
static Json::Value out_of_range (std::string const& object,
|
||||
std::string const& field = std::string());
|
||||
|
||||
static Json::Value bad_type (std::string const& object,
|
||||
std::string const& field = std::string());
|
||||
|
||||
static Json::Value invalid_data (std::string const& object,
|
||||
std::string const& field = std::string());
|
||||
|
||||
static Json::Value array_expected (std::string const& object,
|
||||
std::string const& field = std::string());
|
||||
|
||||
static Json::Value string_expected (std::string const& object,
|
||||
std::string const& field = std::string());
|
||||
|
||||
static Json::Value too_deep (std::string const& object,
|
||||
std::string const& field = std::string());
|
||||
|
||||
static Json::Value singleton_expected (
|
||||
std::string const& object);
|
||||
|
||||
bool parse (std::string const& json_name, Json::Value const& json,
|
||||
SField::ref inName, int depth, std::unique_ptr <STObject>& sub_object);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -138,7 +138,7 @@ void STObject::set (const SOTemplate& type)
|
||||
mData.clear ();
|
||||
mType = &type;
|
||||
|
||||
BOOST_FOREACH (const SOElement * elem, type.peek ())
|
||||
for (SOTemplate::value_type const& elem : type.peek ())
|
||||
{
|
||||
if (elem->flags != SOE_REQUIRED)
|
||||
giveObject (makeNonPresentObject (elem->e_field));
|
||||
@@ -154,7 +154,7 @@ bool STObject::setType (const SOTemplate& type)
|
||||
|
||||
mType = &type;
|
||||
|
||||
BOOST_FOREACH (const SOElement * elem, type.peek ())
|
||||
for (SOTemplate::value_type const& elem : type.peek ())
|
||||
{
|
||||
bool match = false;
|
||||
|
||||
@@ -208,7 +208,7 @@ bool STObject::isValidForType ()
|
||||
{
|
||||
boost::ptr_vector<SerializedType>::iterator it = mData.begin ();
|
||||
|
||||
BOOST_FOREACH (const SOElement * elem, mType->peek ())
|
||||
for (SOTemplate::value_type const& elem : mType->peek ())
|
||||
{
|
||||
if (it == mData.end ())
|
||||
return false;
|
||||
@@ -1232,381 +1232,6 @@ void STArray::sort (bool (*compare) (const STObject&, const STObject&))
|
||||
value.sort (compare);
|
||||
}
|
||||
|
||||
std::unique_ptr<STObject> STObject::parseJson (const Json::Value& object, SField::ref inName, int depth)
|
||||
{
|
||||
if (!object.isObject ())
|
||||
throw std::runtime_error ("Value is not an object");
|
||||
|
||||
SField::ptr name = &inName;
|
||||
|
||||
boost::ptr_vector<SerializedType> data;
|
||||
Json::Value::Members members (object.getMemberNames ());
|
||||
|
||||
for (Json::Value::Members::iterator it = members.begin (), end = members.end (); it != end; ++it)
|
||||
{
|
||||
const std::string& fieldName = *it;
|
||||
const Json::Value& value = object[fieldName];
|
||||
|
||||
SField::ref field = SField::getField (fieldName);
|
||||
|
||||
if (field == sfInvalid)
|
||||
throw std::runtime_error ("Unknown field: " + fieldName);
|
||||
|
||||
switch (field.fieldType)
|
||||
{
|
||||
case STI_UINT8:
|
||||
if (value.isString ())
|
||||
{
|
||||
#if 0
|
||||
|
||||
if (field == sfTransactionResult)
|
||||
{
|
||||
TER terCode;
|
||||
|
||||
if (FUNCTION_THAT_DOESNT_EXIST (value.asString (), terCode))
|
||||
value = static_cast<int> (terCode);
|
||||
else
|
||||
data.push_back (new STUInt8 (field, lexicalCastThrow <unsigned char> (value.asString ())));
|
||||
}
|
||||
|
||||
data.push_back (new STUInt8 (field, lexicalCastThrow <unsigned char> (value.asString ())));
|
||||
#endif
|
||||
}
|
||||
else if (value.isInt ())
|
||||
{
|
||||
if (value.asInt () < 0 || value.asInt () > 255)
|
||||
throw std::runtime_error ("value out of range");
|
||||
|
||||
data.push_back (new STUInt8 (field, range_check_cast<unsigned char> (value.asInt (), 0, 255)));
|
||||
}
|
||||
else if (value.isUInt ())
|
||||
{
|
||||
if (value.asUInt () > 255)
|
||||
throw std::runtime_error ("value out of range");
|
||||
|
||||
data.push_back (new STUInt8 (field, range_check_cast<unsigned char> (value.asUInt (), 0, 255)));
|
||||
}
|
||||
else
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
break;
|
||||
|
||||
case STI_UINT16:
|
||||
if (value.isString ())
|
||||
{
|
||||
std::string strValue = value.asString ();
|
||||
|
||||
if (!strValue.empty () && ((strValue[0] < '0') || (strValue[0] > '9')))
|
||||
{
|
||||
if (field == sfTransactionType)
|
||||
{
|
||||
// Retrieve type from name. Throws if not found.
|
||||
TxType const txType = TxFormats::getInstance()->findTypeByName (strValue);
|
||||
|
||||
data.push_back (new STUInt16 (field, static_cast<uint16> (txType)));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfTransaction;
|
||||
}
|
||||
else if (field == sfLedgerEntryType)
|
||||
{
|
||||
LedgerEntryType const type = LedgerFormats::getInstance()->findTypeByName (strValue);
|
||||
|
||||
data.push_back (new STUInt16 (field, static_cast<uint16> (type)));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfLedgerEntry;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error ("Invalid field data");
|
||||
}
|
||||
else
|
||||
data.push_back (new STUInt16 (field, lexicalCastThrow <uint16> (strValue)));
|
||||
}
|
||||
else if (value.isInt ())
|
||||
data.push_back (new STUInt16 (field, range_check_cast<uint16> (value.asInt (), 0, 65535)));
|
||||
else if (value.isUInt ())
|
||||
data.push_back (new STUInt16 (field, range_check_cast<uint16> (value.asUInt (), 0, 65535)));
|
||||
else
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
break;
|
||||
|
||||
case STI_UINT32:
|
||||
if (value.isString ())
|
||||
{
|
||||
data.push_back (new STUInt32 (field, lexicalCastThrow <uint32> (value.asString ())));
|
||||
}
|
||||
else if (value.isInt ())
|
||||
{
|
||||
data.push_back (new STUInt32 (field, range_check_cast <uint32> (value.asInt (), 0u, 4294967295u)));
|
||||
}
|
||||
else if (value.isUInt ())
|
||||
{
|
||||
data.push_back (new STUInt32 (field, static_cast<uint32> (value.asUInt ())));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_UINT64:
|
||||
if (value.isString ())
|
||||
data.push_back (new STUInt64 (field, uintFromHex (value.asString ())));
|
||||
else if (value.isInt ())
|
||||
data.push_back (new STUInt64 (field,
|
||||
range_check_cast<uint64> (value.asInt (), 0, 18446744073709551615ull)));
|
||||
else if (value.isUInt ())
|
||||
data.push_back (new STUInt64 (field, static_cast<uint64> (value.asUInt ())));
|
||||
else
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case STI_HASH128:
|
||||
if (value.isString ())
|
||||
data.push_back (new STHash128 (field, value.asString ()));
|
||||
else
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
break;
|
||||
|
||||
case STI_HASH160:
|
||||
if (value.isString ())
|
||||
data.push_back (new STHash160 (field, value.asString ()));
|
||||
else
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
break;
|
||||
|
||||
case STI_HASH256:
|
||||
if (value.isString ())
|
||||
data.push_back (new STHash256 (field, value.asString ()));
|
||||
else
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
break;
|
||||
|
||||
case STI_VL:
|
||||
if (!value.isString ())
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
data.push_back (new STVariableLength (field, strUnHex (value.asString ())));
|
||||
break;
|
||||
|
||||
case STI_AMOUNT:
|
||||
data.push_back (new STAmount (field, value));
|
||||
break;
|
||||
|
||||
case STI_VECTOR256:
|
||||
if (!value.isArray ())
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
{
|
||||
data.push_back (new STVector256 (field));
|
||||
STVector256* tail = dynamic_cast<STVector256*> (&data.back ());
|
||||
assert (tail);
|
||||
|
||||
for (Json::UInt i = 0; !object.isValidIndex (i); ++i)
|
||||
{
|
||||
uint256 s;
|
||||
s.SetHex (object[i].asString ());
|
||||
tail->addValue (s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_PATHSET:
|
||||
if (!value.isArray ())
|
||||
throw std::runtime_error ("Path set must be array");
|
||||
|
||||
{
|
||||
data.push_back (new STPathSet (field));
|
||||
STPathSet* tail = dynamic_cast<STPathSet*> (&data.back ());
|
||||
assert (tail);
|
||||
|
||||
for (Json::UInt i = 0; value.isValidIndex (i); ++i)
|
||||
{
|
||||
STPath p;
|
||||
|
||||
if (!value[i].isArray ())
|
||||
throw std::runtime_error ("Path must be array");
|
||||
|
||||
for (Json::UInt j = 0; value[i].isValidIndex (j); ++j)
|
||||
{
|
||||
// each element in this path has some combination of account, currency, or issuer
|
||||
|
||||
Json::Value pathEl = value[i][j];
|
||||
|
||||
if (!pathEl.isObject ())
|
||||
throw std::runtime_error ("Path elements must be objects");
|
||||
|
||||
const Json::Value& account = pathEl["account"];
|
||||
const Json::Value& currency = pathEl["currency"];
|
||||
const Json::Value& issuer = pathEl["issuer"];
|
||||
bool hasCurrency = false;
|
||||
uint160 uAccount, uCurrency, uIssuer;
|
||||
|
||||
if (!account.isNull ())
|
||||
{
|
||||
// human account id
|
||||
if (!account.isString ())
|
||||
throw std::runtime_error ("path element accounts must be strings");
|
||||
|
||||
std::string strValue = account.asString ();
|
||||
|
||||
if (value.size () == 40) // 160-bit hex account value
|
||||
uAccount.SetHex (strValue);
|
||||
|
||||
{
|
||||
RippleAddress a;
|
||||
|
||||
if (!a.setAccountID (strValue))
|
||||
throw std::runtime_error ("Account in path element invalid");
|
||||
|
||||
uAccount = a.getAccountID ();
|
||||
}
|
||||
}
|
||||
|
||||
if (!currency.isNull ())
|
||||
{
|
||||
// human currency
|
||||
if (!currency.isString ())
|
||||
throw std::runtime_error ("path element currencies must be strings");
|
||||
|
||||
hasCurrency = true;
|
||||
|
||||
if (currency.asString ().size () == 40)
|
||||
uCurrency.SetHex (currency.asString ());
|
||||
else if (!STAmount::currencyFromString (uCurrency, currency.asString ()))
|
||||
throw std::runtime_error ("invalid currency");
|
||||
}
|
||||
|
||||
if (!issuer.isNull ())
|
||||
{
|
||||
// human account id
|
||||
if (!issuer.isString ())
|
||||
throw std::runtime_error ("path element issuers must be strings");
|
||||
|
||||
if (issuer.asString ().size () == 40)
|
||||
uIssuer.SetHex (issuer.asString ());
|
||||
else
|
||||
{
|
||||
RippleAddress a;
|
||||
|
||||
if (!a.setAccountID (issuer.asString ()))
|
||||
throw std::runtime_error ("path element issuer invalid");
|
||||
|
||||
uIssuer = a.getAccountID ();
|
||||
}
|
||||
}
|
||||
|
||||
p.addElement (STPathElement (uAccount, uCurrency, uIssuer, hasCurrency));
|
||||
}
|
||||
|
||||
tail->addPath (p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_ACCOUNT:
|
||||
{
|
||||
if (!value.isString ())
|
||||
throw std::runtime_error ("Incorrect type");
|
||||
|
||||
std::string strValue = value.asString ();
|
||||
|
||||
if (value.size () == 40) // 160-bit hex account value
|
||||
{
|
||||
uint160 v;
|
||||
v.SetHex (strValue);
|
||||
data.push_back (new STAccount (field, v));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ripple address
|
||||
RippleAddress a;
|
||||
|
||||
if (!a.setAccountID (strValue))
|
||||
{
|
||||
WriteLog (lsINFO, STObject) << "Invalid acccount JSON: " << fieldName << ": " << strValue;
|
||||
throw std::runtime_error ("Account invalid");
|
||||
}
|
||||
|
||||
data.push_back (new STAccount (field, a.getAccountID ()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_OBJECT:
|
||||
case STI_TRANSACTION:
|
||||
case STI_LEDGERENTRY:
|
||||
case STI_VALIDATION:
|
||||
if (!value.isObject ())
|
||||
throw std::runtime_error ("Inner value is not an object");
|
||||
|
||||
if (depth > 64)
|
||||
throw std::runtime_error ("Json nest depth exceeded");
|
||||
|
||||
data.push_back (parseJson (value, field, depth + 1).release ());
|
||||
break;
|
||||
|
||||
case STI_ARRAY:
|
||||
if (!value.isArray ())
|
||||
throw std::runtime_error ("Inner value is not an array");
|
||||
|
||||
{
|
||||
data.push_back (new STArray (field));
|
||||
STArray* tail = dynamic_cast<STArray*> (&data.back ());
|
||||
assert (tail);
|
||||
|
||||
for (Json::UInt i = 0; value.isValidIndex (i); ++i)
|
||||
{
|
||||
|
||||
bool isObject (value[i].isObject());
|
||||
bool singleKey (true);
|
||||
|
||||
if (isObject)
|
||||
{
|
||||
singleKey = value[i].size() == 1;
|
||||
}
|
||||
|
||||
if (!isObject || !singleKey)
|
||||
{
|
||||
std::stringstream err;
|
||||
|
||||
err << "First level children of `"
|
||||
<< field.getName()
|
||||
<< "`must be objects containing a single key with"
|
||||
<< " an object value";
|
||||
|
||||
throw std::runtime_error (err.str());
|
||||
}
|
||||
|
||||
// TODO: There doesn't seem to be a nice way to get just the
|
||||
// first/only key in an object without copying all keys into
|
||||
// a vector
|
||||
std::string objectName (value[i].getMemberNames()[0]);;
|
||||
SField::ref nameField (SField::getField(objectName));
|
||||
Json::Value objectFields (value[i][objectName]);
|
||||
|
||||
tail->push_back (*STObject::parseJson (objectFields,
|
||||
nameField,
|
||||
depth + 1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error ("Invalid field type");
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<STObject> (new STObject (*name, data));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class SerializedObjectTests : public UnitTest
|
||||
@@ -1656,8 +1281,9 @@ public:
|
||||
Json::Value faultyJson;
|
||||
bool parsedOK (parseJSONString(faulty, faultyJson));
|
||||
unexpected(!parsedOK, "failed to parse");
|
||||
so = STObject::parseJson (faultyJson);
|
||||
fail ("It should have thrown. "
|
||||
STParsedJSON parsed ("test", faultyJson);
|
||||
expect (parsed.object.get() == nullptr,
|
||||
"It should have thrown. "
|
||||
"Immediate children of STArray encoded as json must "
|
||||
"have one key only.");
|
||||
}
|
||||
@@ -1677,16 +1303,15 @@ public:
|
||||
bool parsedOK (parseJSONString(json, jsonObject));
|
||||
if (parsedOK)
|
||||
{
|
||||
std::unique_ptr<STObject> so;
|
||||
so = STObject::parseJson (jsonObject);
|
||||
Json::FastWriter writer;
|
||||
std::string const& serialized (writer.write(so->getJson(0)));
|
||||
bool serializedOK = serialized == json;
|
||||
unexpected (!serializedOK, serialized + " should equal: " + json);
|
||||
STParsedJSON parsed ("test", jsonObject);
|
||||
Json::FastWriter writer;
|
||||
std::string const& serialized (
|
||||
writer.write (parsed.object->getJson(0)));
|
||||
expect (serialized == json, serialized + " should equal: " + json);
|
||||
}
|
||||
else
|
||||
{
|
||||
fail ("Couldn't parse json: " + json);
|
||||
fail ("Couldn't parse json: " + json);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,17 +48,17 @@ public:
|
||||
setType (type);
|
||||
}
|
||||
|
||||
std::unique_ptr<STObject> oClone () const
|
||||
STObject (SField::ref name, boost::ptr_vector<SerializedType>& data) : SerializedType (name), mType (NULL)
|
||||
{
|
||||
mData.swap (data);
|
||||
}
|
||||
|
||||
std::unique_ptr <STObject> oClone () const
|
||||
{
|
||||
return std::unique_ptr<STObject> (new STObject (*this));
|
||||
}
|
||||
|
||||
static std::unique_ptr<STObject> parseJson (const Json::Value & value, SField::ref name = sfGeneric, int depth = 0);
|
||||
|
||||
virtual ~STObject ()
|
||||
{
|
||||
;
|
||||
}
|
||||
virtual ~STObject () { }
|
||||
|
||||
static std::unique_ptr<SerializedType> deserialize (SerializerIterator & sit, SField::ref name);
|
||||
|
||||
@@ -295,26 +295,11 @@ private:
|
||||
}
|
||||
*/
|
||||
|
||||
// VFALCO TODO these parameters should not be const references.
|
||||
template <typename T, typename U>
|
||||
static T range_check_cast (const U& value, const T& minimum, const T& maximum)
|
||||
{
|
||||
if ((value < minimum) || (value > maximum))
|
||||
throw std::runtime_error ("Value out of range");
|
||||
|
||||
return static_cast<T> (value);
|
||||
}
|
||||
|
||||
STObject* duplicate () const
|
||||
{
|
||||
return new STObject (*this);
|
||||
}
|
||||
|
||||
STObject (SField::ref name, boost::ptr_vector<SerializedType>& data) : SerializedType (name), mType (NULL)
|
||||
{
|
||||
mData.swap (data);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::ptr_vector<SerializedType> mData;
|
||||
const SOTemplate* mType;
|
||||
@@ -322,6 +307,16 @@ private:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// VFALCO TODO these parameters should not be const references.
|
||||
template <typename T, typename U>
|
||||
static T range_check_cast (const U& value, const T& minimum, const T& maximum)
|
||||
{
|
||||
if ((value < minimum) || (value > maximum))
|
||||
throw std::runtime_error ("Value out of range");
|
||||
|
||||
return static_cast<T> (value);
|
||||
}
|
||||
|
||||
inline STObject::iterator range_begin (STObject& x)
|
||||
{
|
||||
return x.begin ();
|
||||
|
||||
@@ -47,7 +47,7 @@ void SOTemplate::push_back (SOElement const& r)
|
||||
|
||||
// Append the new element.
|
||||
//
|
||||
mTypes.push_back (new SOElement (r));
|
||||
mTypes.push_back (value_type (new SOElement (r)));
|
||||
}
|
||||
|
||||
int SOTemplate::getIndex (SField::ref f) const
|
||||
|
||||
@@ -53,18 +53,18 @@ public:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Defines the fields and their attributes within a SerializedObject.
|
||||
|
||||
Each subclass of SerializedObject will provide its own template
|
||||
describing the available fields and their metadata attributes.
|
||||
*/
|
||||
class SOTemplate
|
||||
{
|
||||
public:
|
||||
/** Create an empty template.
|
||||
typedef std::unique_ptr <SOElement const> value_type;
|
||||
typedef std::vector <value_type> list_type;
|
||||
|
||||
/** Create an empty template.
|
||||
After creating the template, call @ref push_back with the
|
||||
desired fields.
|
||||
|
||||
@see push_back
|
||||
*/
|
||||
SOTemplate ();
|
||||
@@ -72,21 +72,19 @@ public:
|
||||
// VFALCO NOTE Why do we even bother with the 'private' keyword if
|
||||
// this function is present?
|
||||
//
|
||||
std::vector <SOElement const*> const& peek () const
|
||||
list_type const& peek () const
|
||||
{
|
||||
return mTypes;
|
||||
}
|
||||
|
||||
/** Add an element to the template.
|
||||
*/
|
||||
/** Add an element to the template. */
|
||||
void push_back (SOElement const& r);
|
||||
|
||||
/** Retrieve the position of a named field.
|
||||
*/
|
||||
/** Retrieve the position of a named field. */
|
||||
int getIndex (SField::ref) const;
|
||||
|
||||
private:
|
||||
std::vector <SOElement const*> mTypes;
|
||||
list_type mTypes;
|
||||
|
||||
std::vector <int> mIndex; // field num -> index
|
||||
};
|
||||
|
||||
@@ -65,6 +65,20 @@ static inline const uint160& get_u160_one ()
|
||||
#define ACCOUNT_XRP get_u160_zero()
|
||||
#define ACCOUNT_ONE get_u160_one() // Used as a place holder.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A type which can be exported to a well known binary format.
|
||||
|
||||
A SerializedType:
|
||||
- Always a field
|
||||
- Can always go inside an eligible enclosing SerializedType
|
||||
(such as STArray)
|
||||
- Has a field name
|
||||
|
||||
|
||||
Like JSON, a SerializedObject is a basket which has rules
|
||||
on what it can hold.
|
||||
*/
|
||||
// VFALCO TODO Document this as it looks like a central class.
|
||||
// STObject is derived from it
|
||||
//
|
||||
@@ -88,6 +102,9 @@ public:
|
||||
return std::unique_ptr<SerializedType> (new SerializedType (name));
|
||||
}
|
||||
|
||||
/** A SerializeType is a field.
|
||||
This sets the name.
|
||||
*/
|
||||
void setFName (SField::ref n)
|
||||
{
|
||||
fName = &n;
|
||||
@@ -160,19 +177,27 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline SerializedType* new_clone (const SerializedType& s)
|
||||
{
|
||||
return s.clone ().release ();
|
||||
SerializedType* const copy (s.clone ().release ());
|
||||
assert (typeid (*copy) == typeid (s));
|
||||
return copy;
|
||||
}
|
||||
|
||||
inline void delete_clone (const SerializedType* s)
|
||||
{
|
||||
boost::checked_delete (s);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& out, const SerializedType& t)
|
||||
{
|
||||
return out << t.getFullText ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STUInt8 : public SerializedType
|
||||
{
|
||||
public:
|
||||
@@ -230,6 +255,8 @@ private:
|
||||
static STUInt8* construct (SerializerIterator&, SField::ref f);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STUInt16 : public SerializedType
|
||||
{
|
||||
public:
|
||||
@@ -287,6 +314,8 @@ private:
|
||||
static STUInt16* construct (SerializerIterator&, SField::ref name);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STUInt32 : public SerializedType
|
||||
{
|
||||
public:
|
||||
@@ -344,10 +373,11 @@ private:
|
||||
static STUInt32* construct (SerializerIterator&, SField::ref name);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STUInt64 : public SerializedType
|
||||
{
|
||||
public:
|
||||
|
||||
STUInt64 (uint64 v = 0) : value (v)
|
||||
{
|
||||
;
|
||||
@@ -401,6 +431,8 @@ private:
|
||||
static STUInt64* construct (SerializerIterator&, SField::ref name);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Internal form:
|
||||
// 1: If amount is zero, then value is zero and offset is -100
|
||||
// 2: Otherwise:
|
||||
@@ -805,6 +837,8 @@ private:
|
||||
extern const STAmount saZero;
|
||||
extern const STAmount saOne;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STHash128 : public SerializedType
|
||||
{
|
||||
public:
|
||||
@@ -876,6 +910,8 @@ private:
|
||||
static STHash128* construct (SerializerIterator&, SField::ref name);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STHash160 : public SerializedType
|
||||
{
|
||||
public:
|
||||
@@ -947,6 +983,8 @@ private:
|
||||
static STHash160* construct (SerializerIterator&, SField::ref name);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STHash256 : public SerializedType
|
||||
{
|
||||
public:
|
||||
@@ -1018,6 +1056,8 @@ private:
|
||||
static STHash256* construct (SerializerIterator&, SField::ref);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// variable length byte string
|
||||
class STVariableLength : public SerializedType
|
||||
{
|
||||
@@ -1091,6 +1131,8 @@ private:
|
||||
static STVariableLength* construct (SerializerIterator&, SField::ref);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STAccount : public STVariableLength
|
||||
{
|
||||
public:
|
||||
@@ -1137,6 +1179,8 @@ private:
|
||||
static STAccount* construct (SerializerIterator&, SField::ref);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STPathElement
|
||||
{
|
||||
private:
|
||||
@@ -1223,6 +1267,8 @@ private:
|
||||
uint160 mIssuerID;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STPath
|
||||
{
|
||||
public:
|
||||
@@ -1322,6 +1368,8 @@ inline std::vector<STPathElement>::const_iterator range_end (const STPath& x)
|
||||
return x.end ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// A set of zero or more payment paths
|
||||
class STPathSet : public SerializedType
|
||||
{
|
||||
@@ -1482,6 +1530,8 @@ inline std::vector<STPath>::const_iterator range_end (const STPathSet& x)
|
||||
return x.end ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STVector256 : public SerializedType
|
||||
{
|
||||
public:
|
||||
@@ -1582,4 +1632,3 @@ private:
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../ripple/sslutil/ripple_sslutil.h"
|
||||
#include "../ripple/rpc/api/ErrorCodes.h"
|
||||
|
||||
// VFALCO TODO fix these warnings!
|
||||
#if BEAST_MSVC
|
||||
@@ -55,6 +56,8 @@
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#include "protocol/STParsedJSON.cpp"
|
||||
|
||||
namespace ripple
|
||||
{
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ namespace ripple {
|
||||
|
||||
}
|
||||
|
||||
#include "protocol/STParsedJSON.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace boost
|
||||
|
||||
@@ -42,6 +42,12 @@
|
||||
|
||||
#include "../ripple_websocket/ripple_websocket.h" // for HTTPClient, RPCDoor
|
||||
|
||||
// VFALCO NOTE This is the "new new new" where individual headers are included
|
||||
// directly (instead of th emodule header). The corresponding .cpp
|
||||
// still uses the unity style inclusion.
|
||||
//
|
||||
#include "../ripple/rpc/api/ErrorCodes.h"
|
||||
|
||||
namespace ripple
|
||||
{
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@ private:
|
||||
}
|
||||
else
|
||||
{
|
||||
return rpcError (rpcINVALID_PARAMS);
|
||||
return RPC::make_param_error (std::string ("Invalid currency/issuer '") +
|
||||
strCurrencyIssuer + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,104 +17,32 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
struct RPCErr; // for Log
|
||||
struct RPCErr;
|
||||
|
||||
SETUP_LOG (RPCErr)
|
||||
|
||||
// VFALCO NOTE Deprecated function
|
||||
Json::Value rpcError (int iError, Json::Value jvResult)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
int iError;
|
||||
const char* pToken;
|
||||
const char* pMessage;
|
||||
} errorInfoA[] =
|
||||
{
|
||||
{ rpcACT_BITCOIN, "actBitcoin", "Account is bitcoin address." },
|
||||
{ rpcACT_EXISTS, "actExists", "Account already exists." },
|
||||
{ rpcACT_MALFORMED, "actMalformed", "Account malformed." },
|
||||
{ rpcACT_NOT_FOUND, "actNotFound", "Account not found." },
|
||||
{ rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string." },
|
||||
{ rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid." },
|
||||
{ rpcBAD_ISSUER, "badIssuer", "Issuer account malformed." },
|
||||
{ rpcBAD_MARKET, "badMarket", "No such market." },
|
||||
{ rpcBAD_SECRET, "badSecret", "Secret does not match account." },
|
||||
{ rpcBAD_SEED, "badSeed", "Disallowed seed." },
|
||||
{ rpcBAD_SYNTAX, "badSyntax", "Syntax error." },
|
||||
{ rpcCOMMAND_MISSING, "commandMissing", "Missing command entry." },
|
||||
{ rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." },
|
||||
{ rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exist." },
|
||||
{ rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed." },
|
||||
{ rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed." },
|
||||
{ rpcFORBIDDEN, "forbidden", "Bad credentials." },
|
||||
{ rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." },
|
||||
{ rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." },
|
||||
{ rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed." },
|
||||
{ rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." },
|
||||
{ rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." },
|
||||
{ rpcINTERNAL, "internal", "Internal error." },
|
||||
{ rpcINVALID_PARAMS, "invalidParams", "Invalid parameters." },
|
||||
{ rpcJSON_RPC, "json_rpc", "JSON-RPC transport error." },
|
||||
{ rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." },
|
||||
{ rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." },
|
||||
{ rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." },
|
||||
{ rpcNICKNAME_MALFORMED, "nicknameMalformed", "Nickname is malformed." },
|
||||
{ rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." },
|
||||
{ rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." },
|
||||
{ rpcNOT_IMPL, "notImpl", "Not implemented." },
|
||||
{ rpcNO_ACCOUNT, "noAccount", "No such account." },
|
||||
{ rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." },
|
||||
{ rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." },
|
||||
{ rpcNO_EVENTS, "noEvents", "Current transport does not support events." },
|
||||
{ rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." },
|
||||
{ rpcNO_NETWORK, "noNetwork", "Network not available." },
|
||||
{ rpcNO_PATH, "noPath", "Unable to find a ripple path." },
|
||||
{ rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." },
|
||||
{ rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress." },
|
||||
{ rpcNOT_STANDALONE, "notStandAlone", "Operation valid in debug mode only." },
|
||||
{ rpcNOT_SUPPORTED, "notSupported", "Operation not supported." },
|
||||
{ rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." },
|
||||
{ rpcPAYS_ACT_MALFORMED, "paysActMalformed", "Pays account malformed." },
|
||||
{ rpcPAYS_AMT_MALFORMED, "paysAmtMalformed", "Pays amount malformed." },
|
||||
{ rpcPORT_MALFORMED, "portMalformed", "Port is malformed." },
|
||||
{ rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." },
|
||||
{ rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." },
|
||||
{ rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." },
|
||||
{ rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided." },
|
||||
{ rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found." },
|
||||
{ rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." },
|
||||
{ rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed." },
|
||||
{ rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed." },
|
||||
{ rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." },
|
||||
{ rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." },
|
||||
{ rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method." },
|
||||
{ rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." },
|
||||
{ rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now." },
|
||||
{ rpcSLOW_DOWN, "slowDown", "You are placing too much load on the server." },
|
||||
{ rpcATX_DEPRECATED, "deprecated", "Use the new API or specify a ledger range." },
|
||||
};
|
||||
|
||||
int i;
|
||||
|
||||
for (i = NUMBER (errorInfoA); i-- && errorInfoA[i].iError != iError;)
|
||||
;
|
||||
|
||||
jvResult["error"] = i >= 0 ? errorInfoA[i].pToken : lexicalCast <std::string> (iError);
|
||||
jvResult["error_message"] = i >= 0 ? errorInfoA[i].pMessage : lexicalCast <std::string> (iError);
|
||||
jvResult["error_code"] = iError;
|
||||
|
||||
if (i >= 0)
|
||||
{
|
||||
WriteLog (lsDEBUG, RPCErr) << "rpcError: "
|
||||
<< errorInfoA[i].pToken << ": " << errorInfoA[i].pMessage << std::endl;
|
||||
}
|
||||
|
||||
RPC::inject_error (iError, jvResult);
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
// VFALCO NOTE Deprecated function
|
||||
bool isRpcError (Json::Value jvResult)
|
||||
{
|
||||
return jvResult.isObject () && jvResult.isMember ("error");
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
Json::Value const& logRPCError (Json::Value const& json)
|
||||
{
|
||||
if (RPC::contains_error (json))
|
||||
{
|
||||
WriteLog (lsDEBUG, RPCErr) <<
|
||||
"rpcError: " << json ["error"] <<
|
||||
": " << json ["error_message"];
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,92 +20,11 @@
|
||||
#ifndef RIPPLE_NET_RPC_RPCERR_H_INCLUDED
|
||||
#define RIPPLE_NET_RPC_RPCERR_H_INCLUDED
|
||||
|
||||
enum
|
||||
{
|
||||
rpcSUCCESS = 0,
|
||||
rpcBAD_SYNTAX, // Must be 1 to print usage to command line.
|
||||
rpcJSON_RPC,
|
||||
rpcFORBIDDEN,
|
||||
|
||||
// Error numbers beyond this line are not stable between versions.
|
||||
// Programs should use error tokens.
|
||||
|
||||
// Misc failure
|
||||
rpcLOAD_FAILED,
|
||||
rpcNO_PERMISSION,
|
||||
rpcNO_EVENTS,
|
||||
rpcNOT_STANDALONE,
|
||||
rpcTOO_BUSY,
|
||||
rpcSLOW_DOWN,
|
||||
|
||||
// Networking
|
||||
rpcNO_CLOSED,
|
||||
rpcNO_CURRENT,
|
||||
rpcNO_NETWORK,
|
||||
|
||||
// Ledger state
|
||||
rpcACT_EXISTS,
|
||||
rpcACT_NOT_FOUND,
|
||||
rpcINSUF_FUNDS,
|
||||
rpcLGR_NOT_FOUND,
|
||||
rpcNICKNAME_MISSING,
|
||||
rpcNO_ACCOUNT,
|
||||
rpcNO_PATH,
|
||||
rpcPASSWD_CHANGED,
|
||||
rpcSRC_MISSING,
|
||||
rpcSRC_UNCLAIMED,
|
||||
rpcTXN_NOT_FOUND,
|
||||
rpcWRONG_SEED,
|
||||
|
||||
// Malformed command
|
||||
rpcINVALID_PARAMS,
|
||||
rpcUNKNOWN_COMMAND,
|
||||
rpcNO_PF_REQUEST,
|
||||
|
||||
// Bad parameter
|
||||
rpcACT_BITCOIN,
|
||||
rpcACT_MALFORMED,
|
||||
rpcQUALITY_MALFORMED,
|
||||
rpcBAD_BLOB,
|
||||
rpcBAD_FEATURE,
|
||||
rpcBAD_ISSUER,
|
||||
rpcBAD_MARKET,
|
||||
rpcBAD_SECRET,
|
||||
rpcBAD_SEED,
|
||||
rpcCOMMAND_MISSING,
|
||||
rpcDST_ACT_MALFORMED,
|
||||
rpcDST_ACT_MISSING,
|
||||
rpcDST_AMT_MALFORMED,
|
||||
rpcDST_ISR_MALFORMED,
|
||||
rpcGETS_ACT_MALFORMED,
|
||||
rpcGETS_AMT_MALFORMED,
|
||||
rpcHOST_IP_MALFORMED,
|
||||
rpcLGR_IDXS_INVALID,
|
||||
rpcLGR_IDX_MALFORMED,
|
||||
rpcNICKNAME_MALFORMED,
|
||||
rpcNICKNAME_PERM,
|
||||
rpcPAYS_ACT_MALFORMED,
|
||||
rpcPAYS_AMT_MALFORMED,
|
||||
rpcPORT_MALFORMED,
|
||||
rpcPUBLIC_MALFORMED,
|
||||
rpcSRC_ACT_MALFORMED,
|
||||
rpcSRC_ACT_MISSING,
|
||||
rpcSRC_ACT_NOT_FOUND,
|
||||
rpcSRC_AMT_MALFORMED,
|
||||
rpcSRC_CUR_MALFORMED,
|
||||
rpcSRC_ISR_MALFORMED,
|
||||
rpcATX_DEPRECATED,
|
||||
|
||||
// Internal error (should never happen)
|
||||
rpcINTERNAL, // Generic internal error.
|
||||
rpcFAIL_GEN_DECRPYT,
|
||||
rpcNOT_IMPL,
|
||||
rpcNOT_SUPPORTED,
|
||||
rpcNO_GEN_DECRPYT,
|
||||
};
|
||||
Json::Value const& logRPCError (Json::Value const& json);
|
||||
|
||||
// VFALCO NOTE these are deprecated
|
||||
bool isRpcError (Json::Value jvResult);
|
||||
Json::Value rpcError (int iError, Json::Value jvResult = Json::Value (Json::objectValue));
|
||||
Json::Value rpcError (int iError,
|
||||
Json::Value jvResult = Json::Value (Json::objectValue));
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
|
||||
Reference in New Issue
Block a user