1#include <test/jtx/Oracle.h> 
    3#include <xrpl/protocol/jss.h> 
   30                 .fee = 
static_cast<int>(env.
current()->fees().base.drops()),
 
   37            env.
fund(env.
current()->fees().accountReserve(0), owner);
 
   41                 .fee = 
static_cast<int>(env.
current()->fees().base.drops()),
 
   48                env.
current()->fees().accountReserve(1) +
 
   54                 .fee = 
static_cast<int>(env.
current()->fees().base.drops())});
 
   55            BEAST_EXPECT(oracle.exists());
 
   59                        {
"XRP", 
"EUR", 740, 1},
 
   60                        {
"XRP", 
"GBP", 740, 1},
 
   61                        {
"XRP", 
"CNY", 740, 1},
 
   62                        {
"XRP", 
"CAD", 740, 1},
 
   63                        {
"XRP", 
"AUD", 740, 1},
 
   65                .fee = 
static_cast<int>(env.
current()->fees().base.drops()),
 
   72                static_cast<int>(env.
current()->fees().base.drops());
 
   74            Oracle oracle(env, {.owner = owner, .fee = baseFee}, 
false);
 
   84                .
series = {{
"XRP", 
"USD", 740, 1}, {
"XRP", 
"USD", 750, 1}},
 
   91                    {{
"XRP", 
"USD", 740, 1}, {
"XRP", 
"EUR", 
std::nullopt, 1}},
 
   98                    {{
"XRP", 
"USD", 740, 1}, {
"XRP", 
"USD", 
std::nullopt, 1}},
 
  104                    {{
"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}},
 
  132                static_cast<int>(env.current()->fees().base.drops());
 
  139                    .series = {{{
"XRP", 
"USD", 740, 1}}},
 
  144                        {
"XRP", 
"US1", 740, 1},
 
  145                        {
"XRP", 
"US2", 750, 1},
 
  146                        {
"XRP", 
"US3", 740, 1},
 
  147                        {
"XRP", 
"US4", 750, 1},
 
  148                        {
"XRP", 
"US5", 740, 1},
 
  149                        {
"XRP", 
"US6", 750, 1},
 
  150                        {
"XRP", 
"US7", 740, 1},
 
  151                        {
"XRP", 
"US8", 750, 1},
 
  152                        {
"XRP", 
"US9", 740, 1},
 
  153                        {
"XRP", 
"U10", 750, 1},
 
  162                static_cast<int>(env.
current()->fees().base.drops());
 
  164            Oracle oracle(env, {.owner = owner, .fee = baseFee}, 
false);
 
  169                .provider = 
"provider",
 
  182                .
fee = 
static_cast<int>(env.
current()->fees().base.drops())});
 
  183            BEAST_EXPECT(oracle.exists());
 
  185                .
series = {{
"XRP", 
"USD", 740, 1}},
 
  186                .provider = 
"provider1",
 
  190                .
series = {{
"XRP", 
"USD", 740, 1}},
 
  191                .assetClass = 
"currency1",
 
  199                static_cast<int>(env.
current()->fees().base.drops());
 
  201            Oracle oracle(env, {.owner = owner, .fee = baseFee}, 
false);
 
  234                static_cast<int>(env.
current()->fees().base.drops());
 
  238            Oracle oracle(env, {.owner = owner, .fee = baseFee});
 
  239            BEAST_EXPECT(oracle.exists());
 
  242                .series = {{
"XRP", 
"USD", 740, 1}},
 
  252                static_cast<int>(env.
current()->fees().base.drops());
 
  253            auto closeTime = [&]() {
 
  254                return duration_cast<seconds>(
 
  255                           env.
current()->info().closeTime.time_since_epoch() -
 
  260            Oracle oracle(env, {.owner = owner, .fee = baseFee});
 
  261            BEAST_EXPECT(oracle.exists());
 
  265                .
series = {{
"XRP", 
"USD", 740, 1}},
 
  266                .lastUpdateTime = 
static_cast<std::uint32_t>(closeTime() - 301),
 
  271                .
series = {{
"XRP", 
"USD", 740, 1}},
 
  272                .lastUpdateTime = 
static_cast<std::uint32_t>(closeTime() + 311),
 
  277            BEAST_EXPECT(oracle.expectLastUpdateTime(
 
  281                .
series = {{
"XRP", 
"USD", 740, 1}},
 
  287                .
series = {{
"XRP", 
"USD", 740, 1}},
 
  297                static_cast<int>(env.
current()->fees().base.drops());
 
  299            Oracle oracle(env, {.owner = owner, .fee = baseFee});
 
  300            BEAST_EXPECT(oracle.exists());
 
  316                static_cast<int>(env.
current()->fees().base.drops());
 
  321                 .series = {{
"USD", 
"USD", 740, 1}},
 
  330                static_cast<int>(env.
current()->fees().base.drops());
 
  344                static_cast<int>(env.
current()->fees().base.drops());
 
  346            Oracle oracle(env, {.owner = owner, .fee = baseFee});
 
  350                     {
"XRP", 
"EUR", 740, 1}},
 
  375                 .fee = 
static_cast<int>(env.
current()->fees().base.drops())});
 
 
  390                static_cast<int>(env.
current()->fees().base.drops());
 
  394                env, {.owner = owner, .series = series, .fee = baseFee});
 
  395            BEAST_EXPECT(oracle.exists());
 
  396            BEAST_EXPECT(
ownerCount(env, owner) == (count + adj));
 
  397            auto const entry = oracle.ledgerEntry();
 
  398            BEAST_EXPECT(entry[jss::node][jss::Owner] == owner.
human());
 
  399            if (features[fixIncludeKeyletFields])
 
  402                    entry[jss::node][jss::OracleDocumentID] ==
 
  403                    oracle.documentID());
 
  407                BEAST_EXPECT(!entry[jss::node].isMember(jss::OracleDocumentID));
 
  409            BEAST_EXPECT(oracle.expectLastUpdateTime(946694810));
 
  414            Env env(*
this, features);
 
  415            test(env, {{
"XRP", 
"USD", 740, 1}}, 1);
 
  420            Env env(*
this, features);
 
  423                {{
"XRP", 
"USD", 740, 1},
 
  424                 {
"BTC", 
"USD", 740, 1},
 
  425                 {
"ETH", 
"USD", 740, 1},
 
  426                 {
"CAN", 
"USD", 740, 1},
 
  427                 {
"YAN", 
"USD", 740, 1},
 
  428                 {
"GBP", 
"USD", 740, 1}},
 
  434            Env env(*
this, features);
 
  436                static_cast<int>(env.
current()->fees().base.drops());
 
  440            Oracle oracle(env, {.owner = owner, .fee = baseFee});
 
  441            BEAST_EXPECT(oracle.exists());
 
  444                .series = {{
"912810RR9", 
"USD", 740, 1}},
 
 
  458            static_cast<int>(env.
current()->fees().base.drops());
 
  461        Oracle oracle(env, {.owner = owner, .fee = baseFee});
 
  462        BEAST_EXPECT(oracle.exists());
 
 
  504                static_cast<int>(env.
current()->fees().base.drops());
 
  507                env, {.owner = owner, .series = series, .fee = baseFee});
 
  509            BEAST_EXPECT(oracle.exists());
 
  510            oracle.remove({.fee = baseFee});
 
  511            BEAST_EXPECT(!oracle.exists());
 
  512            BEAST_EXPECT(
ownerCount(env, owner) == (count - adj));
 
  518            test(env, {{
"XRP", 
"USD", 740, 1}}, 1);
 
  527                    {
"XRP", 
"USD", 740, 1},
 
  528                    {
"BTC", 
"USD", 740, 1},
 
  529                    {
"ETH", 
"USD", 740, 1},
 
  530                    {
"CAN", 
"USD", 740, 1},
 
  531                    {
"YAN", 
"USD", 740, 1},
 
  532                    {
"GBP", 
"USD", 740, 1},
 
  541                static_cast<int>(env.
current()->fees().base.drops());
 
  543            auto const alice = 
Account(
"alice");
 
  544            auto const acctDelFee{
drops(env.
current()->fees().increment)};
 
  550                 .series = {{
"XRP", 
"USD", 740, 1}},
 
  556                 .series = {{
"XRP", 
"EUR", 740, 1}},
 
  559            BEAST_EXPECT(oracle.exists());
 
  560            BEAST_EXPECT(oracle1.exists());
 
  561            auto const index = env.
closed()->seq();
 
  563            for (
int i = 0; i < 256; ++i)
 
  567            BEAST_EXPECT(!oracle.exists());
 
  568            BEAST_EXPECT(!oracle1.exists());
 
  571            auto verifyLedgerData = [&](
auto const& field, 
auto const& value) {
 
  573                jvParams[field] = value;
 
  574                jvParams[jss::binary] = 
false;
 
  575                jvParams[jss::type] = jss::oracle;
 
  578                BEAST_EXPECT(jrr[jss::result][jss::state].size() == 2);
 
  580            verifyLedgerData(jss::ledger_index, index);
 
 
  595                static_cast<int>(env.
current()->fees().base.drops());
 
  598            Oracle oracle(env, {.owner = owner, .fee = baseFee});
 
  599            BEAST_EXPECT(oracle.exists());
 
  604            BEAST_EXPECT(oracle.expectPrice({{
"XRP", 
"USD", 740, 2}}));
 
  608            BEAST_EXPECT(
ownerCount(env, owner) == count);
 
  613            BEAST_EXPECT(oracle.expectPrice(
 
  614                {{
"XRP", 
"USD", 0, 0}, {
"XRP", 
"EUR", 700, 2}}));
 
  616            BEAST_EXPECT(
ownerCount(env, owner) == count);
 
  620                .
series = {{
"XRP", 
"USD", 741, 2}, {
"XRP", 
"EUR", 710, 2}},
 
  622            BEAST_EXPECT(oracle.expectPrice(
 
  623                {{
"XRP", 
"USD", 741, 2}, {
"XRP", 
"EUR", 710, 2}}));
 
  625            BEAST_EXPECT(
ownerCount(env, owner) == count);
 
  631                        {
"BTC", 
"USD", 741, 2},
 
  632                        {
"ETH", 
"EUR", 710, 2},
 
  633                        {
"YAN", 
"EUR", 710, 2},
 
  634                        {
"CAN", 
"EUR", 710, 2},
 
  638            BEAST_EXPECT(
ownerCount(env, owner) == count);
 
  646                    {{
"XRP", 
"USD", 742, 2},
 
  647                     {
"XRP", 
"EUR", 711, 2},
 
  652            BEAST_EXPECT(
oracle.expectPrice(
 
  653                {{
"XRP", 
"USD", 742, 2}, {
"XRP", 
"EUR", 711, 2}}));
 
  656            BEAST_EXPECT(
ownerCount(env, owner) == count);
 
  663                static_cast<int>(env.current()->fees().base.drops());
 
  665                env.current()->fees().accountReserve(1) +
 
  666                    env.current()->fees().base * 2,
 
  668            Oracle 
oracle(env, {.owner = owner, .fee = baseFee});
 
  670                UpdateArg{.series = {{
"XRP", 
"USD", 742, 2}}, .fee = baseFee});
 
  673        for (
bool const withFixOrder : {
false, 
true})
 
  681                static_cast<int>(env.current()->fees().base.drops());
 
  683            auto test = [&](Env& env, 
DataSeries const& series) {
 
  684                env.fund(
XRP(1'000), owner);
 
  686                    env, {.owner = owner, .series = series, .fee = baseFee});
 
  687                BEAST_EXPECT(
oracle.exists());
 
  690                    sle->getFieldArray(sfPriceDataSeries).size() ==
 
  693                auto const beforeQuoteAssetName1 =
 
  694                    sle->getFieldArray(sfPriceDataSeries)[0]
 
  695                        .getFieldCurrency(sfQuoteAsset)
 
  697                auto const beforeQuoteAssetName2 =
 
  698                    sle->getFieldArray(sfPriceDataSeries)[1]
 
  699                        .getFieldCurrency(sfQuoteAsset)
 
  702                oracle.set(UpdateArg{.series = series, .fee = baseFee});
 
  705                auto const afterQuoteAssetName1 =
 
  706                    sle->getFieldArray(sfPriceDataSeries)[0]
 
  707                        .getFieldCurrency(sfQuoteAsset)
 
  709                auto const afterQuoteAssetName2 =
 
  710                    sle->getFieldArray(sfPriceDataSeries)[1]
 
  711                        .getFieldCurrency(sfQuoteAsset)
 
  714                if (env.current()->rules().enabled(fixPriceOracleOrder))
 
  716                    BEAST_EXPECT(afterQuoteAssetName1 == beforeQuoteAssetName1);
 
  717                    BEAST_EXPECT(afterQuoteAssetName2 == beforeQuoteAssetName2);
 
  721                    BEAST_EXPECT(afterQuoteAssetName1 != beforeQuoteAssetName1);
 
  722                    BEAST_EXPECT(afterQuoteAssetName2 != beforeQuoteAssetName2);
 
  725            test(env, {{
"XRP", 
"USD", 742, 2}, {
"XRP", 
"EUR", 711, 2}});
 
 
  732        testcase(
"Multisig");
 
  734        Oracle::setFee(100'000);
 
  736        Env env(*
this, features);
 
  738            static_cast<int>(env.
current()->fees().base.drops());
 
  746        env.
fund(
XRP(10'000), alice, becky, zelda, ed, bob);
 
  754        env(signers(alice, 2, {{becky, 1}, {bogie, 1}, {ed, 2}}), 
sig(alie));
 
  757        int const signerListOwners{features[featureMultiSignReserve] ? 1 : 5};
 
  772        BEAST_EXPECT(oracle.exists());
 
  776            .
series = {{
"XRP", 
"USD", 740, 1}},
 
  781            .
series = {{
"XRP", 
"USD", 740, 1}},
 
  786            .
series = {{
"XRP", 
"USD", 741, 1}},
 
  787            .msig = 
msig(becky, bogie),
 
  789        BEAST_EXPECT(oracle.expectPrice({{
"XRP", 
"USD", 741, 1}}));
 
  791        env(signers(alice, jtx::none), 
sig(alie));
 
  793        env.require(
owners(alice, 1));
 
  795        env(signers(alice, 2, {{zelda, 1}, {bob, 1}, {ed, 2}}), sig(alie));
 
  798        oracle.set(UpdateArg{
 
  799            .series = {{
"XRP", 
"USD", 740, 1}},
 
  800            .msig = msig(becky, bogie),
 
  805            .series = {{
"XRP", 
"USD", 7412, 2}},
 
  806            .msig = msig(zelda, bob),
 
  808        BEAST_EXPECT(
oracle.expectPrice({{
"XRP", 
"USD", 7412, 2}}));
 
  810            .series = {{
"XRP", 
"USD", 74245, 3}},
 
  813        BEAST_EXPECT(
oracle.expectPrice({{
"XRP", 
"USD", 74245, 3}}));
 
  817            {.msig = msig(bob), .fee = baseFee, .err = ter(tefBAD_QUORUM)});
 
  819            {.msig = msig(becky),
 
  821             .err = ter(tefBAD_SIGNATURE)});
 
  822        oracle.remove({.msig = msig(ed), .fee = baseFee});
 
  823        BEAST_EXPECT(!
oracle.exists());
 
 
  829        testcase(
"Amendment");
 
  834        Env env(*
this, features);
 
  836            static_cast<int>(env.
current()->fees().base.drops());
 
  845            Oracle oracle(env, {.owner = owner, .fee = baseFee}, 
false);
 
 
  859        testCreate(all - fixIncludeKeyletFields);
 
  863        for (
auto const& features :
 
  865              all - featureMultiSignReserve - featureExpandedSignerList,
 
  866              all - featureExpandedSignerList})
 
  867            testMultisig(features);
 
 
 
 
testcase_t testcase
Memberspace for declaring test cases.
 
Immutable cryptographic account descriptor.
 
std::string const & human() const
Returns the human readable public key.
 
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
 
std::vector< std::tuple< std::string, std::string, std::optional< std::uint32_t >, std::optional< std::uint8_t > > > DataSeries
 
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.
 
FeatureBitset testable_amendments()
 
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
 
XRP_t const XRP
Converts to XRP Issue or STAmount.
 
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 testCreate(FeatureBitset features)
 
void testMultisig(FeatureBitset features)
 
std::optional< AnyValue > documentID
 
std::optional< AccountID > owner
 
Set the sequence number on a JTx.