rippled
STParsedJSON.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/StringUtilities.h>
21 #include <ripple/basics/contract.h>
22 #include <ripple/basics/safe_cast.h>
23 #include <ripple/beast/core/LexicalCast.h>
24 #include <ripple/protocol/ErrorCodes.h>
25 #include <ripple/protocol/LedgerFormats.h>
26 #include <ripple/protocol/SField.h>
27 #include <ripple/protocol/STAccount.h>
28 #include <ripple/protocol/STAmount.h>
29 #include <ripple/protocol/STArray.h>
30 #include <ripple/protocol/STBitString.h>
31 #include <ripple/protocol/STBlob.h>
32 #include <ripple/protocol/STInteger.h>
33 #include <ripple/protocol/STIssue.h>
34 #include <ripple/protocol/STParsedJSON.h>
35 #include <ripple/protocol/STPathSet.h>
36 #include <ripple/protocol/STVector256.h>
37 #include <ripple/protocol/STXChainBridge.h>
38 #include <ripple/protocol/TER.h>
39 #include <ripple/protocol/TxFormats.h>
40 #include <ripple/protocol/UintTypes.h>
41 #include <ripple/protocol/XChainAttestations.h>
42 #include <ripple/protocol/impl/STVar.h>
43 
44 #include <cassert>
45 #include <charconv>
46 #include <memory>
47 
48 namespace ripple {
49 
50 namespace STParsedJSONDetail {
51 template <typename U, typename S>
52 constexpr std::
53  enable_if_t<std::is_unsigned<U>::value && std::is_signed<S>::value, U>
54  to_unsigned(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 
61 template <typename U1, typename U2>
62 constexpr std::
63  enable_if_t<std::is_unsigned<U1>::value && std::is_unsigned<U2>::value, U1>
64  to_unsigned(U2 value)
65 {
66  if (std::numeric_limits<U1>::max() < value)
67  Throw<std::runtime_error>("Value out of range");
68  return static_cast<U1>(value);
69 }
70 
71 static std::string
72 make_name(std::string const& object, std::string const& field)
73 {
74  if (field.empty())
75  return object;
76 
77  return object + "." + field;
78 }
79 
80 static Json::Value
81 not_an_object(std::string const& object, std::string const& field)
82 {
83  return RPC::make_error(
85  "Field '" + make_name(object, field) + "' is not a JSON object.");
86 }
87 
88 static Json::Value
89 not_an_object(std::string const& object)
90 {
91  return not_an_object(object, "");
92 }
93 
94 static Json::Value
95 not_an_array(std::string const& object)
96 {
97  return RPC::make_error(
98  rpcINVALID_PARAMS, "Field '" + object + "' is not a JSON array.");
99 }
100 
101 static Json::Value
102 unknown_field(std::string const& object, std::string const& field)
103 {
104  return RPC::make_error(
106  "Field '" + make_name(object, field) + "' is unknown.");
107 }
108 
109 static Json::Value
110 out_of_range(std::string const& object, std::string const& field)
111 {
112  return RPC::make_error(
114  "Field '" + make_name(object, field) + "' is out of range.");
115 }
116 
117 static Json::Value
118 bad_type(std::string const& object, std::string const& field)
119 {
120  return RPC::make_error(
122  "Field '" + make_name(object, field) + "' has bad type.");
123 }
124 
125 static Json::Value
126 invalid_data(std::string const& object, std::string const& field)
127 {
128  return RPC::make_error(
130  "Field '" + make_name(object, field) + "' has invalid data.");
131 }
132 
133 static Json::Value
134 invalid_data(std::string const& object)
135 {
136  return invalid_data(object, "");
137 }
138 
139 static Json::Value
140 array_expected(std::string const& object, std::string const& field)
141 {
142  return RPC::make_error(
144  "Field '" + make_name(object, field) + "' must be a JSON array.");
145 }
146 
147 static Json::Value
148 string_expected(std::string const& object, std::string const& field)
149 {
150  return RPC::make_error(
152  "Field '" + make_name(object, field) + "' must be a string.");
153 }
154 
155 static Json::Value
156 too_deep(std::string const& object)
157 {
158  return RPC::make_error(
160  "Field '" + object + "' exceeds nesting depth limit.");
161 }
162 
163 static Json::Value
164 singleton_expected(std::string const& object, unsigned int index)
165 {
166  return RPC::make_error(
168  "Field '" + object + "[" + std::to_string(index) +
169  "]' must be an object with a single key/object value.");
170 }
171 
172 static Json::Value
173 template_mismatch(SField const& sField)
174 {
175  return RPC::make_error(
177  "Object '" + sField.getName() +
178  "' contents did not meet requirements for that type.");
179 }
180 
181 static Json::Value
183 {
184  return RPC::make_error(
186  "Item '" + item + "' at index " + std::to_string(index) +
187  " is not an object. Arrays may only contain objects.");
188 }
189 
190 // This function is used by parseObject to parse any JSON type that doesn't
191 // recurse. Everything represented here is a leaf-type.
194  std::string const& json_name,
195  std::string const& fieldName,
196  SField const* name,
197  Json::Value const& value,
198  Json::Value& error)
199 {
201 
202  auto const& field = SField::getField(fieldName);
203 
204  if (field == sfInvalid)
205  {
206  error = unknown_field(json_name, fieldName);
207  return ret;
208  }
209 
210  switch (field.fieldType)
211  {
212  case STI_UINT8:
213  try
214  {
215  constexpr auto minValue =
217  constexpr auto maxValue =
219  if (value.isString())
220  {
221  std::string const strValue = value.asString();
222 
223  if (!strValue.empty() &&
224  ((strValue[0] < '0') || (strValue[0] > '9')))
225  {
226  if (field == sfTransactionResult)
227  {
228  auto ter = transCode(strValue);
229 
230  if (!ter || TERtoInt(*ter) < minValue ||
231  TERtoInt(*ter) > maxValue)
232  {
233  error = out_of_range(json_name, fieldName);
234  return ret;
235  }
236 
237  ret = detail::make_stvar<STUInt8>(
238  field,
239  static_cast<std::uint8_t>(TERtoInt(*ter)));
240  }
241  else
242  {
243  error = bad_type(json_name, fieldName);
244  return ret;
245  }
246  }
247  else
248  {
249  ret = detail::make_stvar<STUInt8>(
250  field,
251  beast::lexicalCastThrow<std::uint8_t>(strValue));
252  }
253  }
254  else if (value.isInt())
255  {
256  if (value.asInt() < minValue || value.asInt() > maxValue)
257  {
258  error = out_of_range(json_name, fieldName);
259  return ret;
260  }
261 
262  ret = detail::make_stvar<STUInt8>(
263  field, static_cast<std::uint8_t>(value.asInt()));
264  }
265  else if (value.isUInt())
266  {
267  if (value.asUInt() > maxValue)
268  {
269  error = out_of_range(json_name, fieldName);
270  return ret;
271  }
272 
273  ret = detail::make_stvar<STUInt8>(
274  field, static_cast<std::uint8_t>(value.asUInt()));
275  }
276  else
277  {
278  error = bad_type(json_name, fieldName);
279  return ret;
280  }
281  }
282  catch (std::exception const&)
283  {
284  error = invalid_data(json_name, fieldName);
285  return ret;
286  }
287  break;
288 
289  case STI_UINT16:
290  try
291  {
292  if (value.isString())
293  {
294  std::string const strValue = value.asString();
295 
296  if (!strValue.empty() &&
297  ((strValue[0] < '0') || (strValue[0] > '9')))
298  {
299  if (field == sfTransactionType)
300  {
301  ret = detail::make_stvar<STUInt16>(
302  field,
303  static_cast<std::uint16_t>(
304  TxFormats::getInstance().findTypeByName(
305  strValue)));
306 
307  if (*name == sfGeneric)
308  name = &sfTransaction;
309  }
310  else if (field == sfLedgerEntryType)
311  {
312  ret = detail::make_stvar<STUInt16>(
313  field,
314  static_cast<std::uint16_t>(
315  LedgerFormats::getInstance().findTypeByName(
316  strValue)));
317 
318  if (*name == sfGeneric)
319  name = &sfLedgerEntry;
320  }
321  else
322  {
323  error = invalid_data(json_name, fieldName);
324  return ret;
325  }
326  }
327  else
328  {
329  ret = detail::make_stvar<STUInt16>(
330  field,
331  beast::lexicalCastThrow<std::uint16_t>(strValue));
332  }
333  }
334  else if (value.isInt())
335  {
336  ret = detail::make_stvar<STUInt16>(
337  field, to_unsigned<std::uint16_t>(value.asInt()));
338  }
339  else if (value.isUInt())
340  {
341  ret = detail::make_stvar<STUInt16>(
342  field, to_unsigned<std::uint16_t>(value.asUInt()));
343  }
344  else
345  {
346  error = bad_type(json_name, fieldName);
347  return ret;
348  }
349  }
350  catch (std::exception const&)
351  {
352  error = invalid_data(json_name, fieldName);
353  return ret;
354  }
355 
356  break;
357 
358  case STI_UINT32:
359  try
360  {
361  if (value.isString())
362  {
363  ret = detail::make_stvar<STUInt32>(
364  field,
365  beast::lexicalCastThrow<std::uint32_t>(
366  value.asString()));
367  }
368  else if (value.isInt())
369  {
370  ret = detail::make_stvar<STUInt32>(
371  field, to_unsigned<std::uint32_t>(value.asInt()));
372  }
373  else if (value.isUInt())
374  {
375  ret = detail::make_stvar<STUInt32>(
376  field, safe_cast<std::uint32_t>(value.asUInt()));
377  }
378  else
379  {
380  error = bad_type(json_name, fieldName);
381  return ret;
382  }
383  }
384  catch (std::exception const&)
385  {
386  error = invalid_data(json_name, fieldName);
387  return ret;
388  }
389 
390  break;
391 
392  case STI_UINT64:
393  try
394  {
395  if (value.isString())
396  {
397  auto const str = value.asString();
398 
399  std::uint64_t val;
400 
401  auto [p, ec] = std::from_chars(
402  str.data(), str.data() + str.size(), val, 16);
403 
404  if (ec != std::errc() || (p != str.data() + str.size()))
405  Throw<std::invalid_argument>("invalid data");
406 
407  ret = detail::make_stvar<STUInt64>(field, val);
408  }
409  else if (value.isInt())
410  {
411  ret = detail::make_stvar<STUInt64>(
412  field, to_unsigned<std::uint64_t>(value.asInt()));
413  }
414  else if (value.isUInt())
415  {
416  ret = detail::make_stvar<STUInt64>(
417  field, safe_cast<std::uint64_t>(value.asUInt()));
418  }
419  else
420  {
421  error = bad_type(json_name, fieldName);
422  return ret;
423  }
424  }
425  catch (std::exception const&)
426  {
427  error = invalid_data(json_name, fieldName);
428  return ret;
429  }
430 
431  break;
432 
433  case STI_UINT128: {
434  if (!value.isString())
435  {
436  error = bad_type(json_name, fieldName);
437  return ret;
438  }
439 
440  uint128 num;
441 
442  if (auto const s = value.asString(); !num.parseHex(s))
443  {
444  if (!s.empty())
445  {
446  error = invalid_data(json_name, fieldName);
447  return ret;
448  }
449 
450  num.zero();
451  }
452 
453  ret = detail::make_stvar<STUInt128>(field, num);
454  break;
455  }
456 
457  case STI_UINT160: {
458  if (!value.isString())
459  {
460  error = bad_type(json_name, fieldName);
461  return ret;
462  }
463 
464  uint160 num;
465 
466  if (auto const s = value.asString(); !num.parseHex(s))
467  {
468  if (!s.empty())
469  {
470  error = invalid_data(json_name, fieldName);
471  return ret;
472  }
473 
474  num.zero();
475  }
476 
477  ret = detail::make_stvar<STUInt160>(field, num);
478  break;
479  }
480 
481  case STI_UINT256: {
482  if (!value.isString())
483  {
484  error = bad_type(json_name, fieldName);
485  return ret;
486  }
487 
488  uint256 num;
489 
490  if (auto const s = value.asString(); !num.parseHex(s))
491  {
492  if (!s.empty())
493  {
494  error = invalid_data(json_name, fieldName);
495  return ret;
496  }
497 
498  num.zero();
499  }
500 
501  ret = detail::make_stvar<STUInt256>(field, num);
502  break;
503  }
504 
505  case STI_VL:
506  if (!value.isString())
507  {
508  error = bad_type(json_name, fieldName);
509  return ret;
510  }
511 
512  try
513  {
514  if (auto vBlob = strUnHex(value.asString()))
515  {
516  ret = detail::make_stvar<STBlob>(
517  field, vBlob->data(), vBlob->size());
518  }
519  else
520  {
521  Throw<std::invalid_argument>("invalid data");
522  }
523  }
524  catch (std::exception const&)
525  {
526  error = invalid_data(json_name, fieldName);
527  return ret;
528  }
529 
530  break;
531 
532  case STI_AMOUNT:
533  try
534  {
535  ret =
536  detail::make_stvar<STAmount>(amountFromJson(field, value));
537  }
538  catch (std::exception const&)
539  {
540  error = invalid_data(json_name, fieldName);
541  return ret;
542  }
543 
544  break;
545 
546  case STI_VECTOR256:
547  if (!value.isArrayOrNull())
548  {
549  error = array_expected(json_name, fieldName);
550  return ret;
551  }
552 
553  try
554  {
555  STVector256 tail(field);
556  for (Json::UInt i = 0; value.isValidIndex(i); ++i)
557  {
558  uint256 s;
559  if (!s.parseHex(value[i].asString()))
560  Throw<std::invalid_argument>("invalid data");
561  tail.push_back(s);
562  }
563  ret = detail::make_stvar<STVector256>(std::move(tail));
564  }
565  catch (std::exception const&)
566  {
567  error = invalid_data(json_name, fieldName);
568  return ret;
569  }
570 
571  break;
572 
573  case STI_PATHSET:
574  if (!value.isArrayOrNull())
575  {
576  error = array_expected(json_name, fieldName);
577  return ret;
578  }
579 
580  try
581  {
582  STPathSet tail(field);
583 
584  for (Json::UInt i = 0; value.isValidIndex(i); ++i)
585  {
586  STPath p;
587 
588  if (!value[i].isArrayOrNull())
589  {
591  ss << fieldName << "[" << i << "]";
592  error = array_expected(json_name, ss.str());
593  return ret;
594  }
595 
596  for (Json::UInt j = 0; value[i].isValidIndex(j); ++j)
597  {
599  ss << fieldName << "[" << i << "][" << j << "]";
600  std::string const element_name(
601  json_name + "." + ss.str());
602 
603  // each element in this path has some combination of
604  // account, currency, or issuer
605 
606  Json::Value pathEl = value[i][j];
607 
608  if (!pathEl.isObject())
609  {
610  error = not_an_object(element_name);
611  return ret;
612  }
613 
614  Json::Value const& account = pathEl["account"];
615  Json::Value const& currency = pathEl["currency"];
616  Json::Value const& issuer = pathEl["issuer"];
617  bool hasCurrency = false;
618  AccountID uAccount, uIssuer;
619  Currency uCurrency;
620 
621  if (account)
622  {
623  // human account id
624  if (!account.isString())
625  {
626  error =
627  string_expected(element_name, "account");
628  return ret;
629  }
630 
631  // If we have what looks like a 160-bit hex value,
632  // we set it, otherwise, we assume it's an AccountID
633  if (!uAccount.parseHex(account.asString()))
634  {
635  auto const a =
636  parseBase58<AccountID>(account.asString());
637  if (!a)
638  {
639  error =
640  invalid_data(element_name, "account");
641  return ret;
642  }
643  uAccount = *a;
644  }
645  }
646 
647  if (currency)
648  {
649  // human currency
650  if (!currency.isString())
651  {
652  error =
653  string_expected(element_name, "currency");
654  return ret;
655  }
656 
657  hasCurrency = true;
658 
659  if (!uCurrency.parseHex(currency.asString()))
660  {
661  if (!to_currency(
662  uCurrency, currency.asString()))
663  {
664  error =
665  invalid_data(element_name, "currency");
666  return ret;
667  }
668  }
669  }
670 
671  if (issuer)
672  {
673  // human account id
674  if (!issuer.isString())
675  {
676  error = string_expected(element_name, "issuer");
677  return ret;
678  }
679 
680  if (!uIssuer.parseHex(issuer.asString()))
681  {
682  auto const a =
683  parseBase58<AccountID>(issuer.asString());
684  if (!a)
685  {
686  error =
687  invalid_data(element_name, "issuer");
688  return ret;
689  }
690  uIssuer = *a;
691  }
692  }
693 
694  p.emplace_back(
695  uAccount, uCurrency, uIssuer, hasCurrency);
696  }
697 
698  tail.push_back(p);
699  }
700  ret = detail::make_stvar<STPathSet>(std::move(tail));
701  }
702  catch (std::exception const&)
703  {
704  error = invalid_data(json_name, fieldName);
705  return ret;
706  }
707 
708  break;
709 
710  case STI_ACCOUNT: {
711  if (!value.isString())
712  {
713  error = bad_type(json_name, fieldName);
714  return ret;
715  }
716 
717  std::string const strValue = value.asString();
718 
719  try
720  {
721  if (AccountID account; account.parseHex(strValue))
722  return detail::make_stvar<STAccount>(field, account);
723 
724  if (auto result = parseBase58<AccountID>(strValue))
725  return detail::make_stvar<STAccount>(field, *result);
726 
727  error = invalid_data(json_name, fieldName);
728  return ret;
729  }
730  catch (std::exception const&)
731  {
732  error = invalid_data(json_name, fieldName);
733  return ret;
734  }
735  }
736  break;
737 
738  case STI_ISSUE:
739  try
740  {
741  ret = detail::make_stvar<STIssue>(issueFromJson(field, value));
742  }
743  catch (std::exception const&)
744  {
745  error = invalid_data(json_name, fieldName);
746  return ret;
747  }
748  break;
749 
750  case STI_XCHAIN_BRIDGE:
751  try
752  {
753  ret = detail::make_stvar<STXChainBridge>(
754  STXChainBridge(field, value));
755  }
756  catch (std::exception const&)
757  {
758  error = invalid_data(json_name, fieldName);
759  return ret;
760  }
761  break;
762 
763  case STI_CURRENCY:
764  try
765  {
766  ret = detail::make_stvar<STCurrency>(
767  currencyFromJson(field, value));
768  }
769  catch (std::exception const&)
770  {
771  error = invalid_data(json_name, fieldName);
772  return ret;
773  }
774  break;
775 
776  default:
777  error = bad_type(json_name, fieldName);
778  return ret;
779  }
780 
781  return ret;
782 }
783 
784 static const int maxDepth = 64;
785 
786 // Forward declaration since parseObject() and parseArray() call each other.
788 parseArray(
789  std::string const& json_name,
790  Json::Value const& json,
791  SField const& inName,
792  int depth,
793  Json::Value& error);
794 
797  std::string const& json_name,
798  Json::Value const& json,
799  SField const& inName,
800  int depth,
801  Json::Value& error)
802 {
803  if (!json.isObjectOrNull())
804  {
805  error = not_an_object(json_name);
806  return std::nullopt;
807  }
808 
809  if (depth > maxDepth)
810  {
811  error = too_deep(json_name);
812  return std::nullopt;
813  }
814 
815  try
816  {
817  STObject data(inName);
818 
819  for (auto const& fieldName : json.getMemberNames())
820  {
821  Json::Value const& value = json[fieldName];
822 
823  auto const& field = SField::getField(fieldName);
824 
825  if (field == sfInvalid)
826  {
827  error = unknown_field(json_name, fieldName);
828  return std::nullopt;
829  }
830 
831  switch (field.fieldType)
832  {
833  // Object-style containers (which recurse).
834  case STI_OBJECT:
835  case STI_TRANSACTION:
836  case STI_LEDGERENTRY:
837  case STI_VALIDATION:
838  if (!value.isObject())
839  {
840  error = not_an_object(json_name, fieldName);
841  return std::nullopt;
842  }
843 
844  try
845  {
846  auto ret = parseObject(
847  json_name + "." + fieldName,
848  value,
849  field,
850  depth + 1,
851  error);
852  if (!ret)
853  return std::nullopt;
854  data.emplace_back(std::move(*ret));
855  }
856  catch (std::exception const&)
857  {
858  error = invalid_data(json_name, fieldName);
859  return std::nullopt;
860  }
861 
862  break;
863 
864  // Array-style containers (which recurse).
865  case STI_ARRAY:
866  try
867  {
868  auto array = parseArray(
869  json_name + "." + fieldName,
870  value,
871  field,
872  depth + 1,
873  error);
874  if (!array.has_value())
875  return std::nullopt;
876  data.emplace_back(std::move(*array));
877  }
878  catch (std::exception const&)
879  {
880  error = invalid_data(json_name, fieldName);
881  return std::nullopt;
882  }
883 
884  break;
885 
886  // Everything else (types that don't recurse).
887  default: {
888  auto leaf =
889  parseLeaf(json_name, fieldName, &inName, value, error);
890 
891  if (!leaf)
892  return std::nullopt;
893 
894  data.emplace_back(std::move(*leaf));
895  }
896 
897  break;
898  }
899  }
900 
901  // Some inner object types have templates. Attempt to apply that.
902  data.applyTemplateFromSField(inName); // May throw
903 
904  return data;
905  }
906  catch (STObject::FieldErr const& e)
907  {
908  std::cerr << "template_mismatch: " << e.what() << "\n";
909  error = template_mismatch(inName);
910  }
911  catch (std::exception const&)
912  {
913  error = invalid_data(json_name);
914  }
915  return std::nullopt;
916 }
917 
920  std::string const& json_name,
921  Json::Value const& json,
922  SField const& inName,
923  int depth,
924  Json::Value& error)
925 {
926  if (!json.isArrayOrNull())
927  {
928  error = not_an_array(json_name);
929  return std::nullopt;
930  }
931 
932  if (depth > maxDepth)
933  {
934  error = too_deep(json_name);
935  return std::nullopt;
936  }
937 
938  try
939  {
940  STArray tail(inName);
941 
942  for (Json::UInt i = 0; json.isValidIndex(i); ++i)
943  {
944  bool const isObjectOrNull(json[i].isObjectOrNull());
945  bool const singleKey(isObjectOrNull ? json[i].size() == 1 : true);
946 
947  if (!isObjectOrNull || !singleKey)
948  {
949  // null values are !singleKey
950  error = singleton_expected(json_name, i);
951  return std::nullopt;
952  }
953 
954  // TODO: There doesn't seem to be a nice way to get just the
955  // first/only key in an object without copying all keys into
956  // a vector
957  std::string const objectName(json[i].getMemberNames()[0]);
958  ;
959  auto const& nameField(SField::getField(objectName));
960 
961  if (nameField == sfInvalid)
962  {
963  error = unknown_field(json_name, objectName);
964  return std::nullopt;
965  }
966 
967  Json::Value const objectFields(json[i][objectName]);
968 
970  ss << json_name << "."
971  << "[" << i << "]." << objectName;
972 
973  auto ret = parseObject(
974  ss.str(), objectFields, nameField, depth + 1, error);
975  if (!ret)
976  {
977  std::string errMsg = error["error_message"].asString();
978  error["error_message"] =
979  "Error at '" + ss.str() + "'. " + errMsg;
980  return std::nullopt;
981  }
982 
983  if (ret->getFName().fieldType != STI_OBJECT)
984  {
985  ss << "Field type: " << ret->getFName().fieldType << " ";
986  error = non_object_in_array(ss.str(), i);
987  return std::nullopt;
988  }
989 
990  tail.push_back(std::move(*ret));
991  }
992 
993  return detail::make_stvar<STArray>(std::move(tail));
994  }
995  catch (std::exception const&)
996  {
997  error = invalid_data(json_name);
998  return std::nullopt;
999  }
1000 }
1001 
1002 } // namespace STParsedJSONDetail
1003 
1004 //------------------------------------------------------------------------------
1005 
1007  std::string const& name,
1008  Json::Value const& json)
1009 {
1010  using namespace STParsedJSONDetail;
1011  object = parseObject(name, json, sfGeneric, 0, error);
1012 }
1013 
1014 //------------------------------------------------------------------------------
1015 
1017  std::string const& name,
1018  Json::Value const& json)
1019 {
1020  using namespace STParsedJSONDetail;
1021  auto arr = parseArray(name, json, sfGeneric, 0, error);
1022  if (!arr)
1023  array.reset();
1024  else
1025  {
1026  auto p = dynamic_cast<STArray*>(&arr->get());
1027  if (p == nullptr)
1028  array.reset();
1029  else
1030  array = std::move(*p);
1031  }
1032 }
1033 
1034 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
ripple::to_currency
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
std::is_signed
ripple::STParsedJSONDetail::maxDepth
static const int maxDepth
Definition: STParsedJSON.cpp:784
ripple::STParsedJSONDetail::singleton_expected
static Json::Value singleton_expected(std::string const &object, unsigned int index)
Definition: STParsedJSON.cpp:164
std::is_unsigned
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
std::string
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
Json::Value::isValidIndex
bool isValidIndex(UInt index) const
Return true if index < size().
Definition: json_value.cpp:841
std::exception
STL class.
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:359
ripple::STParsedJSONDetail::template_mismatch
static Json::Value template_mismatch(SField const &sField)
Definition: STParsedJSON.cpp:173
ripple::STParsedJSONDetail::bad_type
static Json::Value bad_type(std::string const &object, std::string const &field)
Definition: STParsedJSON.cpp:118
charconv
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
ripple::STParsedJSONDetail::parseArray
static std::optional< detail::STVar > parseArray(std::string const &json_name, Json::Value const &json, SField const &inName, int depth, Json::Value &error)
Definition: STParsedJSON.cpp:919
ripple::currencyFromJson
STCurrency currencyFromJson(SField const &name, Json::Value const &v)
Definition: STCurrency.cpp:96
ripple::STVector256::push_back
void push_back(uint256 const &v)
Definition: STVector256.h:217
ripple::STParsedJSONDetail::non_object_in_array
static Json::Value non_object_in_array(std::string const &item, Json::UInt index)
Definition: STParsedJSON.cpp:182
std::stringstream
STL class.
ripple::STArray::push_back
void push_back(STObject const &object)
Definition: STArray.h:212
ripple::STParsedJSONDetail::too_deep
static Json::Value too_deep(std::string const &object)
Definition: STParsedJSON.cpp:156
std::cerr
ripple::SField::getField
static const SField & getField(int fieldCode)
Definition: SField.cpp:464
ripple::TERtoInt
constexpr TERUnderlyingType TERtoInt(TELcodes v)
Definition: TER.h:347
ripple::sfInvalid
const SField sfInvalid(access, -1)
Definition: SField.h:358
ripple::STPathSet
Definition: STPathSet.h:176
ripple::STParsedJSONDetail::parseLeaf
static std::optional< detail::STVar > parseLeaf(std::string const &json_name, std::string const &fieldName, SField const *name, Json::Value const &value, Json::Value &error)
Definition: STParsedJSON.cpp:193
ripple::transCode
std::optional< TER > transCode(std::string const &token)
Definition: TER.cpp:264
ripple::STParsedJSONObject::error
Json::Value error
On failure, an appropriate set of error values.
Definition: STParsedJSON.h:53
ripple::sfLedgerEntry
const SField sfLedgerEntry
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
ripple::sfTransactionType
const SF_UINT16 sfTransactionType
ripple::STObject::FieldErr
Definition: STObject.h:656
ripple::STParsedJSONDetail::out_of_range
static Json::Value out_of_range(std::string const &object, std::string const &field)
Definition: STParsedJSON.cpp:110
ripple::TxFormats::getInstance
static TxFormats const & getInstance()
Definition: TxFormats.cpp:508
Json::Value::isArrayOrNull
bool isArrayOrNull() const
Definition: json_value.cpp:1021
ripple::STArray
Definition: STArray.h:28
std::to_string
T to_string(T... args)
ripple::STPath::emplace_back
void emplace_back(Args &&... args)
Definition: STPathSet.h:412
std::errc
ripple::amountFromJson
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:927
std::uint8_t
ripple::issueFromJson
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
std::from_chars
T from_chars(T... args)
ripple::STParsedJSONDetail::to_unsigned
constexpr std::enable_if_t< std::is_unsigned< U >::value &&std::is_signed< S >::value, U > to_unsigned(S value)
Definition: STParsedJSON.cpp:54
memory
ripple::LedgerFormats::getInstance
static LedgerFormats const & getInstance()
Definition: LedgerFormats.cpp:362
ripple::STXChainBridge
Definition: STXChainBridge.h:33
std::numeric_limits::min
T min(T... args)
ripple::STObject
Definition: STObject.h:55
ripple::STParsedJSONArray::STParsedJSONArray
STParsedJSONArray()=delete
Json::Value::getMemberNames
Members getMemberNames() const
Return a list of the member names.
Definition: json_value.cpp:948
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::sfTransactionResult
const SF_UINT8 sfTransactionResult
ripple::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
ripple::STParsedJSONDetail::parseObject
static std::optional< STObject > parseObject(std::string const &json_name, Json::Value const &json, SField const &inName, int depth, Json::Value &error)
Definition: STParsedJSON.cpp:796
ripple::SField
Identifies fields.
Definition: SField.h:141
ripple::base_uint::zero
void zero()
Definition: base_uint.h:542
ripple::SField::getName
std::string const & getName() const
Definition: SField.h:204
ripple::STParsedJSONDetail::not_an_object
static Json::Value not_an_object(std::string const &object, std::string const &field)
Definition: STParsedJSON.cpp:81
cassert
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
Json::Value::isUInt
bool isUInt() const
Definition: json_value.cpp:985
ripple::STParsedJSONDetail::make_name
static std::string make_name(std::string const &object, std::string const &field)
Definition: STParsedJSON.cpp:72
ripple::STVector256
Definition: STVector256.h:30
ripple::STParsedJSONDetail::invalid_data
static Json::Value invalid_data(std::string const &object, std::string const &field)
Definition: STParsedJSON.cpp:126
std::string::empty
T empty(T... args)
std::optional
std::stringstream::str
T str(T... args)
Json::Value::asInt
Int asInt() const
Definition: json_value.cpp:503
ripple::STParsedJSONObject::STParsedJSONObject
STParsedJSONObject()=delete
ripple::STParsedJSONDetail::string_expected
static Json::Value string_expected(std::string const &object, std::string const &field)
Definition: STParsedJSON.cpp:148
std::numeric_limits::max
T max(T... args)
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
ripple::STPath
Definition: STPathSet.h:118
ripple::strUnHex
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:52
std::numeric_limits
Json::Value::isObjectOrNull
bool isObjectOrNull() const
Definition: json_value.cpp:1033
ripple::sfTransaction
const SField sfTransaction
ripple::STParsedJSONDetail::array_expected
static Json::Value array_expected(std::string const &object, std::string const &field)
Definition: STParsedJSON.cpp:140
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:181
std::runtime_error::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::STParsedJSONDetail::not_an_array
static Json::Value not_an_array(std::string const &object)
Definition: STParsedJSON.cpp:95
ripple::STParsedJSONDetail::unknown_field
static Json::Value unknown_field(std::string const &object, std::string const &field)
Definition: STParsedJSON.cpp:102
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::STPathSet::push_back
void push_back(STPath const &e)
Definition: STPathSet.h:509