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