1#include <xrpl/protocol/STParsedJSON.h>
3#include <xrpl/basics/StringUtilities.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/basics/contract.h>
6#include <xrpl/basics/safe_cast.h>
7#include <xrpl/beast/core/LexicalCast.h>
8#include <xrpl/beast/utility/Zero.h>
9#include <xrpl/json/json_forwards.h>
10#include <xrpl/json/json_value.h>
11#include <xrpl/protocol/AccountID.h>
12#include <xrpl/protocol/ErrorCodes.h>
13#include <xrpl/protocol/LedgerFormats.h>
14#include <xrpl/protocol/MPTIssue.h>
15#include <xrpl/protocol/PathAsset.h>
16#include <xrpl/protocol/Permissions.h>
17#include <xrpl/protocol/SField.h>
18#include <xrpl/protocol/STAccount.h>
19#include <xrpl/protocol/STAmount.h>
20#include <xrpl/protocol/STArray.h>
21#include <xrpl/protocol/STBitString.h>
22#include <xrpl/protocol/STBlob.h>
23#include <xrpl/protocol/STCurrency.h>
24#include <xrpl/protocol/STInteger.h>
25#include <xrpl/protocol/STIssue.h>
26#include <xrpl/protocol/STNumber.h>
27#include <xrpl/protocol/STPathSet.h>
28#include <xrpl/protocol/STVector256.h>
29#include <xrpl/protocol/STXChainBridge.h>
30#include <xrpl/protocol/TER.h>
31#include <xrpl/protocol/TxFormats.h>
32#include <xrpl/protocol/UintTypes.h>
33#include <xrpl/protocol/detail/STVar.h>
34#include <xrpl/protocol/jss.h>
52template <
typename U,
typename S>
58 return static_cast<U
>(value);
61template <
typename U1,
typename U2>
67 return static_cast<U1
>(value);
77 return object +
"." + field;
144 "Field '" +
makeName(
object, field) +
"' exceeds allowed JSON array size of " +
167 "]' must be an object with a single key/object value.");
175 "Object '" + sField.
getName() +
"' contents did not meet requirements for that type.");
184 " is not an object. Arrays may only contain objects.");
188template <
class STResult,
class Integer>
202 if (value.isString())
209 else if (value.isInt())
214 else if (value.isUInt())
221 error =
badType(jsonName, fieldName);
234template <
class STResult,
class Integer = std::u
int16_t>
248 if (value.isString())
252 if (!strValue.
empty() && ((strValue[0] <
'0') || (strValue[0] >
'9')))
254 if (field == sfTransactionType)
262 name = &sfTransaction;
264 else if (field == sfLedgerEntryType)
272 name = &sfLedgerEntry;
295template <
class STResult,
class Integer = std::u
int32_t>
309 if (value.isString())
311 if (field == sfPermissionValue)
314 auto const granularPermission =
316 if (granularPermission)
372 switch (field.fieldType)
379 if (value.isString())
383 if (!strValue.
empty() && ((strValue[0] <
'0') || (strValue[0] >
'9')))
385 if (field == sfTransactionResult)
400 error =
badType(jsonName, fieldName);
410 else if (value.isInt())
412 if (value.asInt() < kMinValue || value.asInt() > kMaxValue)
421 else if (value.isUInt())
423 if (value.asUInt() > kMaxValue)
434 error =
badType(jsonName, fieldName);
462 if (value.isString())
464 auto const str = value.asString();
472 str.data(), str.data() + str.size(), val, useBase10 ? 10 : 16);
474 if (ec !=
std::errc() || (p != str.data() + str.size()))
479 else if (value.isInt())
484 else if (value.isUInt())
491 error =
badType(jsonName, fieldName);
504 if (!value.isString())
506 error =
badType(jsonName, fieldName);
512 if (
auto const s = value.asString(); !num.
parseHex(s))
528 if (!value.isString())
530 error =
badType(jsonName, fieldName);
536 if (
auto const s = value.asString(); !num.
parseHex(s))
552 if (!value.isString())
554 error =
badType(jsonName, fieldName);
560 if (
auto const s = value.asString(); !num.
parseHex(s))
576 if (!value.isString())
578 error =
badType(jsonName, fieldName);
584 if (
auto const s = value.asString(); !num.
parseHex(s))
602 if (value.isString())
607 else if (value.isInt())
615 else if (value.isUInt())
617 auto const uintValue = value.asUInt();
628 error =
badType(jsonName, fieldName);
641 if (!value.isString())
643 error =
badType(jsonName, fieldName);
649 if (
auto vBlob =
strUnHex(value.asString()))
693 if (not value.isArrayOrNull())
708 for (
json::UInt i = 0; value.isValidIndex(i); ++i)
711 if (!s.
parseHex(value[i].asString()))
726 if (not value.isArrayOrNull())
742 for (
json::UInt i = 0; value.isValidIndex(i); ++i)
746 if (not value[i].isArrayOrNull())
749 ss << fieldName <<
"[" << i <<
"]";
757 ss << fieldName <<
"[" << i <<
"]";
762 for (
json::UInt j = 0; value[i].isValidIndex(j); ++j)
765 ss << fieldName <<
"[" << i <<
"][" << j <<
"]";
779 if (pathEl.
isMember(jss::currency) && pathEl.
isMember(jss::mpt_issuance_id))
785 bool const isMPT = pathEl.
isMember(jss::mpt_issuance_id);
786 auto const assetName = isMPT ? jss::mpt_issuance_id : jss::currency;
790 bool hasAsset =
false;
794 if (!account && !asset && !issuer)
803 if (!account.isString())
811 if (!uAccount.
parseHex(account.asString()))
816 error =
invalidData(elementName, jss::account.cStr());
839 error =
invalidData(elementName, assetName.cStr());
844 error =
invalidData(elementName, jss::account.cStr());
856 error =
invalidData(elementName, assetName.cStr());
878 error =
invalidData(elementName, jss::issuer.cStr());
886 error =
invalidData(elementName, jss::issuer.cStr());
891 p.
emplaceBack(uAccount, uAsset, uIssuer, hasAsset);
907 if (!value.isString())
909 error =
badType(jsonName, fieldName);
917 if (
AccountID account; account.parseHex(strValue))
946 case STI_XCHAIN_BRIDGE:
971 error =
badType(jsonName, fieldName);
995 if (not
json.isObjectOrNull())
1004 return std::nullopt;
1011 for (
auto const& fieldName :
json.getMemberNames())
1019 return std::nullopt;
1022 switch (field.fieldType)
1026 case STI_TRANSACTION:
1027 case STI_LEDGERENTRY:
1028 case STI_VALIDATION:
1029 if (!value.isObject())
1032 return std::nullopt;
1038 parseObject(jsonName +
"." + fieldName, value, field, depth + 1, error);
1040 return std::nullopt;
1041 data.emplaceBack(std::move(*ret));
1046 return std::nullopt;
1056 parseArray(jsonName +
"." + fieldName, value, field, depth + 1, error);
1057 if (!array.has_value())
1058 return std::nullopt;
1059 data.emplaceBack(std::move(*array));
1064 return std::nullopt;
1071 auto leaf =
parseLeaf(jsonName, fieldName, &inName, value, error);
1074 return std::nullopt;
1076 data.emplaceBack(std::move(*leaf));
1084 data.applyTemplateFromSField(inName);
1097 return std::nullopt;
1108 if (not
json.isArrayOrNull())
1111 return std::nullopt;
1117 return std::nullopt;
1123 return std::nullopt;
1132 bool const isObjectOrNull(
json[i].isObjectOrNull());
1133 bool const singleKey(isObjectOrNull ?
json[i].size() == 1 :
true);
1135 if (!isObjectOrNull || !singleKey)
1139 return std::nullopt;
1150 return std::nullopt;
1156 ss << jsonName <<
"." <<
"[" << i <<
"]." << memberName;
1158 auto ret =
parseObject(ss.
str(), objectFields, nameField, depth + 1, error);
1162 error[
"error_message"] =
"Error at '" + ss.
str() +
"'. " + errMsg;
1163 return std::nullopt;
1166 if (ret->getFName().fieldType != STI_OBJECT)
1168 ss <<
"Field type: " << ret->getFName().fieldType <<
" ";
1170 return std::nullopt;
1181 return std::nullopt;
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
std::optional< std::uint32_t > getGranularValue(std::string const &name) const
static Permission const & getInstance()
static SField const & getField(int fieldCode)
std::string const & getName() const
static constexpr auto kSmdBaseTen
void pushBack(STObject const &object)
json::Value error
On failure, an appropriate set of error values.
STParsedJSONObject()=delete
void pushBack(STPath const &e)
void emplaceBack(Args &&... args)
void pushBack(uint256 const &v)
Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
JSON (JavaScript Object Notation).
json::Value makeError(ErrorCodeI code)
Returns a new json object that reflects the error code.
static std::optional< detail::STVar > parseUnsigned(SField const &field, std::string const &jsonName, std::string const &fieldName, SField const *name, json::Value const &value, json::Value &error)
static json::Value stringExpected(std::string const &object, std::string const &field)
static json::Value invalidData(std::string const &object, std::string const &field)
static json::Value tooDeep(std::string const &object)
static json::Value notAnArray(std::string const &object)
static std::optional< detail::STVar > parseLeaf(std::string const &jsonName, std::string const &fieldName, SField const *name, json::Value const &value, json::Value &error)
static std::optional< STObject > parseObject(std::string const &jsonName, json::Value const &json, SField const &inName, int depth, json::Value &error)
static json::Value templateMismatch(SField const &sField)
static std::optional< detail::STVar > parseArray(std::string const &jsonName, json::Value const &json, SField const &inName, int depth, json::Value &error)
static json::Value arrayTooBig(std::string const &object, std::string const &field)
static json::Value nonObjectInArray(std::string const &item, json::UInt index)
constexpr std::enable_if_t< std::is_unsigned_v< U > &&std::is_signed_v< S >, U > toUnsigned(S value)
static std::string makeName(std::string const &object, std::string const &field)
static json::Value singletonExpected(std::string const &object, unsigned int index)
static std::optional< detail::STVar > parseUInt16(SField const &field, std::string const &jsonName, std::string const &fieldName, SField const *name, json::Value const &value, json::Value &error)
static json::Value badType(std::string const &object, std::string const &field)
static json::Value arrayExpected(std::string const &object, std::string const &field)
static json::Value outOfRange(std::string const &object, std::string const &field)
static json::Value notAnObject(std::string const &object, std::string const &field)
static json::Value unknownField(std::string const &object, std::string const &field)
static std::optional< detail::STVar > parseUInt32(SField const &field, std::string const &jsonName, std::string const &fieldName, SField const *name, json::Value const &value, json::Value &error)
STVar makeStvar(Args &&... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue issueFromJson(json::Value const &v)
STCurrency currencyFromJson(SField const &name, json::Value const &v)
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safeCast(Src s) noexcept
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
bool toCurrency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
AccountID getMPTIssuer(MPTID const &mptid)
constexpr std::size_t kMaxParsedJsonDepth
Maximum JSON object nesting depth permitted during parsing.
constexpr std::size_t kMaxParsedJsonArraySize
Maximum number of elements permitted in any JSON array field during parsing.
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
STAmount amountFromJson(SField const &name, json::Value const &v)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
constexpr TERUnderlyingType TERtoInt(TELcodes v)
STNumber numberFromJson(SField const &field, json::Value const &value)
std::optional< TER > transCode(std::string const &token)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)