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