20#include <test/jtx/Oracle.h>
22#include <xrpl/protocol/jss.h>
52 env.
fund(env.
current()->fees().accountReserve(0), owner);
60 env.
current()->fees().accountReserve(1) +
63 Oracle oracle(env, {.owner = owner});
64 BEAST_EXPECT(oracle.exists());
68 {
"XRP",
"EUR", 740, 1},
69 {
"XRP",
"GBP", 740, 1},
70 {
"XRP",
"CNY", 740, 1},
71 {
"XRP",
"CAD", 740, 1},
72 {
"XRP",
"AUD", 740, 1},
80 Oracle oracle(env, {.owner = owner},
false);
88 .
series = {{
"XRP",
"USD", 740, 1}, {
"XRP",
"USD", 750, 1}},
94 {{
"XRP",
"USD", 740, 1}, {
"XRP",
"EUR", std::nullopt, 1}},
100 {{
"XRP",
"USD", 740, 1}, {
"XRP",
"USD", std::nullopt, 1}},
105 {{
"XRP",
"EUR", 740, 1}, {
"XRP",
"EUR", std::nullopt, 1}},
111 {{
"XRP",
"US1", 740, 1},
112 {
"XRP",
"US2", 750, 1},
113 {
"XRP",
"US3", 740, 1},
114 {
"XRP",
"US4", 750, 1},
115 {
"XRP",
"US5", 740, 1},
116 {
"XRP",
"US6", 750, 1},
117 {
"XRP",
"US7", 740, 1},
118 {
"XRP",
"US8", 750, 1},
119 {
"XRP",
"US9", 740, 1},
120 {
"XRP",
"U10", 750, 1},
121 {
"XRP",
"U11", 740, 1}},
134 .
owner = owner, .series = {{{
"XRP",
"USD", 740, 1}}}});
138 {
"XRP",
"US1", 740, 1},
139 {
"XRP",
"US2", 750, 1},
140 {
"XRP",
"US3", 740, 1},
141 {
"XRP",
"US4", 750, 1},
142 {
"XRP",
"US5", 740, 1},
143 {
"XRP",
"US6", 750, 1},
144 {
"XRP",
"US7", 740, 1},
145 {
"XRP",
"US8", 750, 1},
146 {
"XRP",
"US9", 740, 1},
147 {
"XRP",
"U10", 750, 1},
155 Oracle oracle(env, {.owner = owner},
false);
160 .provider =
"provider",
164 .provider = std::nullopt,
171 BEAST_EXPECT(oracle.exists());
173 .
series = {{
"XRP",
"USD", 740, 1}},
174 .provider =
"provider1",
177 .
series = {{
"XRP",
"USD", 740, 1}},
178 .assetClass =
"currency1",
185 Oracle oracle(env, {.owner = owner},
false);
213 Oracle oracle(env, {.owner = owner});
214 BEAST_EXPECT(oracle.exists());
217 .series = {{
"XRP",
"USD", 740, 1}},
225 auto closeTime = [&]() {
226 return duration_cast<seconds>(
227 env.
current()->info().closeTime.time_since_epoch() -
232 Oracle oracle(env, {.owner = owner});
233 BEAST_EXPECT(oracle.exists());
237 .
series = {{
"XRP",
"USD", 740, 1}},
238 .lastUpdateTime =
static_cast<std::uint32_t>(closeTime() - 301),
242 .
series = {{
"XRP",
"USD", 740, 1}},
243 .lastUpdateTime =
static_cast<std::uint32_t>(closeTime() + 311),
246 BEAST_EXPECT(oracle.expectLastUpdateTime(
250 .
series = {{
"XRP",
"USD", 740, 1}},
255 .
series = {{
"XRP",
"USD", 740, 1}},
264 Oracle oracle(env, {.owner = owner});
265 BEAST_EXPECT(oracle.exists());
267 .
series = {{
"XRP",
"EUR", std::nullopt, std::nullopt}},
271 .
series = {{
"XRP",
"USD", std::nullopt, std::nullopt}},
282 .series = {{
"USD",
"USD", 740, 1}},
301 Oracle oracle(env, {.owner = owner});
304 {{
"XRP",
"EUR", std::nullopt, std::nullopt},
305 {
"XRP",
"EUR", 740, 1}},
309 .
series = {{
"XRP",
"EUR", std::nullopt, std::nullopt}},
314 .series = {{
"XRP",
"EUR", std::nullopt, std::nullopt}},
324 Oracle oracle1(env, {.owner = owner});
340 Oracle oracle(env, {.owner = owner, .series = series});
341 BEAST_EXPECT(oracle.exists());
342 BEAST_EXPECT(
ownerCount(env, owner) == (count + adj));
343 BEAST_EXPECT(oracle.expectLastUpdateTime(946694810));
349 test(env, {{
"XRP",
"USD", 740, 1}}, 1);
357 {{
"XRP",
"USD", 740, 1},
358 {
"BTC",
"USD", 740, 1},
359 {
"ETH",
"USD", 740, 1},
360 {
"CAN",
"USD", 740, 1},
361 {
"YAN",
"USD", 740, 1},
362 {
"GBP",
"USD", 740, 1}},
372 Oracle oracle(env, {.owner = owner});
373 BEAST_EXPECT(oracle.exists());
375 .
owner =
some, .series = {{
"912810RR9",
"USD", 740, 1}}});
389 Oracle oracle(env, {.owner = owner});
390 BEAST_EXPECT(oracle.exists());
424 Oracle oracle(env, {.owner = owner, .series = series});
426 BEAST_EXPECT(oracle.exists());
428 BEAST_EXPECT(!oracle.exists());
429 BEAST_EXPECT(
ownerCount(env, owner) == (count - adj));
435 test(env, {{
"XRP",
"USD", 740, 1}}, 1);
444 {
"XRP",
"USD", 740, 1},
445 {
"BTC",
"USD", 740, 1},
446 {
"ETH",
"USD", 740, 1},
447 {
"CAN",
"USD", 740, 1},
448 {
"YAN",
"USD", 740, 1},
449 {
"GBP",
"USD", 740, 1},
457 auto const alice =
Account(
"alice");
458 auto const acctDelFee{
drops(env.
current()->fees().increment)};
462 env, {.owner = owner, .series = {{
"XRP",
"USD", 740, 1}}});
467 .series = {{
"XRP",
"EUR", 740, 1}}});
469 BEAST_EXPECT(oracle.exists());
470 BEAST_EXPECT(oracle1.exists());
471 auto const index = env.
closed()->seq();
473 for (
int i = 0; i < 256; ++i)
477 BEAST_EXPECT(!oracle.exists());
478 BEAST_EXPECT(!oracle1.exists());
481 auto verifyLedgerData = [&](
auto const& field,
auto const& value) {
483 jvParams[field] = value;
484 jvParams[jss::binary] =
false;
485 jvParams[jss::type] = jss::oracle;
489 boost::lexical_cast<std::string>(jvParams));
490 BEAST_EXPECT(jrr[jss::result][jss::state].size() == 2);
492 verifyLedgerData(jss::ledger_index, index);
508 Oracle oracle(env, {.owner = owner});
509 BEAST_EXPECT(oracle.exists());
513 BEAST_EXPECT(oracle.expectPrice({{
"XRP",
"USD", 740, 2}}));
517 BEAST_EXPECT(
ownerCount(env, owner) == count);
521 BEAST_EXPECT(oracle.expectPrice(
522 {{
"XRP",
"USD", 0, 0}, {
"XRP",
"EUR", 700, 2}}));
524 BEAST_EXPECT(
ownerCount(env, owner) == count);
528 .
series = {{
"XRP",
"USD", 741, 2}, {
"XRP",
"EUR", 710, 2}}});
529 BEAST_EXPECT(oracle.expectPrice(
530 {{
"XRP",
"USD", 741, 2}, {
"XRP",
"EUR", 710, 2}}));
532 BEAST_EXPECT(
ownerCount(env, owner) == count);
537 {
"BTC",
"USD", 741, 2},
538 {
"ETH",
"EUR", 710, 2},
539 {
"YAN",
"EUR", 710, 2},
540 {
"CAN",
"EUR", 710, 2},
543 BEAST_EXPECT(
ownerCount(env, owner) == count);
547 .series = {{
"BTC",
"USD", std::nullopt, std::nullopt}}});
550 {
"XRP",
"USD", 742, 2},
551 {
"XRP",
"EUR", 711, 2},
552 {
"ETH",
"EUR", std::nullopt, std::nullopt},
553 {
"YAN",
"EUR", std::nullopt, std::nullopt},
554 {
"CAN",
"EUR", std::nullopt, std::nullopt}}});
555 BEAST_EXPECT(
oracle.expectPrice(
556 {{
"XRP",
"USD", 742, 2}, {
"XRP",
"EUR", 711, 2}}));
559 BEAST_EXPECT(
ownerCount(env, owner) == count);
566 env.current()->fees().accountReserve(1) +
567 env.current()->fees().base * 2,
569 Oracle
oracle(env, {.owner = owner});
570 oracle.set(UpdateArg{.series = {{
"XRP",
"USD", 742, 2}}});
577 testcase(
"Multisig");
579 Oracle::setFee(100'000);
581 Env env(*
this, features);
588 env.
fund(
XRP(10'000), alice, becky, zelda, ed, bob);
596 env(signers(alice, 2, {{becky, 1}, {bogie, 1}, {ed, 2}}),
sig(alie));
599 int const signerListOwners{features[featureMultiSignReserve] ? 1 : 5};
610 BEAST_EXPECT(oracle.exists());
614 .
series = {{
"XRP",
"USD", 740, 1}},
618 .
series = {{
"XRP",
"USD", 740, 1}},
622 .
series = {{
"XRP",
"USD", 741, 1}}, .msig =
msig(becky, bogie)});
623 BEAST_EXPECT(oracle.expectPrice({{
"XRP",
"USD", 741, 1}}));
625 env(signers(alice, jtx::none),
sig(alie));
627 env.require(
owners(alice, 1));
629 env(signers(alice, 2, {{zelda, 1}, {bob, 1}, {ed, 2}}), sig(alie));
632 oracle.set(UpdateArg{
633 .series = {{
"XRP",
"USD", 740, 1}},
634 .msig = msig(becky, bogie),
638 .series = {{
"XRP",
"USD", 7412, 2}}, .msig = msig(zelda, bob)});
639 BEAST_EXPECT(
oracle.expectPrice({{
"XRP",
"USD", 7412, 2}}));
641 UpdateArg{.series = {{
"XRP",
"USD", 74245, 3}}, .msig = msig(ed)});
642 BEAST_EXPECT(
oracle.expectPrice({{
"XRP",
"USD", 74245, 3}}));
645 oracle.remove({.msig = msig(bob), .err = ter(tefBAD_QUORUM)});
646 oracle.remove({.msig = msig(becky), .err = ter(tefBAD_SIGNATURE)});
647 oracle.remove({.msig = msig(ed)});
648 BEAST_EXPECT(!
oracle.exists());
654 testcase(
"Amendment");
659 Env env(*
this, features);
667 Oracle oracle(env, {.owner = owner},
false);
684 for (
auto const& features :
686 all - featureMultiSignReserve - featureExpandedSignerList,
687 all - featureExpandedSignerList})
688 testMultisig(features);
testcase_t testcase
Memberspace for declaring test cases.
Immutable cryptographic account descriptor.
A transaction testing environment.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
void memoize(Account const &account)
Associate AccountID with account.
Set a multisignature on a JTx.
Oracle class facilitates unit-testing of the Price Oracle feature.
Match the number of items in the account's owner directory.
Set the regular signature on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Keylet oracle(AccountID const &account, std::uint32_t const &documentID) noexcept
static constexpr std::chrono::seconds testStartTime
std::uint32_t ownerCount(Env const &env, Account const &account)
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::size_t constexpr maxPriceScale
The maximum price scaling factor.
constexpr std::uint32_t const tfSellNFToken
constexpr std::uint32_t asfDisableMaster
@ invalid
Timely, but invalid signature.
@ tecINSUFFICIENT_RESERVE
@ tecTOKEN_PAIR_NOT_FOUND
static constexpr std::chrono::seconds epoch_offset
Clock for measuring the network time.
std::string to_string(base_uint< Bits, Tag > const &a)
std::optional< AnyValue > uri
std::optional< AnyValue > assetClass
std::optional< AccountID > owner
std::optional< jtx::msig > msig
std::optional< AnyValue > provider
void run() override
Runs the suite.
void testMultisig(FeatureBitset features)
std::optional< AnyValue > documentID
std::optional< AccountID > owner
Set the sequence number on a JTx.