rippled
STObject_test.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/Log.h>
21 #include <ripple/protocol/jss.h>
22 #include <ripple/protocol/SecretKey.h>
23 #include <ripple/protocol/st.h>
24 #include <ripple/json/json_reader.h>
25 #include <ripple/json/to_string.h>
26 #include <ripple/beast/unit_test.h>
27 #include <test/jtx.h>
28 
29 #include <array>
30 #include <memory>
31 #include <type_traits>
32 
33 namespace ripple {
34 
35 class STObject_test : public beast::unit_test::suite
36 {
37 public:
38  bool parseJSONString (std::string const& json, Json::Value& to)
39  {
40  Json::Reader reader;
41  return reader.parse(json, to) && to.isObject();
42  }
43 
45  {
46  testcase ("parse json array invalid children");
47  try
48  {
49  /*
50 
51  STArray/STObject constructs don't really map perfectly to json
52  arrays/objects.
53 
54  STObject is an associative container, mapping fields to value, but
55  an STObject may also have a Field as its name, stored outside the
56  associative structure. The name is important, so to maintain
57  fidelity, it will take TWO json objects to represent them.
58 
59  */
60  std::string faulty ("{\"Template\":[{"
61  "\"ModifiedNode\":{\"Sequence\":1}, "
62  "\"DeletedNode\":{\"Sequence\":1}"
63  "}]}");
64 
66  Json::Value faultyJson;
67  bool parsedOK (parseJSONString(faulty, faultyJson));
68  unexpected(!parsedOK, "failed to parse");
69  STParsedJSONObject parsed ("test", faultyJson);
70  BEAST_EXPECT(! parsed.object);
71  }
72  catch(std::runtime_error& e)
73  {
74  std::string what(e.what());
75  unexpected (what.find("First level children of `Template`") != 0);
76  }
77  }
78 
80  {
81  testcase ("parse json array");
82  std::string const json (
83  "{\"Template\":[{\"ModifiedNode\":{\"Sequence\":1}}]}");
84 
85  Json::Value jsonObject;
86  bool parsedOK (parseJSONString(json, jsonObject));
87  if (parsedOK)
88  {
89  STParsedJSONObject parsed ("test", jsonObject);
90  BEAST_EXPECT(parsed.object);
91  std::string const& serialized (
92  to_string (parsed.object->getJson(JsonOptions::none)));
93  BEAST_EXPECT(serialized == json);
94  }
95  else
96  {
97  fail ("Couldn't parse json: " + json);
98  }
99  }
100 
102  {
103  testcase("parse json object");
104 
105  {
106  std::string const goodJson(
107  R"({"CloseResolution":19,"Method":250,)"
108  R"("TransactionResult":"tecFROZEN"})");
109 
110  Json::Value jv;
111  if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
112  {
113  STParsedJSONObject parsed("test", jv);
114  if (BEAST_EXPECT(parsed.object))
115  {
116  std::string const& serialized(
117  to_string(parsed.object->getJson(JsonOptions::none)));
118  BEAST_EXPECT(serialized == goodJson);
119  }
120  }
121  }
122 
123  {
124  std::string const goodJson(
125  R"({"CloseResolution":19,"Method":"250",)"
126  R"("TransactionResult":"tecFROZEN"})");
127  std::string const expectedJson(
128  R"({"CloseResolution":19,"Method":250,)"
129  R"("TransactionResult":"tecFROZEN"})");
130 
131  Json::Value jv;
132  if (BEAST_EXPECT(parseJSONString(goodJson, jv)))
133  {
134  // Integer values are always parsed as int,
135  // unless they're too big. We want a small uint.
136  jv["CloseResolution"] = Json::UInt(19);
137  STParsedJSONObject parsed("test", jv);
138  if (BEAST_EXPECT(parsed.object))
139  {
140  std::string const& serialized(
141  to_string(parsed.object->getJson(JsonOptions::none)));
142  BEAST_EXPECT(serialized == expectedJson);
143  }
144  }
145  }
146 
147  {
148  std::string const json(
149  R"({"CloseResolution":19,"Method":250,)"
150  R"("TransactionResult":"terQUEUED"})");
151 
152  Json::Value jv;
153  if (BEAST_EXPECT(parseJSONString(json, jv)))
154  {
155  STParsedJSONObject parsed("test", jv);
156  BEAST_EXPECT(!parsed.object);
157  BEAST_EXPECT(parsed.error);
158  BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
159  BEAST_EXPECT(parsed.error[jss::error_message] ==
160  "Field 'test.TransactionResult' is out of range.");
161  }
162  }
163 
164  {
165  std::string const json(
166  R"({"CloseResolution":19,"Method":"pony",)"
167  R"("TransactionResult":"tesSUCCESS"})");
168 
169  Json::Value jv;
170  if (BEAST_EXPECT(parseJSONString(json, jv)))
171  {
172  STParsedJSONObject parsed("test", jv);
173  BEAST_EXPECT(!parsed.object);
174  BEAST_EXPECT(parsed.error);
175  BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
176  BEAST_EXPECT(parsed.error[jss::error_message] ==
177  "Field 'test.Method' has bad type.");
178  }
179  }
180 
181  {
182  std::string const json(
183  R"({"CloseResolution":19,"Method":3294967296,)"
184  R"("TransactionResult":"tesSUCCESS"})");
185 
186  Json::Value jv;
187  if (BEAST_EXPECT(parseJSONString(json, jv)))
188  {
189  STParsedJSONObject parsed("test", jv);
190  BEAST_EXPECT(!parsed.object);
191  BEAST_EXPECT(parsed.error);
192  BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
193  BEAST_EXPECT(parsed.error[jss::error_message] ==
194  "Field 'test.Method' is out of range.");
195  }
196  }
197 
198  {
199  std::string const json(
200  R"({"CloseResolution":-10,"Method":42,)"
201  R"("TransactionResult":"tesSUCCESS"})");
202 
203  Json::Value jv;
204  if (BEAST_EXPECT(parseJSONString(json, jv)))
205  {
206  STParsedJSONObject parsed("test", jv);
207  BEAST_EXPECT(!parsed.object);
208  BEAST_EXPECT(parsed.error);
209  BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
210  BEAST_EXPECT(parsed.error[jss::error_message] ==
211  "Field 'test.CloseResolution' is out of range.");
212  }
213  }
214 
215  {
216  std::string const json(
217  R"({"CloseResolution":19,"Method":3.141592653,)"
218  R"("TransactionResult":"tesSUCCESS"})");
219 
220  Json::Value jv;
221  if (BEAST_EXPECT(parseJSONString(json, jv)))
222  {
223  STParsedJSONObject parsed("test", jv);
224  BEAST_EXPECT(!parsed.object);
225  BEAST_EXPECT(parsed.error);
226  BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
227  BEAST_EXPECT(parsed.error[jss::error_message] ==
228  "Field 'test.Method' has bad type.");
229  }
230  }
231  }
232 
234  {
235  testcase ("serialization");
236 
237  unexpected (sfGeneric.isUseful (), "sfGeneric must not be useful");
238  {
239  // Try to put sfGeneric in an SOTemplate.
240  except<std::runtime_error>( [&]()
241  {
242  SOTemplate elements {{ sfGeneric, soeREQUIRED }};
243  });
244  }
245 
246  unexpected (sfInvalid.isUseful (), "sfInvalid must not be useful");
247  {
248  // Test return of sfInvalid.
249  auto testInvalid = [this] (SerializedTypeID tid, int fv)
250  {
251  SField const& shouldBeInvalid {SField::getField (tid, fv)};
252  BEAST_EXPECT (shouldBeInvalid == sfInvalid);
253  };
254  testInvalid (STI_VL, 255);
255  testInvalid (STI_HASH256, 255);
256  testInvalid (STI_UINT32, 255);
257  testInvalid (STI_VECTOR256, 255);
258  testInvalid (STI_OBJECT, 255);
259  }
260  {
261  // Try to put sfInvalid in an SOTemplate.
262  except<std::runtime_error>( [&]()
263  {
264  SOTemplate elements {{ sfInvalid, soeREQUIRED }};
265  });
266  }
267  {
268  // Try to put the same SField into an SOTemplate twice.
269  except<std::runtime_error>( [&]()
270  {
271  SOTemplate elements {
272  { sfAccount, soeREQUIRED },
273  { sfAccount, soeREQUIRED },
274  };
275  });
276  }
277 
278  // Put a variety of SFields of different types in an SOTemplate.
279  SField const& sfTestVL = sfMasterSignature;
280  SField const& sfTestH256 = sfCheckID;
281  SField const& sfTestU32 = sfSettleDelay;
282  SField const& sfTestV256 = sfAmendments;
283  SField const& sfTestObject = sfMajority;
284 
285 
286  SOTemplate const elements
287  {
288  { sfFlags, soeREQUIRED },
289  { sfTestVL, soeREQUIRED },
290  { sfTestH256, soeOPTIONAL },
291  { sfTestU32, soeREQUIRED },
292  { sfTestV256, soeOPTIONAL },
293  };
294 
295  STObject object1 (elements, sfTestObject);
296  STObject object2 (object1);
297 
298  unexpected (object1.getSerializer () != object2.getSerializer (),
299  "STObject error 1");
300 
301  unexpected (object1.isFieldPresent (sfTestH256) ||
302  !object1.isFieldPresent (sfTestVL), "STObject error");
303 
304  object1.makeFieldPresent (sfTestH256);
305 
306  unexpected (!object1.isFieldPresent (sfTestH256), "STObject Error 2");
307 
308  unexpected (object1.getFieldH256 (sfTestH256) != uint256 (),
309  "STObject error 3");
310 
311  if (object1.getSerializer () == object2.getSerializer ())
312  {
313  log <<
314  "O1: " << object1.getJson (JsonOptions::none) << '\n' <<
315  "O2: " << object2.getJson (JsonOptions::none) << std::endl;
316  fail ("STObject error 4");
317  }
318  else
319  {
320  pass ();
321  }
322 
323  object1.makeFieldAbsent (sfTestH256);
324 
325  unexpected (object1.isFieldPresent (sfTestH256), "STObject error 5");
326 
327  unexpected (object1.getFlags () != 0, "STObject error 6");
328 
329  unexpected (object1.getSerializer () != object2.getSerializer (),
330  "STObject error 7");
331 
332  STObject copy (object1);
333 
334  unexpected (object1.isFieldPresent (sfTestH256), "STObject error 8");
335 
336  unexpected (copy.isFieldPresent (sfTestH256), "STObject error 9");
337 
338  unexpected (object1.getSerializer () != copy.getSerializer (),
339  "STObject error 10");
340 
341  copy.setFieldU32 (sfTestU32, 1);
342 
343  unexpected (object1.getSerializer () == copy.getSerializer (),
344  "STObject error 11");
345 
346  for (int i = 0; i < 1000; i++)
347  {
348  Blob j (i, 2);
349 
350  object1.setFieldVL (sfTestVL, j);
351 
352  Serializer s;
353  object1.add (s);
354  SerialIter it (s.slice());
355 
356  STObject object3 (elements, it, sfTestObject);
357 
358  unexpected (object1.getFieldVL (sfTestVL) != j, "STObject error");
359 
360  unexpected (object3.getFieldVL (sfTestVL) != j, "STObject error");
361  }
362 
363  {
364  std::vector<uint256> uints;
365  uints.reserve(5);
366  for (int i = 0; i < uints.capacity(); ++i)
367  {
368  uints.emplace_back(i);
369  }
370  object1.setFieldV256(sfTestV256, STVector256(uints));
371 
372  Serializer s;
373  object1.add(s);
374  SerialIter it(s.slice());
375 
376  STObject object3(elements, it, sfTestObject);
377 
378  auto const& uints1 = object1.getFieldV256(sfTestV256);
379  auto const& uints3 = object3.getFieldV256(sfTestV256);
380 
381  BEAST_EXPECT(uints1 == uints3);
382  }
383  }
384 
385  // Exercise field accessors
386  void
388  {
389  testcase ("fields");
390 
391  auto const& sf1Outer = sfSequence;
392  auto const& sf2Outer = sfExpiration;
393  auto const& sf3Outer = sfQualityIn;
394  auto const& sf4 = sfSignature;
395  auto const& sf5 = sfPublicKey;
396 
397  // read free object
398 
399  {
400  auto const st = [&]()
401  {
402  STObject s(sfGeneric);
403  s.setFieldU32(sf1Outer, 1);
404  s.setFieldU32(sf2Outer, 2);
405  return s;
406  }();
407 
408  BEAST_EXPECT(st[sf1Outer] == 1);
409  BEAST_EXPECT(st[sf2Outer] == 2);
410  except<STObject::FieldErr>([&]()
411  { st[sf3Outer]; });
412  BEAST_EXPECT(*st[~sf1Outer] == 1);
413  BEAST_EXPECT(*st[~sf2Outer] == 2);
414  BEAST_EXPECT(st[~sf3Outer] == boost::none);
415  BEAST_EXPECT(!! st[~sf1Outer]);
416  BEAST_EXPECT(!! st[~sf2Outer]);
417  BEAST_EXPECT(! st[~sf3Outer]);
418  BEAST_EXPECT(st[sf1Outer] != st[sf2Outer]);
419  BEAST_EXPECT(st[~sf1Outer] != st[~sf2Outer]);
420  }
421 
422  // read templated object
423  SOTemplate const sotOuter
424  {
425  { sf1Outer, soeREQUIRED },
426  { sf2Outer, soeOPTIONAL },
427  { sf3Outer, soeDEFAULT },
428  { sf4, soeOPTIONAL },
429  { sf5, soeDEFAULT },
430  };
431 
432  {
433  auto const st = [&]()
434  {
435  STObject s(sotOuter, sfGeneric);
436  s.setFieldU32(sf1Outer, 1);
437  s.setFieldU32(sf2Outer, 2);
438  return s;
439  }();
440 
441  BEAST_EXPECT(st[sf1Outer] == 1);
442  BEAST_EXPECT(st[sf2Outer] == 2);
443  BEAST_EXPECT(st[sf3Outer] == 0);
444  BEAST_EXPECT(*st[~sf1Outer] == 1);
445  BEAST_EXPECT(*st[~sf2Outer] == 2);
446  BEAST_EXPECT(*st[~sf3Outer] == 0);
447  BEAST_EXPECT(!! st[~sf1Outer]);
448  BEAST_EXPECT(!! st[~sf2Outer]);
449  BEAST_EXPECT(!! st[~sf3Outer]);
450  }
451 
452  // write free object
453 
454  {
455  STObject st(sfGeneric);
456  unexcept([&]() { st[sf1Outer]; });
457  except([&](){ return st[sf1Outer] == 0; });
458  BEAST_EXPECT(st[~sf1Outer] == boost::none);
459  BEAST_EXPECT(st[~sf1Outer] == boost::optional<std::uint32_t>{});
460  BEAST_EXPECT(st[~sf1Outer] != boost::optional<std::uint32_t>(1));
461  BEAST_EXPECT(! st[~sf1Outer]);
462  st[sf1Outer] = 2;
463  BEAST_EXPECT(st[sf1Outer] == 2);
464  BEAST_EXPECT(st[~sf1Outer] != boost::none);
465  BEAST_EXPECT(st[~sf1Outer] == boost::optional<std::uint32_t>(2));
466  BEAST_EXPECT(!! st[~sf1Outer]);
467  st[sf1Outer] = 1;
468  BEAST_EXPECT(st[sf1Outer] == 1);
469  BEAST_EXPECT(!! st[sf1Outer]);
470  BEAST_EXPECT(!! st[~sf1Outer]);
471  st[sf1Outer] = 0;
472  BEAST_EXPECT(! st[sf1Outer]);
473  BEAST_EXPECT(!! st[~sf1Outer]);
474  st[~sf1Outer] = boost::none;
475  BEAST_EXPECT(! st[~sf1Outer]);
476  BEAST_EXPECT(st[~sf1Outer] == boost::none);
477  BEAST_EXPECT(st[~sf1Outer] == boost::optional<std::uint32_t>{});
478  st[~sf1Outer] = boost::none;
479  BEAST_EXPECT(! st[~sf1Outer]);
480  except([&]() { return st[sf1Outer] == 0; });
481  except([&]() { return *st[~sf1Outer]; });
482  st[sf1Outer] = 1;
483  BEAST_EXPECT(st[sf1Outer] == 1);
484  BEAST_EXPECT(!! st[sf1Outer]);
485  BEAST_EXPECT(!! st[~sf1Outer]);
486  st[sf1Outer] = 3;
487  st[sf2Outer] = st[sf1Outer];
488  BEAST_EXPECT(st[sf1Outer] == 3);
489  BEAST_EXPECT(st[sf2Outer] == 3);
490  BEAST_EXPECT(st[sf2Outer] == st[sf1Outer]);
491  st[sf1Outer] = 4;
492  st[sf2Outer] = st[sf1Outer];
493  BEAST_EXPECT(st[sf1Outer] == 4);
494  BEAST_EXPECT(st[sf2Outer] == 4);
495  BEAST_EXPECT(st[sf2Outer] == st[sf1Outer]);
496  }
497 
498  // Write templated object
499 
500  {
501  STObject st(sotOuter, sfGeneric);
502  BEAST_EXPECT(!! st[~sf1Outer]);
503  BEAST_EXPECT(st[~sf1Outer] != boost::none);
504  BEAST_EXPECT(st[sf1Outer] == 0);
505  BEAST_EXPECT(*st[~sf1Outer] == 0);
506  BEAST_EXPECT(! st[~sf2Outer]);
507  BEAST_EXPECT(st[~sf2Outer] == boost::none);
508  except([&]() { return st[sf2Outer] == 0; });
509  BEAST_EXPECT(!! st[~sf3Outer]);
510  BEAST_EXPECT(st[~sf3Outer] != boost::none);
511  BEAST_EXPECT(st[sf3Outer] == 0);
512  except([&]() { st[~sf1Outer] = boost::none; });
513  st[sf1Outer] = 1;
514  BEAST_EXPECT(st[sf1Outer] == 1);
515  BEAST_EXPECT(*st[~sf1Outer] == 1);
516  BEAST_EXPECT(!! st[~sf1Outer]);
517  st[sf1Outer] = 0;
518  BEAST_EXPECT(st[sf1Outer] == 0);
519  BEAST_EXPECT(*st[~sf1Outer] == 0);
520  BEAST_EXPECT(!! st[~sf1Outer]);
521  st[sf2Outer] = 2;
522  BEAST_EXPECT(st[sf2Outer] == 2);
523  BEAST_EXPECT(*st[~sf2Outer] == 2);
524  BEAST_EXPECT(!! st[~sf2Outer]);
525  st[~sf2Outer] = boost::none;
526  except([&]() { return *st[~sf2Outer]; });
527  BEAST_EXPECT(! st[~sf2Outer]);
528  st[sf3Outer] = 3;
529  BEAST_EXPECT(st[sf3Outer] == 3);
530  BEAST_EXPECT(*st[~sf3Outer] == 3);
531  BEAST_EXPECT(!! st[~sf3Outer]);
532  st[sf3Outer] = 2;
533  BEAST_EXPECT(st[sf3Outer] == 2);
534  BEAST_EXPECT(*st[~sf3Outer] == 2);
535  BEAST_EXPECT(!! st[~sf3Outer]);
536  st[sf3Outer] = 0;
537  BEAST_EXPECT(st[sf3Outer] == 0);
538  BEAST_EXPECT(*st[~sf3Outer] == 0);
539  BEAST_EXPECT(!! st[~sf3Outer]);
540  except([&]() { st[~sf3Outer] = boost::none; });
541  BEAST_EXPECT(st[sf3Outer] == 0);
542  BEAST_EXPECT(*st[~sf3Outer] == 0);
543  BEAST_EXPECT(!! st[~sf3Outer]);
544  }
545 
546  // coercion operator to boost::optional
547 
548  {
549  STObject st(sfGeneric);
550  auto const v = ~st[~sf1Outer];
551  static_assert(std::is_same<
552  std::decay_t<decltype(v)>,
553  boost::optional<std::uint32_t>>::value, "");
554  }
555 
556  // UDT scalar fields
557 
558  {
559  STObject st(sfGeneric);
560  st[sfAmount] = STAmount{};
561  st[sfAccount] = AccountID{};
562  st[sfDigest] = uint256{};
563  [&](STAmount){}(st[sfAmount]);
564  [&](AccountID){}(st[sfAccount]);
565  [&](uint256){}(st[sfDigest]);
566  }
567 
568  // STBlob and slice
569 
570  {
571  {
572  STObject st(sfGeneric);
573  Buffer b(1);
574  BEAST_EXPECT(! b.empty());
575  st[sf4] = std::move(b);
576  BEAST_EXPECT(b.empty());
577  BEAST_EXPECT(Slice(st[sf4]).size() == 1);
578  st[~sf4] = boost::none;
579  BEAST_EXPECT(! ~st[~sf4]);
580  b = Buffer{2};
581  st[sf4] = Slice(b);
582  BEAST_EXPECT(b.size() == 2);
583  BEAST_EXPECT(Slice(st[sf4]).size() == 2);
584  st[sf5] = st[sf4];
585  BEAST_EXPECT(Slice(st[sf4]).size() == 2);
586  BEAST_EXPECT(Slice(st[sf5]).size() == 2);
587  }
588  {
589  STObject st(sotOuter, sfGeneric);
590  BEAST_EXPECT(st[sf5] == Slice{});
591  BEAST_EXPECT(!! st[~sf5]);
592  BEAST_EXPECT(!! ~st[~sf5]);
593  Buffer b(1);
594  st[sf5] = std::move(b);
595  BEAST_EXPECT(b.empty());
596  BEAST_EXPECT(Slice(st[sf5]).size() == 1);
597  st[~sf4] = boost::none;
598  BEAST_EXPECT(! ~st[~sf4]);
599  }
600  }
601 
602  // UDT blobs
603 
604  {
605  STObject st(sfGeneric);
606  BEAST_EXPECT(! st[~sf5]);
607  auto const kp = generateKeyPair(
609  generateSeed("masterpassphrase"));
610  st[sf5] = kp.first;
611  BEAST_EXPECT(st[sf5] != PublicKey{});
612  st[~sf5] = boost::none;
613 #if 0
614  pk = st[sf5];
615  BEAST_EXPECT(pk.size() == 0);
616 #endif
617  }
618 
619  // By reference fields
620 
621  {
622  auto const& sf = sfIndexes;
623  STObject st(sfGeneric);
625  v.emplace_back(1);
626  v.emplace_back(2);
627  st[sf] = v;
628  st[sf] = std::move(v);
629  auto const& cst = st;
630  BEAST_EXPECT(cst[sf].size() == 2);
631  BEAST_EXPECT(cst[~sf]->size() == 2);
632  BEAST_EXPECT(cst[sf][0] == 1);
633  BEAST_EXPECT(cst[sf][1] == 2);
634  static_assert(std::is_same<decltype(cst[sfIndexes]),
635  std::vector<uint256> const&>::value, "");
636  }
637 
638  // Default by reference field
639 
640  {
641  auto const& sf1 = sfIndexes;
642  auto const& sf2 = sfHashes;
643  auto const& sf3 = sfAmendments;
644  SOTemplate const sot
645  {
646  { sf1, soeREQUIRED },
647  { sf2, soeOPTIONAL },
648  { sf3, soeDEFAULT },
649  };
650 
651  STObject st(sot, sfGeneric);
652  auto const& cst(st);
653  BEAST_EXPECT(cst[sf1].size() == 0);
654  BEAST_EXPECT(! cst[~sf2]);
655  BEAST_EXPECT(cst[sf3].size() == 0);
657  v.emplace_back(1);
658  st[sf1] = v;
659  BEAST_EXPECT(cst[sf1].size() == 1);
660  BEAST_EXPECT(cst[sf1][0] == uint256{1});
661  st[sf2] = v;
662  BEAST_EXPECT(cst[sf2].size() == 1);
663  BEAST_EXPECT(cst[sf2][0] == uint256{1});
664  st[~sf2] = boost::none;
665  BEAST_EXPECT(! st[~sf2]);
666  st[sf3] = v;
667  BEAST_EXPECT(cst[sf3].size() == 1);
668  BEAST_EXPECT(cst[sf3][0] == uint256{1});
669  st[sf3] = std::vector<uint256>{};
670  BEAST_EXPECT(cst[sf3].size() == 0);
671  }
672  }
673 
674  void
676  {
677  testcase ("Malformed serialized forms");
678 
679  try
680  {
681  std::array<std::uint8_t, 7> const payload {
682  { 0xe9, 0x12, 0xab, 0xcd, 0x12, 0xfe, 0xdc }};
683  SerialIter sit{makeSlice(payload)};
684  auto obj = std::make_shared<STArray>(sit, sfMetadata);
685  BEAST_EXPECT(!obj);
686  }
687  catch (std::exception const& e)
688  {
689  BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0);
690  }
691 
692  try
693  {
694  std::array<std::uint8_t, 3> const payload {{ 0xe2, 0xe1, 0xe2 }};
695  SerialIter sit{makeSlice(payload)};
696  auto obj = std::make_shared<STObject>(sit, sfMetadata);
697  BEAST_EXPECT(!obj);
698  }
699  catch (std::exception const& e)
700  {
701  BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0);
702  }
703  }
704 
705  void
706  run() override
707  {
708  // Instantiate a jtx::Env so debugLog writes are exercised.
709  test::jtx::Env env (*this);
710 
711  testFields();
716  testMalformed();
717  }
718 };
719 
720 BEAST_DEFINE_TESTSUITE(STObject,protocol,ripple);
721 
722 } // ripple
ripple::STObject_test::testParseJSONArrayWithInvalidChildrenObjects
void testParseJSONArrayWithInvalidChildrenObjects()
Definition: STObject_test.cpp:44
std::is_same
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:199
ripple::STObject::makeFieldAbsent
void makeFieldAbsent(SField const &field)
Definition: STObject.cpp:471
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1069
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
std::exception
STL class.
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:317
ripple::STObject::setFieldV256
void setFieldV256(SField const &field, STVector256 const &v)
Definition: STObject.cpp:621
ripple::sfQualityIn
const SF_U32 sfQualityIn(access, STI_UINT32, 20, "QualityIn")
Definition: SField.h:357
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:43
ripple::STObject::getFieldV256
const STVector256 & getFieldV256(SField const &field) const
Definition: STObject.cpp:561
std::vector::reserve
T reserve(T... args)
ripple::sfMetadata
const SField sfMetadata(access, STI_METADATA, 257, "Metadata")
Definition: SField.h:321
Json::UInt
unsigned int UInt
Definition: json_forwards.h:28
std::vector< unsigned char >
std::string::find
T find(T... args)
ripple::sfSequence
const SF_U32 sfSequence(access, STI_UINT32, 4, "Sequence")
Definition: SField.h:340
ripple::SerializedTypeID
SerializedTypeID
Definition: SField.h:52
ripple::SField::isUseful
bool isUseful() const
Definition: SField.h:191
ripple::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:460
ripple::sfFlags
const SF_U32 sfFlags(access, STI_UINT32, 2, "Flags")
Definition: SField.h:338
ripple::STObject_test::run
void run() override
Definition: STObject_test.cpp:706
ripple::AccountID
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:48
ripple::sfMasterSignature
const SF_Blob sfMasterSignature(access, STI_VL, 18, "MasterSignature", SField::sMD_Default, SField::notSigning)
Definition: SField.h:457
ripple::STObject_test::testMalformed
void testMalformed()
Definition: STObject_test.cpp:675
ripple::STObject::getSerializer
Serializer getSerializer() const
Definition: STObject.h:356
ripple::Buffer::empty
bool empty() const noexcept
Definition: Buffer.h:136
ripple::soeREQUIRED
@ soeREQUIRED
Definition: SOTemplate.h:35
ripple::Buffer
Like std::vector<char> but better.
Definition: Buffer.h:35
ripple::STParsedJSONObject
Holds the serialized result of parsing an input JSON object.
Definition: STParsedJSON.h:31
ripple::SField::getField
static const SField & getField(int fieldCode)
Definition: SField.cpp:269
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::STObject::setFieldVL
void setFieldVL(SField const &field, Blob const &)
Definition: STObject.cpp:631
ripple::STObject::getFieldVL
Blob getFieldVL(SField const &field) const
Definition: STObject.cpp:542
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
ripple::sfAmount
const SF_Amount sfAmount(access, STI_AMOUNT, 1, "Amount")
Definition: SField.h:423
ripple::sfInvalid
const SField sfInvalid(access, -1)
Definition: SField.h:316
ripple::sfSignature
const SF_Blob sfSignature(access, STI_VL, 6, "Signature", SField::sMD_Default, SField::notSigning)
Definition: SField.h:444
ripple::generateKeyPair
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:267
ripple::sfMajority
const SField sfMajority(access, STI_OBJECT, 18, "Majority")
Definition: SField.h:490
ripple::STParsedJSONObject::error
Json::Value error
On failure, an appropriate set of error values.
Definition: STParsedJSON.h:52
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:436
ripple::base_uint< 256 >
std::vector::capacity
T capacity(T... args)
ripple::SOTemplate
Defines the fields and their attributes within a STObject.
Definition: SOTemplate.h:75
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::JsonOptions::none
@ none
ripple::soeOPTIONAL
@ soeOPTIONAL
Definition: SOTemplate.h:36
ripple::STObject_test::testSerialization
void testSerialization()
Definition: STObject_test.cpp:233
array
ripple::STI_VL
@ STI_VL
Definition: SField.h:66
ripple::STI_HASH256
@ STI_HASH256
Definition: SField.h:64
ripple::STAmount
Definition: STAmount.h:42
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:67
ripple::Buffer::size
std::size_t size() const noexcept
Returns the number of bytes in the buffer.
Definition: Buffer.h:130
ripple::STObject::getFlags
std::uint32_t getFlags() const
Definition: STObject.cpp:439
ripple::STObject_test::parseJSONString
bool parseJSONString(std::string const &json, Json::Value &to)
Definition: STObject_test.cpp:38
std::runtime_error
STL class.
ripple::SerialIter
Definition: Serializer.h:311
ripple::STObject_test::testParseJSONArray
void testParseJSONArray()
Definition: STObject_test.cpp:79
ripple::STI_VECTOR256
@ STI_VECTOR256
Definition: SField.h:76
ripple::STParsedJSONObject::object
boost::optional< STObject > object
The STObject if the parse was successful.
Definition: STParsedJSON.h:49
ripple::STObject_test::testFields
void testFields()
Definition: STObject_test.cpp:387
ripple::sfIndexes
const SF_Vec256 sfIndexes(access, STI_VECTOR256, 1, "Indexes", SField::sMD_Never)
Definition: SField.h:473
ripple::sfExpiration
const SF_U32 sfExpiration(access, STI_UINT32, 10, "Expiration")
Definition: SField.h:346
memory
ripple::KeyType::secp256k1
@ secp256k1
std::decay_t
ripple::Serializer
Definition: Serializer.h:43
ripple::STObject::makeFieldPresent
STBase * makeFieldPresent(SField const &field)
Definition: STObject.cpp:449
ripple::generateSeed
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition: Seed.cpp:74
ripple::sfHashes
const SF_Vec256 sfHashes(access, STI_VECTOR256, 2, "Hashes")
Definition: SField.h:474
ripple::STI_UINT32
@ STI_UINT32
Definition: SField.h:61
ripple::STObject
Definition: STObject.h:51
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:440
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::STObject_test
Definition: STObject_test.cpp:35
std::endl
T endl(T... args)
ripple::STObject::add
virtual void add(Serializer &s) const override
Definition: STObject.h:343
ripple::STObject_test::testParseJSONEdgeCases
void testParseJSONEdgeCases()
Definition: STObject_test.cpp:101
ripple::SField
Identifies fields.
Definition: SField.h:112
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:392
Json::Reader::parse
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:76
ripple::STVector256
Definition: STVector256.h:29
ripple::sfSettleDelay
const SF_U32 sfSettleDelay(access, STI_UINT32, 39, "SettleDelay")
Definition: SField.h:376
ripple::sfDigest
const SF_U256 sfDigest(access, STI_HASH256, 21, "Digest")
Definition: SField.h:417
ripple::sfCheckID
const SF_U256 sfCheckID(access, STI_HASH256, 24, "CheckID")
Definition: SField.h:420
ripple::STI_OBJECT
@ STI_OBJECT
Definition: SField.h:69
ripple::sfAmendments
const SF_Vec256 sfAmendments(access, STI_VECTOR256, 3, "Amendments")
Definition: SField.h:475
ripple::STObject::getJson
virtual Json::Value getJson(JsonOptions options) const override
Definition: STObject.cpp:657
std::unique_ptr
STL class.
ripple::STObject::setFieldU32
void setFieldU32(SField const &field, std::uint32_t)
Definition: STObject.cpp:601
type_traits
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
ripple::soeDEFAULT
@ soeDEFAULT
Definition: SOTemplate.h:37
std::runtime_error::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:141
ripple::STObject::getFieldH256
uint256 getFieldH256(SField const &field) const
Definition: STObject.cpp:532