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>
59 return static_cast<U
>(value);
62template <
typename U1,
typename U2>
69 return static_cast<U1
>(value);
157 "Field '" +
makeName(
object, field) +
"' exceeds allowed JSON array size of " +
180 "]' must be an object with a single key/object value.");
188 "Object '" + sField.
getName() +
"' contents did not meet requirements for that type.");
197 " is not an object. Arrays may only contain objects.");
201template <
class STResult,
class Integer>
215 if (value.isString())
222 else if (value.isInt())
227 else if (value.isUInt())
234 error =
badType(jsonName, fieldName);
247template <
class STResult,
class Integer = std::u
int16_t>
261 if (value.isString())
265 if (!strValue.
empty() && ((strValue[0] <
'0') || (strValue[0] >
'9')))
267 if (field == sfTransactionType)
275 name = &sfTransaction;
277 else if (field == sfLedgerEntryType)
285 name = &sfLedgerEntry;
308template <
class STResult,
class Integer = std::u
int32_t>
322 if (value.isString())
324 if (field == sfPermissionValue)
327 auto const granularPermission =
329 if (granularPermission)
385 switch (field.fieldType)
392 if (value.isString())
396 if (!strValue.
empty() && ((strValue[0] <
'0') || (strValue[0] >
'9')))
398 if (field == sfTransactionResult)
413 error =
badType(jsonName, fieldName);
423 else if (value.isInt())
425 if (value.asInt() < kMinValue || value.asInt() > kMaxValue)
434 else if (value.isUInt())
436 if (value.asUInt() > kMaxValue)
447 error =
badType(jsonName, fieldName);
475 if (value.isString())
477 auto const str = value.asString();
485 str.data(), str.data() + str.size(), val, useBase10 ? 10 : 16);
487 if (ec !=
std::errc() || (p != str.data() + str.size()))
492 else if (value.isInt())
497 else if (value.isUInt())
504 error =
badType(jsonName, fieldName);
517 if (!value.isString())
519 error =
badType(jsonName, fieldName);
525 if (
auto const s = value.asString(); !num.
parseHex(s))
541 if (!value.isString())
543 error =
badType(jsonName, fieldName);
549 if (
auto const s = value.asString(); !num.
parseHex(s))
565 if (!value.isString())
567 error =
badType(jsonName, fieldName);
573 if (
auto const s = value.asString(); !num.
parseHex(s))
589 if (!value.isString())
591 error =
badType(jsonName, fieldName);
597 if (
auto const s = value.asString(); !num.
parseHex(s))
615 if (value.isString())
620 else if (value.isInt())
628 else if (value.isUInt())
630 auto const uintValue = value.asUInt();
641 error =
badType(jsonName, fieldName);
654 if (!value.isString())
656 error =
badType(jsonName, fieldName);
662 if (
auto vBlob =
strUnHex(value.asString()))
706 if (not value.isArrayOrNull())
721 for (
json::UInt i = 0; value.isValidIndex(i); ++i)
724 if (!s.
parseHex(value[i].asString()))
739 if (not value.isArrayOrNull())
755 for (
json::UInt i = 0; value.isValidIndex(i); ++i)
759 if (not value[i].isArrayOrNull())
762 ss << fieldName <<
"[" << i <<
"]";
770 ss << fieldName <<
"[" << i <<
"]";
775 for (
json::UInt j = 0; value[i].isValidIndex(j); ++j)
778 ss << fieldName <<
"[" << i <<
"][" << j <<
"]";
792 if (pathEl.
isMember(jss::currency) && pathEl.
isMember(jss::mpt_issuance_id))
798 bool const isMPT = pathEl.
isMember(jss::mpt_issuance_id);
799 auto const assetName = isMPT ? jss::mpt_issuance_id : jss::currency;
803 bool hasAsset =
false;
807 if (!account && !asset && !issuer)
816 if (!account.isString())
824 if (!uAccount.
parseHex(account.asString()))
829 error =
invalidData(elementName, jss::account.cStr());
852 error =
invalidData(elementName, assetName.cStr());
857 error =
invalidData(elementName, jss::account.cStr());
869 error =
invalidData(elementName, assetName.cStr());
891 error =
invalidData(elementName, jss::issuer.cStr());
899 error =
invalidData(elementName, jss::issuer.cStr());
904 p.
emplaceBack(uAccount, uAsset, uIssuer, hasAsset);
920 if (!value.isString())
922 error =
badType(jsonName, fieldName);
930 if (
AccountID account; account.parseHex(strValue))
959 case STI_XCHAIN_BRIDGE:
984 error =
badType(jsonName, fieldName);
1008 if (not
json.isObjectOrNull())
1011 return std::nullopt;
1017 return std::nullopt;
1024 for (
auto const& fieldName :
json.getMemberNames())
1032 return std::nullopt;
1035 switch (field.fieldType)
1039 case STI_TRANSACTION:
1040 case STI_LEDGERENTRY:
1041 case STI_VALIDATION:
1042 if (!value.isObject())
1045 return std::nullopt;
1051 joinName(jsonName, fieldName), value, field, depth + 1, error);
1053 return std::nullopt;
1054 data.emplaceBack(std::move(*ret));
1059 return std::nullopt;
1069 joinName(jsonName, fieldName), value, field, depth + 1, error);
1070 if (!array.has_value())
1071 return std::nullopt;
1072 data.emplaceBack(std::move(*array));
1077 return std::nullopt;
1084 auto leaf =
parseLeaf(jsonName, fieldName, &inName, value, error);
1087 return std::nullopt;
1089 data.emplaceBack(std::move(*leaf));
1097 data.applyTemplateFromSField(inName);
1110 return std::nullopt;
1121 if (not
json.isArrayOrNull())
1124 return std::nullopt;
1130 return std::nullopt;
1136 return std::nullopt;
1145 bool const isObjectOrNull(
json[i].isObjectOrNull());
1146 bool const singleKey(isObjectOrNull ?
json[i].size() == 1 :
true);
1148 if (!isObjectOrNull || !singleKey)
1152 return std::nullopt;
1163 return std::nullopt;
1169 ss << jsonName <<
"." <<
"[" << i <<
"]." << memberName;
1171 auto ret =
parseObject(ss.
str(), objectFields, nameField, depth + 1, error);
1175 error[
"error_message"] =
"Error at '" + ss.
str() +
"'. " + errMsg;
1176 return std::nullopt;
1179 if (ret->getFName().fieldType != STI_OBJECT)
1181 ss <<
"Field type: " << ret->getFName().fieldType <<
" ";
1183 return std::nullopt;
1194 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)
constexpr Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
JSON (JavaScript Object Notation).
STVar makeStvar(Args &&... args)
json::Value makeError(ErrorCodeI code)
Returns a new json object that reflects the error code.
static std::string joinName(std::string const &jsonName, std::string const &fieldName)
static json::Value outOfRange(std::string const &object, std::string const &field)
static std::string makeName(std::string const &object, std::string const &field)
static json::Value stringExpected(std::string const &object, std::string const &field)
static json::Value arrayExpected(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)
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 invalidData(std::string const &object, std::string const &field)
static json::Value tooDeep(std::string const &object)
static json::Value notAnObject(std::string const &object, std::string const &field)
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 unknownField(std::string const &object, std::string const &field)
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)
constexpr U toUnsigned(S value)
static std::optional< STObject > parseObject(std::string const &jsonName, json::Value const &json, SField const &inName, int depth, json::Value &error)
static json::Value singletonExpected(std::string const &object, unsigned int index)
static json::Value templateMismatch(SField const &sField)
static json::Value notAnArray(std::string const &object)
static json::Value arrayTooBig(std::string const &object, std::string const &field)
static json::Value badType(std::string const &object, std::string const &field)
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 json::Value nonObjectInArray(std::string const &item, json::UInt index)
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.
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.
constexpr Dest safeCast(Src s) noexcept
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)