rippled
Oracle_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2023 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/protocol/jss.h>
21 #include <test/jtx/Oracle.h>
22 
23 namespace ripple {
24 namespace test {
25 namespace jtx {
26 namespace oracle {
27 
28 struct Oracle_test : public beast::unit_test::suite
29 {
30 private:
31  // Helper function that returns the owner count of an account root.
32  static std::uint32_t
33  ownerCount(jtx::Env const& env, jtx::Account const& acct)
34  {
35  std::uint32_t ret{0};
36  if (auto const sleAcct = env.le(acct))
37  ret = sleAcct->at(sfOwnerCount);
38  return ret;
39  }
40 
41  void
43  {
44  testcase("Invalid Set");
45 
46  using namespace jtx;
47  Account const owner("owner");
48 
49  {
50  // Invalid account
51  Env env(*this);
52  Account const bad("bad");
53  env.memoize(bad);
54  Oracle oracle(
55  env, {.owner = bad, .seq = seq(1), .err = ter(terNO_ACCOUNT)});
56  }
57 
58  // Insufficient reserve
59  {
60  Env env(*this);
61  env.fund(env.current()->fees().accountReserve(0), owner);
62  Oracle oracle(
63  env, {.owner = owner, .err = ter(tecINSUFFICIENT_RESERVE)});
64  }
65  // Insufficient reserve if the data series extends to greater than 5
66  {
67  Env env(*this);
68  env.fund(
69  env.current()->fees().accountReserve(1) +
70  env.current()->fees().base * 2,
71  owner);
72  Oracle oracle(env, {.owner = owner});
73  BEAST_EXPECT(oracle.exists());
74  oracle.set(UpdateArg{
75  .series =
76  {
77  {"XRP", "EUR", 740, 1},
78  {"XRP", "GBP", 740, 1},
79  {"XRP", "CNY", 740, 1},
80  {"XRP", "CAD", 740, 1},
81  {"XRP", "AUD", 740, 1},
82  },
83  .err = ter(tecINSUFFICIENT_RESERVE)});
84  }
85 
86  {
87  Env env(*this);
88  env.fund(XRP(1'000), owner);
89  Oracle oracle(env, {.owner = owner}, false);
90 
91  // Invalid flag
92  oracle.set(
93  CreateArg{.flags = tfSellNFToken, .err = ter(temINVALID_FLAG)});
94 
95  // Duplicate token pair
96  oracle.set(CreateArg{
97  .series = {{"XRP", "USD", 740, 1}, {"XRP", "USD", 750, 1}},
98  .err = ter(temMALFORMED)});
99 
100  // Price is not included
101  oracle.set(CreateArg{
102  .series =
103  {{"XRP", "USD", 740, 1}, {"XRP", "EUR", std::nullopt, 1}},
104  .err = ter(temMALFORMED)});
105 
106  // Token pair is in update and delete
107  oracle.set(CreateArg{
108  .series =
109  {{"XRP", "USD", 740, 1}, {"XRP", "USD", std::nullopt, 1}},
110  .err = ter(temMALFORMED)});
111  // Token pair is in add and delete
112  oracle.set(CreateArg{
113  .series =
114  {{"XRP", "EUR", 740, 1}, {"XRP", "EUR", std::nullopt, 1}},
115  .err = ter(temMALFORMED)});
116 
117  // Array of token pair is 0 or exceeds 10
118  oracle.set(CreateArg{
119  .series =
120  {{"XRP", "US1", 740, 1},
121  {"XRP", "US2", 750, 1},
122  {"XRP", "US3", 740, 1},
123  {"XRP", "US4", 750, 1},
124  {"XRP", "US5", 740, 1},
125  {"XRP", "US6", 750, 1},
126  {"XRP", "US7", 740, 1},
127  {"XRP", "US8", 750, 1},
128  {"XRP", "US9", 740, 1},
129  {"XRP", "U10", 750, 1},
130  {"XRP", "U11", 740, 1}},
131  .err = ter(temARRAY_TOO_LARGE)});
132  oracle.set(CreateArg{.series = {}, .err = ter(temARRAY_EMPTY)});
133  }
134 
135  // Array of token pair exceeds 10 after update
136  {
137  Env env{*this};
138  env.fund(XRP(1'000), owner);
139 
140  Oracle oracle(
141  env,
142  CreateArg{
143  .owner = owner, .series = {{{"XRP", "USD", 740, 1}}}});
144  oracle.set(UpdateArg{
145  .series =
146  {
147  {"XRP", "US1", 740, 1},
148  {"XRP", "US2", 750, 1},
149  {"XRP", "US3", 740, 1},
150  {"XRP", "US4", 750, 1},
151  {"XRP", "US5", 740, 1},
152  {"XRP", "US6", 750, 1},
153  {"XRP", "US7", 740, 1},
154  {"XRP", "US8", 750, 1},
155  {"XRP", "US9", 740, 1},
156  {"XRP", "U10", 750, 1},
157  },
158  .err = ter(tecARRAY_TOO_LARGE)});
159  }
160 
161  {
162  Env env(*this);
163  env.fund(XRP(1'000), owner);
164  Oracle oracle(env, {.owner = owner}, false);
165 
166  // Symbol class or provider not included on create
167  oracle.set(CreateArg{
168  .assetClass = std::nullopt,
169  .provider = "provider",
170  .err = ter(temMALFORMED)});
171  oracle.set(CreateArg{
172  .assetClass = "currency",
173  .provider = std::nullopt,
174  .uri = "URI",
175  .err = ter(temMALFORMED)});
176 
177  // Symbol class or provider are included on update
178  // and don't match the current values
179  oracle.set(CreateArg{});
180  BEAST_EXPECT(oracle.exists());
181  oracle.set(UpdateArg{
182  .series = {{"XRP", "USD", 740, 1}},
183  .provider = "provider1",
184  .err = ter(temMALFORMED)});
185  oracle.set(UpdateArg{
186  .series = {{"XRP", "USD", 740, 1}},
187  .assetClass = "currency1",
188  .err = ter(temMALFORMED)});
189  }
190 
191  {
192  Env env(*this);
193  env.fund(XRP(1'000), owner);
194  Oracle oracle(env, {.owner = owner}, false);
195 
196  // Fields too long
197  // Symbol class
198  std::string assetClass(17, '0');
199  oracle.set(
200  CreateArg{.assetClass = assetClass, .err = ter(temMALFORMED)});
201  // provider
202  std::string const large(257, '0');
203  oracle.set(CreateArg{.provider = large, .err = ter(temMALFORMED)});
204  // URI
205  oracle.set(CreateArg{.uri = large, .err = ter(temMALFORMED)});
206  }
207 
208  {
209  // Different owner creates a new object and fails because
210  // of missing fields currency/provider
211  Env env(*this);
212  Account const some("some");
213  env.fund(XRP(1'000), owner);
214  env.fund(XRP(1'000), some);
215  Oracle oracle(env, {.owner = owner});
216  BEAST_EXPECT(oracle.exists());
217  oracle.set(UpdateArg{
218  .owner = some,
219  .series = {{"XRP", "USD", 740, 1}},
220  .err = ter(temMALFORMED)});
221  }
222 
223  {
224  // Invalid update time
225  using namespace std::chrono;
226  Env env(*this);
227  env.fund(XRP(1'000), owner);
228  Oracle oracle(env, {.owner = owner});
229  BEAST_EXPECT(oracle.exists());
230  env.close(seconds(400));
231  // Less than the last close time - 300s
232  oracle.set(UpdateArg{
233  .series = {{"XRP", "USD", 740, 1}},
234  .lastUpdateTime = testStartTime.count() + 400 - 301,
235  .err = ter(tecINVALID_UPDATE_TIME)});
236  // Greater than last close time + 300s
237  oracle.set(UpdateArg{
238  .series = {{"XRP", "USD", 740, 1}},
239  .lastUpdateTime = testStartTime.count() + 400 + 301,
240  .err = ter(tecINVALID_UPDATE_TIME)});
241  oracle.set(UpdateArg{.series = {{"XRP", "USD", 740, 1}}});
242  BEAST_EXPECT(
243  oracle.expectLastUpdateTime(testStartTime.count() + 450));
244  // Less than the previous lastUpdateTime
245  oracle.set(UpdateArg{
246  .series = {{"XRP", "USD", 740, 1}},
247  .lastUpdateTime = testStartTime.count() + 449,
248  .err = ter(tecINVALID_UPDATE_TIME)});
249  }
250 
251  {
252  // delete token pair that doesn't exist
253  Env env(*this);
254  env.fund(XRP(1'000), owner);
255  Oracle oracle(env, {.owner = owner});
256  BEAST_EXPECT(oracle.exists());
257  oracle.set(UpdateArg{
258  .series = {{"XRP", "EUR", std::nullopt, std::nullopt}},
259  .err = ter(tecTOKEN_PAIR_NOT_FOUND)});
260  // delete all token pairs
261  oracle.set(UpdateArg{
262  .series = {{"XRP", "USD", std::nullopt, std::nullopt}},
263  .err = ter(tecARRAY_EMPTY)});
264  }
265 
266  {
267  // same BaseAsset and QuoteAsset
268  Env env(*this);
269  env.fund(XRP(1'000), owner);
270  Oracle oracle(
271  env,
272  {.owner = owner,
273  .series = {{"USD", "USD", 740, 1}},
274  .err = ter(temMALFORMED)});
275  }
276 
277  {
278  // Scale is greater than maxPriceScale
279  Env env(*this);
280  env.fund(XRP(1'000), owner);
281  Oracle oracle(
282  env,
283  {.owner = owner,
284  .series = {{"USD", "BTC", 740, maxPriceScale + 1}},
285  .err = ter(temMALFORMED)});
286  }
287  }
288 
289  void
290  testCreate()
291  {
292  testcase("Create");
293  using namespace jtx;
294  Account const owner("owner");
295 
296  auto test = [&](Env& env, DataSeries const& series, std::uint16_t adj) {
297  env.fund(XRP(1'000), owner);
298  auto const count = ownerCount(env, owner);
299  Oracle oracle(env, {.owner = owner, .series = series});
300  BEAST_EXPECT(oracle.exists());
301  BEAST_EXPECT(ownerCount(env, owner) == (count + adj));
302  BEAST_EXPECT(oracle.expectLastUpdateTime(946694810));
303  };
304 
305  {
306  // owner count is adjusted by 1
307  Env env(*this);
308  test(env, {{"XRP", "USD", 740, 1}}, 1);
309  }
310 
311  {
312  // owner count is adjusted by 2
313  Env env(*this);
314  test(
315  env,
316  {{"XRP", "USD", 740, 1},
317  {"BTC", "USD", 740, 1},
318  {"ETH", "USD", 740, 1},
319  {"CAN", "USD", 740, 1},
320  {"YAN", "USD", 740, 1},
321  {"GBP", "USD", 740, 1}},
322  2);
323  }
324 
325  {
326  // Different owner creates a new object
327  Env env(*this);
328  Account const some("some");
329  env.fund(XRP(1'000), owner);
330  env.fund(XRP(1'000), some);
331  Oracle oracle(env, {.owner = owner});
332  BEAST_EXPECT(oracle.exists());
333  oracle.set(CreateArg{
334  .owner = some, .series = {{"912810RR9", "USD", 740, 1}}});
335  BEAST_EXPECT(Oracle::exists(env, some, oracle.documentID()));
336  }
337  }
338 
339  void
341  {
342  testcase("Invalid Delete");
343 
344  using namespace jtx;
345  Env env(*this);
346  Account const owner("owner");
347  env.fund(XRP(1'000), owner);
348  Oracle oracle(env, {.owner = owner});
349  BEAST_EXPECT(oracle.exists());
350 
351  {
352  // Invalid account
353  Account const bad("bad");
354  env.memoize(bad);
355  oracle.remove(
356  {.owner = bad, .seq = seq(1), .err = ter(terNO_ACCOUNT)});
357  }
358 
359  // Invalid Sequence
360  oracle.remove({.documentID = 2, .err = ter(tecNO_ENTRY)});
361 
362  // Invalid owner
363  Account const invalid("invalid");
364  env.fund(XRP(1'000), invalid);
365  oracle.remove({.owner = invalid, .err = ter(tecNO_ENTRY)});
366  }
367 
368  void
370  {
371  testcase("Delete");
372  using namespace jtx;
373  Account const owner("owner");
374 
375  auto test = [&](Env& env, DataSeries const& series, std::uint16_t adj) {
376  env.fund(XRP(1'000), owner);
377  Oracle oracle(env, {.owner = owner, .series = series});
378  auto const count = ownerCount(env, owner);
379  BEAST_EXPECT(oracle.exists());
380  oracle.remove({});
381  BEAST_EXPECT(!oracle.exists());
382  BEAST_EXPECT(ownerCount(env, owner) == (count - adj));
383  };
384 
385  {
386  // owner count is adjusted by 1
387  Env env(*this);
388  test(env, {{"XRP", "USD", 740, 1}}, 1);
389  }
390 
391  {
392  // owner count is adjusted by 2
393  Env env(*this);
394  test(
395  env,
396  {
397  {"XRP", "USD", 740, 1},
398  {"BTC", "USD", 740, 1},
399  {"ETH", "USD", 740, 1},
400  {"CAN", "USD", 740, 1},
401  {"YAN", "USD", 740, 1},
402  {"GBP", "USD", 740, 1},
403  },
404  2);
405  }
406 
407  {
408  // deleting the account deletes the oracles
409  Env env(*this);
410  auto const alice = Account("alice");
411  auto const acctDelFee{drops(env.current()->fees().increment)};
412  env.fund(XRP(1'000), owner);
413  env.fund(XRP(1'000), alice);
414  Oracle oracle(
415  env, {.owner = owner, .series = {{"XRP", "USD", 740, 1}}});
416  Oracle oracle1(
417  env,
418  {.owner = owner,
419  .documentID = 2,
420  .series = {{"XRP", "EUR", 740, 1}}});
421  BEAST_EXPECT(ownerCount(env, owner) == 2);
422  BEAST_EXPECT(oracle.exists());
423  BEAST_EXPECT(oracle1.exists());
424  auto const index = env.closed()->seq();
425  auto const hash = env.closed()->info().hash;
426  for (int i = 0; i < 256; ++i)
427  env.close();
428  env(acctdelete(owner, alice), fee(acctDelFee));
429  env.close();
430  BEAST_EXPECT(!oracle.exists());
431  BEAST_EXPECT(!oracle1.exists());
432 
433  // can still get the oracles via the ledger index or hash
434  auto verifyLedgerData = [&](auto const& field, auto const& value) {
435  Json::Value jvParams;
436  jvParams[field] = value;
437  jvParams[jss::binary] = false;
438  jvParams[jss::type] = jss::oracle;
439  Json::Value jrr = env.rpc(
440  "json",
441  "ledger_data",
442  boost::lexical_cast<std::string>(jvParams));
443  BEAST_EXPECT(jrr[jss::result][jss::state].size() == 2);
444  };
445  verifyLedgerData(jss::ledger_index, index);
446  verifyLedgerData(jss::ledger_hash, to_string(hash));
447  }
448  }
449 
450  void
451  testUpdate()
452  {
453  testcase("Update");
454  using namespace jtx;
455  Account const owner("owner");
456 
457  {
458  Env env(*this);
459  env.fund(XRP(1'000), owner);
460  auto count = ownerCount(env, owner);
461  Oracle oracle(env, {.owner = owner});
462  BEAST_EXPECT(oracle.exists());
463 
464  // update existing pair
465  oracle.set(UpdateArg{.series = {{"XRP", "USD", 740, 2}}});
466  BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 740, 2}}));
467  // owner count is increased by 1 since the oracle object is added
468  // with one token pair
469  count += 1;
470  BEAST_EXPECT(ownerCount(env, owner) == count);
471 
472  // add new pairs, not-included pair is reset
473  oracle.set(UpdateArg{.series = {{"XRP", "EUR", 700, 2}}});
474  BEAST_EXPECT(oracle.expectPrice(
475  {{"XRP", "USD", 0, 0}, {"XRP", "EUR", 700, 2}}));
476  // owner count is not changed since the number of pairs is 2
477  BEAST_EXPECT(ownerCount(env, owner) == count);
478 
479  // update both pairs
480  oracle.set(UpdateArg{
481  .series = {{"XRP", "USD", 741, 2}, {"XRP", "EUR", 710, 2}}});
482  BEAST_EXPECT(oracle.expectPrice(
483  {{"XRP", "USD", 741, 2}, {"XRP", "EUR", 710, 2}}));
484  // owner count is not changed since the number of pairs is 2
485  BEAST_EXPECT(ownerCount(env, owner) == count);
486 
487  // owner count is increased by 1 since the number of pairs is 6
488  oracle.set(UpdateArg{
489  .series = {
490  {"BTC", "USD", 741, 2},
491  {"ETH", "EUR", 710, 2},
492  {"YAN", "EUR", 710, 2},
493  {"CAN", "EUR", 710, 2},
494  }});
495  count += 1;
496  BEAST_EXPECT(ownerCount(env, owner) == count);
497 
498  // update two pairs and delete four
499  oracle.set(UpdateArg{
500  .series = {{"BTC", "USD", std::nullopt, std::nullopt}}});
501  oracle.set(UpdateArg{
502  .series = {
503  {"XRP", "USD", 742, 2},
504  {"XRP", "EUR", 711, 2},
505  {"ETH", "EUR", std::nullopt, std::nullopt},
506  {"YAN", "EUR", std::nullopt, std::nullopt},
507  {"CAN", "EUR", std::nullopt, std::nullopt}}});
508  BEAST_EXPECT(oracle.expectPrice(
509  {{"XRP", "USD", 742, 2}, {"XRP", "EUR", 711, 2}}));
510  // owner count is decreased by 1 since the number of pairs is 2
511  count -= 1;
512  BEAST_EXPECT(ownerCount(env, owner) == count);
513  }
514 
515  // Min reserve to create and update
516  {
517  Env env(*this);
518  env.fund(
519  env.current()->fees().accountReserve(1) +
520  env.current()->fees().base * 2,
521  owner);
522  Oracle oracle(env, {.owner = owner});
523  oracle.set(UpdateArg{.series = {{"XRP", "USD", 742, 2}}});
524  }
525  }
526 
527  void
529  {
530  testcase("Multisig");
531  using namespace jtx;
532  Oracle::setFee(100'000);
533 
534  Env env(*this, features);
535  Account const alice{"alice", KeyType::secp256k1};
536  Account const bogie{"bogie", KeyType::secp256k1};
537  Account const ed{"ed", KeyType::secp256k1};
538  Account const becky{"becky", KeyType::ed25519};
539  Account const zelda{"zelda", KeyType::secp256k1};
540  Account const bob{"bob", KeyType::secp256k1};
541  env.fund(XRP(10'000), alice, becky, zelda, ed, bob);
542 
543  // alice uses a regular key with the master disabled.
544  Account const alie{"alie", KeyType::secp256k1};
545  env(regkey(alice, alie));
546  env(fset(alice, asfDisableMaster), sig(alice));
547 
548  // Attach signers to alice.
549  env(signers(alice, 2, {{becky, 1}, {bogie, 1}, {ed, 2}}), sig(alie));
550  env.close();
551  // if multiSignReserve disabled then its 2 + 1 per signer
552  int const signerListOwners{features[featureMultiSignReserve] ? 1 : 5};
553  env.require(owners(alice, signerListOwners));
554 
555  // Create
556  // Force close (true) and time advancement because the close time
557  // is no longer 0.
558  Oracle oracle(env, CreateArg{.owner = alice, .close = true}, false);
559  oracle.set(CreateArg{.msig = msig(becky), .err = ter(tefBAD_QUORUM)});
560  oracle.set(
561  CreateArg{.msig = msig(zelda), .err = ter(tefBAD_SIGNATURE)});
562  oracle.set(CreateArg{.msig = msig(becky, bogie)});
563  BEAST_EXPECT(oracle.exists());
564 
565  // Update
566  oracle.set(UpdateArg{
567  .series = {{"XRP", "USD", 740, 1}},
568  .msig = msig(becky),
569  .err = ter(tefBAD_QUORUM)});
570  oracle.set(UpdateArg{
571  .series = {{"XRP", "USD", 740, 1}},
572  .msig = msig(zelda),
573  .err = ter(tefBAD_SIGNATURE)});
574  oracle.set(UpdateArg{
575  .series = {{"XRP", "USD", 741, 1}}, .msig = msig(becky, bogie)});
576  BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 741, 1}}));
577  // remove the signer list
578  env(signers(alice, jtx::none), sig(alie));
579  env.close();
580  env.require(owners(alice, 1));
581  // create new signer list
582  env(signers(alice, 2, {{zelda, 1}, {bob, 1}, {ed, 2}}), sig(alie));
583  env.close();
584  // old list fails
585  oracle.set(UpdateArg{
586  .series = {{"XRP", "USD", 740, 1}},
587  .msig = msig(becky, bogie),
588  .err = ter(tefBAD_SIGNATURE)});
589  // updated list succeeds
590  oracle.set(UpdateArg{
591  .series = {{"XRP", "USD", 7412, 2}}, .msig = msig(zelda, bob)});
592  BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 7412, 2}}));
593  oracle.set(
594  UpdateArg{.series = {{"XRP", "USD", 74245, 3}}, .msig = msig(ed)});
595  BEAST_EXPECT(oracle.expectPrice({{"XRP", "USD", 74245, 3}}));
596 
597  // Remove
598  oracle.remove({.msig = msig(bob), .err = ter(tefBAD_QUORUM)});
599  oracle.remove({.msig = msig(becky), .err = ter(tefBAD_SIGNATURE)});
600  oracle.remove({.msig = msig(ed)});
601  BEAST_EXPECT(!oracle.exists());
602  }
603 
604  void
606  {
607  testcase("Amendment");
608  using namespace jtx;
609 
610  auto const features = supported_amendments() - featurePriceOracle;
611  Account const owner("owner");
612  Env env(*this, features);
613 
614  env.fund(XRP(1'000), owner);
615  {
616  Oracle oracle(env, {.owner = owner, .err = ter(temDISABLED)});
617  }
618 
619  {
620  Oracle oracle(env, {.owner = owner}, false);
621  oracle.remove({.err = ter(temDISABLED)});
622  }
623  }
624 
625  void
626  testLedgerEntry()
627  {
628  testcase("Ledger Entry");
629  using namespace jtx;
630 
631  Env env(*this);
632  std::vector<AccountID> accounts;
633  std::vector<std::uint32_t> oracles;
634  for (int i = 0; i < 10; ++i)
635  {
636  Account const owner(std::string("owner") + std::to_string(i));
637  env.fund(XRP(1'000), owner);
638  // different accounts can have the same asset pair
639  Oracle oracle(env, {.owner = owner, .documentID = i});
640  accounts.push_back(owner.id());
641  oracles.push_back(oracle.documentID());
642  // same account can have different asset pair
643  Oracle oracle1(env, {.owner = owner, .documentID = i + 10});
644  accounts.push_back(owner.id());
645  oracles.push_back(oracle1.documentID());
646  }
647  for (int i = 0; i < accounts.size(); ++i)
648  {
649  auto const jv = [&]() {
650  // document id is uint32
651  if (i % 2)
652  return Oracle::ledgerEntry(env, accounts[i], oracles[i]);
653  // document id is string
654  return Oracle::ledgerEntry(
655  env, accounts[i], std::to_string(oracles[i]));
656  }();
657  try
658  {
659  BEAST_EXPECT(
660  jv[jss::node][jss::Owner] == to_string(accounts[i]));
661  }
662  catch (...)
663  {
664  fail();
665  }
666  }
667  }
668 
669 public:
670  void
671  run() override
672  {
673  using namespace jtx;
674  auto const all = supported_amendments();
675  testInvalidSet();
676  testInvalidDelete();
677  testCreate();
678  testDelete();
679  testUpdate();
680  testAmendment();
681  for (auto const& features :
682  {all,
685  testMultisig(features);
686  testLedgerEntry();
687  }
688 };
689 
690 BEAST_DEFINE_TESTSUITE(Oracle, app, ripple);
691 
692 } // namespace oracle
693 
694 } // namespace jtx
695 
696 } // namespace test
697 
698 } // namespace ripple
ripple::sfOwnerCount
const SF_UINT32 sfOwnerCount
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::jtx::none
static const none_t none
Definition: tags.h:34
ripple::test::jtx::oracle::UpdateArg::provider
std::optional< std::string > provider
Definition: Oracle.h:63
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::test::jtx::oracle::CreateArg::msig
std::optional< jtx::msig > msig
Definition: Oracle.h:49
ripple::test::jtx::oracle::Oracle_test::testDelete
void testDelete()
Definition: Oracle_test.cpp:369
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::test::jtx::oracle::Oracle_test
Definition: Oracle_test.cpp:28
ripple::test::jtx::owners
Match the number of items in the account's owner directory.
Definition: owners.h:69
ripple::test::jtx::oracle::Oracle_test::testAmendment
void testAmendment()
Definition: Oracle_test.cpp:605
ripple::test::jtx::Env::require
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:489
ripple::TxSearched::all
@ all
ripple::keylet::oracle
Keylet oracle(AccountID const &account, std::uint32_t const &documentID) noexcept
Definition: Indexes.cpp:449
std::vector
STL class.
std::chrono::seconds
ripple::featureMultiSignReserve
const uint256 featureMultiSignReserve
ripple::test::jtx::oracle::Oracle_test::run
void run() override
Definition: Oracle_test.cpp:671
ripple::test::jtx::msig
Set a multisignature on a JTx.
Definition: multisign.h:63
ripple::test::jtx::oracle::CreateArg::owner
std::optional< AccountID > owner
Definition: Oracle.h:41
ripple::test::jtx::Account::id
AccountID id() const
Returns the Account ID.
Definition: Account.h:106
ripple::test::jtx::oracle::Oracle_test::testInvalidDelete
void testInvalidDelete()
Definition: Oracle_test.cpp:340
ripple::tefBAD_QUORUM
@ tefBAD_QUORUM
Definition: TER.h:177
ripple::asfDisableMaster
constexpr std::uint32_t asfDisableMaster
Definition: TxFlags.h:77
ripple::test::jtx::signers
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
Definition: multisign.cpp:35
ripple::featureExpandedSignerList
const uint256 featureExpandedSignerList
ripple::test::jtx::oracle::testStartTime
constexpr static std::chrono::seconds testStartTime
Definition: Oracle.h:88
ripple::test::jtx::oracle::UpdateArg
Definition: Oracle.h:57
ripple::test::jtx::oracle::CreateArg
Definition: Oracle.h:39
ripple::test::jtx::oracle::Oracle_test::testInvalidSet
void testInvalidSet()
Definition: Oracle_test.cpp:42
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
std::to_string
T to_string(T... args)
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::tecINVALID_UPDATE_TIME
@ tecINVALID_UPDATE_TIME
Definition: TER.h:337
ripple::ValStatus::current
@ current
This was a new validation and was added.
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
std::uint32_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:34
ripple::ManifestDisposition::invalid
@ invalid
Timely, but invalid signature.
ripple::KeyType::secp256k1
@ secp256k1
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:213
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::test::jtx::oracle::UpdateArg::series
DataSeries series
Definition: Oracle.h:61
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::jtx::oracle::Oracle::exists
bool exists() const
Definition: Oracle.h:140
ripple::test::jtx::regkey
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:216
ripple::featurePriceOracle
const uint256 featurePriceOracle
ripple::FeatureBitset
Definition: Feature.h:113
std::chrono::seconds::count
T count(T... args)
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:290
ripple::test::jtx::oracle::Oracle_test::testMultisig
void testMultisig(FeatureBitset features)
Definition: Oracle_test.cpp:528
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:38
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:289
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:86
ripple::test::jtx::oracle::Oracle
Oracle class facilitates unit-testing of the Price Oracle feature.
Definition: Oracle.h:95
ripple::test::jtx::Env::memoize
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:156
ripple::tecARRAY_TOO_LARGE
@ tecARRAY_TOO_LARGE
Definition: TER.h:340
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:311
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::TxSearched::some
@ some
ripple::test::jtx::oracle::Oracle_test::ownerCount
static std::uint32_t ownerCount(jtx::Env const &env, jtx::Account const &acct)
Definition: Oracle_test.cpp:33
ripple::tefBAD_SIGNATURE
@ tefBAD_SIGNATURE
Definition: TER.h:176