xrpld
Loading...
Searching...
No Matches
STParsedJSON.cpp
1#include <xrpl/protocol/STParsedJSON.h>
2
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>
35
36#include <charconv>
37#include <cstdint>
38#include <exception>
39#include <iostream>
40#include <limits>
41#include <optional>
42#include <sstream>
43#include <stdexcept>
44#include <string>
45#include <system_error>
46#include <type_traits>
47#include <utility>
48
49namespace xrpl {
50
52template <typename U, typename S>
54toUnsigned(S value)
55{
56 if (value < 0 || std::numeric_limits<U>::max() < value)
57 Throw<std::runtime_error>("Value out of range");
58 return static_cast<U>(value);
59}
60
61template <typename U1, typename U2>
63toUnsigned(U2 value)
64{
65 if (std::numeric_limits<U1>::max() < value)
66 Throw<std::runtime_error>("Value out of range");
67 return static_cast<U1>(value);
68}
69
70// LCOV_EXCL_START
71static inline std::string
72makeName(std::string const& object, std::string const& field)
73{
74 if (field.empty())
75 return object;
76
77 return object + "." + field;
78}
79
80static inline json::Value
81notAnObject(std::string const& object, std::string const& field)
82{
83 return RPC::makeError(
84 RpcInvalidParams, "Field '" + makeName(object, field) + "' is not a JSON object.");
85}
86
87static inline json::Value
89{
90 return notAnObject(object, "");
91}
92
93static inline json::Value
94notAnArray(std::string const& object)
95{
96 return RPC::makeError(RpcInvalidParams, "Field '" + object + "' is not a JSON array.");
97}
98
99static inline json::Value
100unknownField(std::string const& object, std::string const& field)
101{
102 return RPC::makeError(RpcInvalidParams, "Field '" + makeName(object, field) + "' is unknown.");
103}
104
105static inline json::Value
106outOfRange(std::string const& object, std::string const& field)
107{
108 return RPC::makeError(
109 RpcInvalidParams, "Field '" + makeName(object, field) + "' is out of range.");
110}
111
112static inline json::Value
113badType(std::string const& object, std::string const& field)
114{
115 return RPC::makeError(
116 RpcInvalidParams, "Field '" + makeName(object, field) + "' has bad type.");
117}
118
119static inline json::Value
120invalidData(std::string const& object, std::string const& field)
121{
122 return RPC::makeError(
123 RpcInvalidParams, "Field '" + makeName(object, field) + "' has invalid data.");
124}
125
126static inline json::Value
128{
129 return invalidData(object, "");
130}
131
132static inline json::Value
133arrayExpected(std::string const& object, std::string const& field)
134{
135 return RPC::makeError(
136 RpcInvalidParams, "Field '" + makeName(object, field) + "' must be a JSON array.");
137}
138
139static inline json::Value
140arrayTooBig(std::string const& object, std::string const& field)
141{
142 return RPC::makeError(
144 "Field '" + makeName(object, field) + "' exceeds allowed JSON array size of " +
145 std::to_string(kMaxParsedJsonArraySize) + " elements per field.");
146}
147
148static inline json::Value
149stringExpected(std::string const& object, std::string const& field)
150{
151 return RPC::makeError(
152 RpcInvalidParams, "Field '" + makeName(object, field) + "' must be a string.");
153}
154
155static inline json::Value
156tooDeep(std::string const& object)
157{
158 return RPC::makeError(RpcInvalidParams, "Field '" + object + "' exceeds nesting depth limit.");
159}
160
161static inline json::Value
162singletonExpected(std::string const& object, unsigned int index)
163{
164 return RPC::makeError(
166 "Field '" + object + "[" + std::to_string(index) +
167 "]' must be an object with a single key/object value.");
168}
169
170static inline json::Value
172{
173 return RPC::makeError(
175 "Object '" + sField.getName() + "' contents did not meet requirements for that type.");
176}
177
178static inline json::Value
180{
181 return RPC::makeError(
183 "Item '" + item + "' at index " + std::to_string(index) +
184 " is not an object. Arrays may only contain objects.");
185}
186// LCOV_EXCL_STOP
187
188template <class STResult, class Integer>
191 SField const& field,
192 std::string const& jsonName,
193 std::string const& fieldName,
194 SField const* name,
195 json::Value const& value,
196 json::Value& error)
197{
199
200 try
201 {
202 if (value.isString())
203 {
205 field,
207 beast::lexicalCastThrow<Integer>(value.asString())));
208 }
209 else if (value.isInt())
210 {
212 field, toUnsigned<typename STResult::value_type>(value.asInt()));
213 }
214 else if (value.isUInt())
215 {
217 field, toUnsigned<typename STResult::value_type>(value.asUInt()));
218 }
219 else
220 {
221 error = badType(jsonName, fieldName);
222 return ret;
223 }
224 }
225 catch (std::exception const&)
226 {
227 error = invalidData(jsonName, fieldName);
228 return ret;
229 }
230
231 return ret;
232}
233
234template <class STResult, class Integer = std::uint16_t>
237 SField const& field,
238 std::string const& jsonName,
239 std::string const& fieldName,
240 SField const* name,
241 json::Value const& value,
242 json::Value& error)
243{
245
246 try
247 {
248 if (value.isString())
249 {
250 std::string const strValue = value.asString();
251
252 if (!strValue.empty() && ((strValue[0] < '0') || (strValue[0] > '9')))
253 {
254 if (field == sfTransactionType)
255 {
257 field,
258 safeCast<typename STResult::value_type>(static_cast<Integer>(
259 TxFormats::getInstance().findTypeByName(strValue))));
260
261 if (*name == sfGeneric)
262 name = &sfTransaction;
263 }
264 else if (field == sfLedgerEntryType)
265 {
267 field,
268 safeCast<typename STResult::value_type>(static_cast<Integer>(
269 LedgerFormats::getInstance().findTypeByName(strValue))));
270
271 if (*name == sfGeneric)
272 name = &sfLedgerEntry;
273 }
274 else
275 {
276 error = invalidData(jsonName, fieldName);
277 return ret;
278 }
279 }
280 }
281 if (!ret)
282 {
283 return parseUnsigned<STResult, Integer>(field, jsonName, fieldName, name, value, error);
284 }
285 }
286 catch (std::exception const&)
287 {
288 error = invalidData(jsonName, fieldName);
289 return ret;
290 }
291
292 return ret;
293}
294
295template <class STResult, class Integer = std::uint32_t>
298 SField const& field,
299 std::string const& jsonName,
300 std::string const& fieldName,
301 SField const* name,
302 json::Value const& value,
303 json::Value& error)
304{
306
307 try
308 {
309 if (value.isString())
310 {
311 if (field == sfPermissionValue)
312 {
313 std::string const strValue = value.asString();
314 auto const granularPermission =
316 if (granularPermission)
317 {
318 ret = detail::makeStvar<STResult>(field, *granularPermission);
319 }
320 else
321 {
322 auto const& txType = TxFormats::getInstance().findTypeByName(strValue);
324 field, Permission::getInstance().txToPermissionType(txType));
325 }
326 }
327 else
328 {
330 field,
332 beast::lexicalCastThrow<Integer>(value.asString())));
333 }
334 }
335 if (!ret)
336 {
337 return parseUnsigned<STResult, Integer>(field, jsonName, fieldName, name, value, error);
338 }
339 }
340 catch (std::exception const&)
341 {
342 error = invalidData(jsonName, fieldName);
343 return ret;
344 }
345
346 return ret;
347}
348
349// This function is used by parseObject to parse any JSON type that doesn't
350// recurse. Everything represented here is a leaf-type.
353 std::string const& jsonName,
354 std::string const& fieldName,
355 SField const* name,
356 json::Value const& value,
357 json::Value& error)
358{
360
361 auto const& field = SField::getField(fieldName);
362
363 // checked in parseObject
364 if (field == sfInvalid)
365 {
366 // LCOV_EXCL_START
367 error = unknownField(jsonName, fieldName);
368 return ret;
369 // LCOV_EXCL_STOP
370 }
371
372 switch (field.fieldType)
373 {
374 case STI_UINT8:
375 try
376 {
377 constexpr auto kMinValue = std::numeric_limits<std::uint8_t>::min();
378 constexpr auto kMaxValue = std::numeric_limits<std::uint8_t>::max();
379 if (value.isString())
380 {
381 std::string const strValue = value.asString();
382
383 if (!strValue.empty() && ((strValue[0] < '0') || (strValue[0] > '9')))
384 {
385 if (field == sfTransactionResult)
386 {
387 auto ter = transCode(strValue);
388
389 if (!ter || TERtoInt(*ter) < kMinValue || TERtoInt(*ter) > kMaxValue)
390 {
391 error = outOfRange(jsonName, fieldName);
392 return ret;
393 }
394
396 field, static_cast<std::uint8_t>(TERtoInt(*ter)));
397 }
398 else
399 {
400 error = badType(jsonName, fieldName);
401 return ret;
402 }
403 }
404 else
405 {
408 }
409 }
410 else if (value.isInt())
411 {
412 if (value.asInt() < kMinValue || value.asInt() > kMaxValue)
413 {
414 error = outOfRange(jsonName, fieldName);
415 return ret;
416 }
417
418 ret =
419 detail::makeStvar<STUInt8>(field, static_cast<std::uint8_t>(value.asInt()));
420 }
421 else if (value.isUInt())
422 {
423 if (value.asUInt() > kMaxValue)
424 {
425 error = outOfRange(jsonName, fieldName);
426 return ret;
427 }
428
430 field, static_cast<std::uint8_t>(value.asUInt()));
431 }
432 else
433 {
434 error = badType(jsonName, fieldName);
435 return ret;
436 }
437 }
438 catch (std::exception const&)
439 {
440 error = invalidData(jsonName, fieldName);
441 return ret;
442 }
443 break;
444
445 case STI_UINT16:
446 ret = parseUInt16<STUInt16>(field, jsonName, fieldName, name, value, error);
447 if (!ret)
448 return ret;
449
450 break;
451
452 case STI_UINT32:
453 ret = parseUInt32<STUInt32>(field, jsonName, fieldName, name, value, error);
454 if (!ret)
455 return ret;
456
457 break;
458
459 case STI_UINT64:
460 try
461 {
462 if (value.isString())
463 {
464 auto const str = value.asString();
465
466 std::uint64_t val = 0;
467
468 bool const useBase10 = field.shouldMeta(SField::kSmdBaseTen);
469
470 // if the field is amount, serialize as base 10
471 auto [p, ec] = std::from_chars(
472 str.data(), str.data() + str.size(), val, useBase10 ? 10 : 16);
473
474 if (ec != std::errc() || (p != str.data() + str.size()))
475 Throw<std::invalid_argument>("invalid data");
476
477 ret = detail::makeStvar<STUInt64>(field, val);
478 }
479 else if (value.isInt())
480 {
482 field, toUnsigned<std::uint64_t>(value.asInt()));
483 }
484 else if (value.isUInt())
485 {
486 ret =
488 }
489 else
490 {
491 error = badType(jsonName, fieldName);
492 return ret;
493 }
494 }
495 catch (std::exception const&)
496 {
497 error = invalidData(jsonName, fieldName);
498 return ret;
499 }
500
501 break;
502
503 case STI_UINT128: {
504 if (!value.isString())
505 {
506 error = badType(jsonName, fieldName);
507 return ret;
508 }
509
510 uint128 num;
511
512 if (auto const s = value.asString(); !num.parseHex(s))
513 {
514 if (!s.empty())
515 {
516 error = invalidData(jsonName, fieldName);
517 return ret;
518 }
519
520 num.zero();
521 }
522
523 ret = detail::makeStvar<STUInt128>(field, num);
524 break;
525 }
526
527 case STI_UINT160: {
528 if (!value.isString())
529 {
530 error = badType(jsonName, fieldName);
531 return ret;
532 }
533
534 uint160 num;
535
536 if (auto const s = value.asString(); !num.parseHex(s))
537 {
538 if (!s.empty())
539 {
540 error = invalidData(jsonName, fieldName);
541 return ret;
542 }
543
544 num.zero();
545 }
546
547 ret = detail::makeStvar<STUInt160>(field, num);
548 break;
549 }
550
551 case STI_UINT192: {
552 if (!value.isString())
553 {
554 error = badType(jsonName, fieldName);
555 return ret;
556 }
557
558 uint192 num;
559
560 if (auto const s = value.asString(); !num.parseHex(s))
561 {
562 if (!s.empty())
563 {
564 error = invalidData(jsonName, fieldName);
565 return ret;
566 }
567
568 num.zero();
569 }
570
571 ret = detail::makeStvar<STUInt192>(field, num);
572 break;
573 }
574
575 case STI_UINT256: {
576 if (!value.isString())
577 {
578 error = badType(jsonName, fieldName);
579 return ret;
580 }
581
582 uint256 num;
583
584 if (auto const s = value.asString(); !num.parseHex(s))
585 {
586 if (!s.empty())
587 {
588 error = invalidData(jsonName, fieldName);
589 return ret;
590 }
591
592 num.zero();
593 }
594
595 ret = detail::makeStvar<STUInt256>(field, num);
596 break;
597 }
598
599 case STI_INT32:
600 try
601 {
602 if (value.isString())
603 {
605 field, beast::lexicalCastThrow<std::int32_t>(value.asString()));
606 }
607 else if (value.isInt())
608 {
609 // future-proofing - a static assert failure if the JSON
610 // library ever supports larger ints
611 // In such case, we will need additional bounds checks here
612 static_assert(std::is_same_v<decltype(value.asInt()), std::int32_t>);
613 ret = detail::makeStvar<STInt32>(field, value.asInt());
614 }
615 else if (value.isUInt())
616 {
617 auto const uintValue = value.asUInt();
618 if (uintValue >
620 {
621 error = outOfRange(jsonName, fieldName);
622 return ret;
623 }
624 ret = detail::makeStvar<STInt32>(field, static_cast<std::int32_t>(uintValue));
625 }
626 else
627 {
628 error = badType(jsonName, fieldName);
629 return ret;
630 }
631 }
632 catch (std::exception const&)
633 {
634 error = invalidData(jsonName, fieldName);
635 return ret;
636 }
637
638 break;
639
640 case STI_VL:
641 if (!value.isString())
642 {
643 error = badType(jsonName, fieldName);
644 return ret;
645 }
646
647 try
648 {
649 if (auto vBlob = strUnHex(value.asString()))
650 {
651 ret = detail::makeStvar<STBlob>(field, vBlob->data(), vBlob->size());
652 }
653 else
654 {
655 Throw<std::invalid_argument>("invalid data");
656 }
657 }
658 catch (std::exception const&)
659 {
660 error = invalidData(jsonName, fieldName);
661 return ret;
662 }
663
664 break;
665
666 case STI_AMOUNT:
667 try
668 {
669 ret = detail::makeStvar<STAmount>(amountFromJson(field, value));
670 }
671 catch (std::exception const&)
672 {
673 error = invalidData(jsonName, fieldName);
674 return ret;
675 }
676
677 break;
678
679 case STI_NUMBER:
680 try
681 {
682 ret = detail::makeStvar<STNumber>(numberFromJson(field, value));
683 }
684 catch (std::exception const&)
685 {
686 error = invalidData(jsonName, fieldName);
687 return ret;
688 }
689
690 break;
691
692 case STI_VECTOR256:
693 if (not value.isArrayOrNull())
694 {
695 error = arrayExpected(jsonName, fieldName);
696 return ret;
697 }
698
699 if (not value.isNull() and value.size() > kMaxParsedJsonArraySize)
700 {
701 error = arrayTooBig(jsonName, fieldName);
702 return ret;
703 }
704
705 try
706 {
707 STVector256 tail(field);
708 for (json::UInt i = 0; value.isValidIndex(i); ++i)
709 {
710 uint256 s;
711 if (!s.parseHex(value[i].asString()))
712 Throw<std::invalid_argument>("invalid data");
713 tail.pushBack(s);
714 }
715 ret = detail::makeStvar<STVector256>(std::move(tail));
716 }
717 catch (std::exception const&)
718 {
719 error = invalidData(jsonName, fieldName);
720 return ret;
721 }
722
723 break;
724
725 case STI_PATHSET:
726 if (not value.isArrayOrNull())
727 {
728 error = arrayExpected(jsonName, fieldName);
729 return ret;
730 }
731
732 if (not value.isNull() and value.size() > kMaxParsedJsonArraySize)
733 {
734 error = arrayTooBig(jsonName, fieldName);
735 return ret;
736 }
737
738 try
739 {
740 STPathSet tail(field);
741
742 for (json::UInt i = 0; value.isValidIndex(i); ++i)
743 {
744 STPath p;
745
746 if (not value[i].isArrayOrNull())
747 {
749 ss << fieldName << "[" << i << "]";
750 error = arrayExpected(jsonName, ss.str());
751 return ret;
752 }
753
754 if (not value[i].isNull() and value[i].size() > kMaxParsedJsonArraySize)
755 {
757 ss << fieldName << "[" << i << "]";
758 error = arrayTooBig(jsonName, ss.str());
759 return ret;
760 }
761
762 for (json::UInt j = 0; value[i].isValidIndex(j); ++j)
763 {
765 ss << fieldName << "[" << i << "][" << j << "]";
766 std::string const elementName(jsonName + "." + ss.str());
767
768 // each element in this path has some combination of
769 // account, asset, or issuer
770
771 json::Value pathEl = value[i][j];
772
773 if (!pathEl.isObject())
774 {
775 error = notAnObject(elementName);
776 return ret;
777 }
778
779 if (pathEl.isMember(jss::currency) && pathEl.isMember(jss::mpt_issuance_id))
780 {
781 error = RPC::makeError(RpcInvalidParams, "Invalid Asset.");
782 return ret;
783 }
784
785 bool const isMPT = pathEl.isMember(jss::mpt_issuance_id);
786 auto const assetName = isMPT ? jss::mpt_issuance_id : jss::currency;
787 json::Value const& account = pathEl[jss::account];
788 json::Value const& asset = pathEl[assetName];
789 json::Value const& issuer = pathEl[jss::issuer];
790 bool hasAsset = false;
791 AccountID uAccount, uIssuer;
792 PathAsset uAsset;
793
794 if (!account && !asset && !issuer)
795 {
796 error = invalidData(elementName);
797 return ret;
798 }
799
800 if (account)
801 {
802 // human account id
803 if (!account.isString())
804 {
805 error = stringExpected(elementName, jss::account.cStr());
806 return ret;
807 }
808
809 // If we have what looks like a 160-bit hex value,
810 // we set it, otherwise, we assume it's an AccountID
811 if (!uAccount.parseHex(account.asString()))
812 {
813 auto const a = parseBase58<AccountID>(account.asString());
814 if (!a)
815 {
816 error = invalidData(elementName, jss::account.cStr());
817 return ret;
818 }
819 uAccount = *a;
820 }
821 }
822
823 if (asset)
824 {
825 // human asset
826 if (!asset.isString())
827 {
828 error = stringExpected(elementName, assetName.cStr());
829 return ret;
830 }
831
832 hasAsset = true;
833
834 if (isMPT)
835 {
836 MPTID u;
837 if (!u.parseHex(asset.asString()))
838 {
839 error = invalidData(elementName, assetName.cStr());
840 return ret;
841 }
842 if (getMPTIssuer(u) == beast::kZero)
843 {
844 error = invalidData(elementName, jss::account.cStr());
845 return ret;
846 }
847 uAsset = u;
848 }
849 else
850 {
851 Currency currency;
852 if (!currency.parseHex(asset.asString()))
853 {
854 if (!toCurrency(currency, asset.asString()))
855 {
856 error = invalidData(elementName, assetName.cStr());
857 return ret;
858 }
859 }
860 uAsset = currency;
861 }
862 }
863
864 if (issuer)
865 {
866 // human account id
867 if (!issuer.isString())
868 {
869 error = stringExpected(elementName, jss::issuer.cStr());
870 return ret;
871 }
872
873 if (!uIssuer.parseHex(issuer.asString()))
874 {
875 auto const a = parseBase58<AccountID>(issuer.asString());
876 if (!a)
877 {
878 error = invalidData(elementName, jss::issuer.cStr());
879 return ret;
880 }
881 uIssuer = *a;
882 }
883
884 if (isMPT && uIssuer != getMPTIssuer(uAsset.get<MPTID>()))
885 {
886 error = invalidData(elementName, jss::issuer.cStr());
887 return ret;
888 }
889 }
890
891 p.emplaceBack(uAccount, uAsset, uIssuer, hasAsset);
892 }
893
894 tail.pushBack(p);
895 }
896 ret = detail::makeStvar<STPathSet>(std::move(tail));
897 }
898 catch (std::exception const&)
899 {
900 error = invalidData(jsonName, fieldName);
901 return ret;
902 }
903
904 break;
905
906 case STI_ACCOUNT: {
907 if (!value.isString())
908 {
909 error = badType(jsonName, fieldName);
910 return ret;
911 }
912
913 std::string const strValue = value.asString();
914
915 try
916 {
917 if (AccountID account; account.parseHex(strValue))
918 return detail::makeStvar<STAccount>(field, account);
919
920 if (auto result = parseBase58<AccountID>(strValue))
921 return detail::makeStvar<STAccount>(field, *result);
922
923 error = invalidData(jsonName, fieldName);
924 return ret;
925 }
926 catch (std::exception const&)
927 {
928 error = invalidData(jsonName, fieldName);
929 return ret;
930 }
931 }
932 break;
933
934 case STI_ISSUE:
935 try
936 {
937 ret = detail::makeStvar<STIssue>(issueFromJson(field, value));
938 }
939 catch (std::exception const&)
940 {
941 error = invalidData(jsonName, fieldName);
942 return ret;
943 }
944 break;
945
946 case STI_XCHAIN_BRIDGE:
947 try
948 {
950 }
951 catch (std::exception const&)
952 {
953 error = invalidData(jsonName, fieldName);
954 return ret;
955 }
956 break;
957
958 case STI_CURRENCY:
959 try
960 {
962 }
963 catch (std::exception const&)
964 {
965 error = invalidData(jsonName, fieldName);
966 return ret;
967 }
968 break;
969
970 default:
971 error = badType(jsonName, fieldName);
972 return ret;
973 }
974
975 return ret;
976}
977
978// Forward declaration since parseObject() and parseArray() call each other.
981 std::string const& jsonName,
982 json::Value const& json,
983 SField const& inName,
984 int depth,
985 json::Value& error);
986
989 std::string const& jsonName,
990 json::Value const& json,
991 SField const& inName,
992 int depth,
993 json::Value& error)
994{
995 if (not json.isObjectOrNull())
996 {
997 error = notAnObject(jsonName);
998 return std::nullopt;
999 }
1000
1001 if (depth > kMaxParsedJsonDepth)
1002 {
1003 error = tooDeep(jsonName);
1004 return std::nullopt;
1005 }
1006
1007 try
1008 {
1009 STObject data(inName);
1010
1011 for (auto const& fieldName : json.getMemberNames())
1012 {
1013 json::Value const& value = json[fieldName];
1014 auto const& field = SField::getField(fieldName);
1015
1016 if (field == sfInvalid)
1017 {
1018 error = unknownField(jsonName, fieldName);
1019 return std::nullopt;
1020 }
1021
1022 switch (field.fieldType)
1023 {
1024 // Object-style containers (which recurse).
1025 case STI_OBJECT:
1026 case STI_TRANSACTION:
1027 case STI_LEDGERENTRY:
1028 case STI_VALIDATION:
1029 if (!value.isObject())
1030 {
1031 error = notAnObject(jsonName, fieldName);
1032 return std::nullopt;
1033 }
1034
1035 try
1036 {
1037 auto ret =
1038 parseObject(jsonName + "." + fieldName, value, field, depth + 1, error);
1039 if (!ret)
1040 return std::nullopt;
1041 data.emplaceBack(std::move(*ret));
1042 }
1043 catch (std::exception const&)
1044 {
1045 error = invalidData(jsonName, fieldName);
1046 return std::nullopt;
1047 }
1048
1049 break;
1050
1051 // Array-style containers (which recurse).
1052 case STI_ARRAY:
1053 try
1054 {
1055 auto array =
1056 parseArray(jsonName + "." + fieldName, value, field, depth + 1, error);
1057 if (!array.has_value())
1058 return std::nullopt;
1059 data.emplaceBack(std::move(*array));
1060 }
1061 catch (std::exception const&)
1062 {
1063 error = invalidData(jsonName, fieldName);
1064 return std::nullopt;
1065 }
1066
1067 break;
1068
1069 // Everything else (types that don't recurse).
1070 default: {
1071 auto leaf = parseLeaf(jsonName, fieldName, &inName, value, error);
1072
1073 if (!leaf)
1074 return std::nullopt;
1075
1076 data.emplaceBack(std::move(*leaf));
1077 }
1078
1079 break;
1080 }
1081 }
1082
1083 // Some inner object types have templates. Attempt to apply that.
1084 data.applyTemplateFromSField(inName); // May throw
1085
1086 return data;
1087 }
1088 catch (STObject::FieldErr const& e)
1089 {
1090 std::cerr << "templateMismatch: " << e.what() << "\n";
1091 error = templateMismatch(inName);
1092 }
1093 catch (std::exception const&)
1094 {
1095 error = invalidData(jsonName);
1096 }
1097 return std::nullopt;
1098}
1099
1102 std::string const& jsonName,
1103 json::Value const& json,
1104 SField const& inName,
1105 int depth,
1106 json::Value& error)
1107{
1108 if (not json.isArrayOrNull())
1109 {
1110 error = notAnArray(jsonName);
1111 return std::nullopt;
1112 }
1113
1114 if (depth > kMaxParsedJsonDepth)
1115 {
1116 error = tooDeep(jsonName);
1117 return std::nullopt;
1118 }
1119
1120 if (not json.isNull() and json.size() > kMaxParsedJsonArraySize)
1121 {
1122 error = arrayTooBig(jsonName, "");
1123 return std::nullopt;
1124 }
1125
1126 try
1127 {
1128 STArray tail(inName);
1129
1130 for (json::UInt i = 0; json.isValidIndex(i); ++i)
1131 {
1132 bool const isObjectOrNull(json[i].isObjectOrNull());
1133 bool const singleKey(isObjectOrNull ? json[i].size() == 1 : true);
1134
1135 if (!isObjectOrNull || !singleKey)
1136 {
1137 // null values are !singleKey
1138 error = singletonExpected(jsonName, i);
1139 return std::nullopt;
1140 }
1141
1142 // TODO: There doesn't seem to be a nice way to get just the
1143 // first/only key in an object without copying all keys into a vector
1144 std::string const memberName(json[i].getMemberNames()[0]);
1145 auto const& nameField(SField::getField(memberName));
1146
1147 if (nameField == sfInvalid)
1148 {
1149 error = unknownField(jsonName, memberName);
1150 return std::nullopt;
1151 }
1152
1153 json::Value const objectFields(json[i][memberName]);
1154
1156 ss << jsonName << "." << "[" << i << "]." << memberName;
1157
1158 auto ret = parseObject(ss.str(), objectFields, nameField, depth + 1, error);
1159 if (!ret)
1160 {
1161 std::string const errMsg = error["error_message"].asString();
1162 error["error_message"] = "Error at '" + ss.str() + "'. " + errMsg;
1163 return std::nullopt;
1164 }
1165
1166 if (ret->getFName().fieldType != STI_OBJECT)
1167 {
1168 ss << "Field type: " << ret->getFName().fieldType << " ";
1169 error = nonObjectInArray(ss.str(), i);
1170 return std::nullopt;
1171 }
1172
1173 tail.pushBack(std::move(*ret));
1174 }
1175
1176 return detail::makeStvar<STArray>(std::move(tail));
1177 }
1178 catch (std::exception const&)
1179 {
1180 error = invalidData(jsonName);
1181 return std::nullopt;
1182 }
1183}
1184
1185} // namespace STParsedJSONDetail
1186
1187//------------------------------------------------------------------------------
1188
1190{
1191 using namespace STParsedJSONDetail;
1192 object = parseObject(name, json, sfGeneric, 0, error);
1193}
1194
1195} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
bool isObject() const
bool isString() const
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.
Definition base_uint.h:507
KeyType findTypeByName(std::string const &name) const
Retrieve the type for a format specified by name.
static LedgerFormats const & getInstance()
T const & get() const
std::optional< std::uint32_t > getGranularValue(std::string const &name) const
static Permission const & getInstance()
Identifies fields.
Definition SField.h:130
static SField const & getField(int fieldCode)
Definition SField.cpp:116
std::string const & getName() const
Definition SField.h:196
static constexpr auto kSmdBaseTen
Definition SField.h:138
void pushBack(STObject const &object)
Definition STArray.h:204
json::Value error
On failure, an appropriate set of error values.
void pushBack(STPath const &e)
Definition STPathSet.h:540
void emplaceBack(Args &&... args)
Definition STPathSet.h:443
void pushBack(uint256 const &v)
static TxFormats const & getInstance()
Definition TxFormats.cpp:57
T empty(T... args)
T from_chars(T... args)
T is_same_v
T is_signed_v
T is_unsigned_v
T max(T... args)
T min(T... args)
Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
JSON (JavaScript Object Notation).
Definition json_errors.h:5
unsigned int UInt
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)
Definition STVar.h:141
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
BaseUInt< 192 > uint192
Definition base_uint.h:563
Issue issueFromJson(json::Value const &v)
Definition Issue.cpp:89
@ RpcInvalidParams
Definition ErrorCodes.h:66
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
Definition safe_cast.h:21
SField const sfGeneric
BaseUInt< 128 > uint128
Definition base_uint.h:560
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Definition UintTypes.h:36
bool toCurrency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition UintTypes.cpp:65
AccountID getMPTIssuer(MPTID const &mptid)
Definition MPTIssue.h:84
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< 160 > uint160
Definition base_uint.h:561
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
Definition UintTypes.h:44
STAmount amountFromJson(SField const &name, json::Value const &v)
Definition STAmount.cpp:916
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
constexpr TERUnderlyingType TERtoInt(TELcodes v)
Definition TER.h:373
STNumber numberFromJson(SField const &field, json::Value const &value)
Definition STNumber.cpp:222
SField const sfInvalid
std::optional< TER > transCode(std::string const &token)
Definition TER.cpp:265
BaseUInt< 256 > uint256
Definition base_uint.h:562
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:49
T str(T... args)
T to_string(T... args)
T what(T... args)