1#include <test/jtx/Account.h>
2#include <test/jtx/Env.h>
3#include <test/jtx/WSClient.h>
4#include <test/jtx/amount.h>
5#include <test/jtx/domain.h>
6#include <test/jtx/offer.h>
7#include <test/jtx/paths.h>
8#include <test/jtx/pay.h>
9#include <test/jtx/permissioned_dex.h>
10#include <test/jtx/sendmax.h>
12#include <xrpld/rpc/BookChanges.h>
14#include <xrpl/basics/base_uint.h>
15#include <xrpl/basics/chrono.h>
16#include <xrpl/beast/hash/uhash.h>
17#include <xrpl/beast/unit_test/suite.h>
18#include <xrpl/json/json_value.h>
19#include <xrpl/json/to_string.h>
20#include <xrpl/ledger/Ledger.h>
21#include <xrpl/protocol/Feature.h>
22#include <xrpl/protocol/LedgerFormats.h>
23#include <xrpl/protocol/SField.h>
24#include <xrpl/protocol/STArray.h>
25#include <xrpl/protocol/STObject.h>
26#include <xrpl/protocol/STTx.h>
27#include <xrpl/protocol/Serializer.h>
28#include <xrpl/protocol/TxFormats.h>
29#include <xrpl/protocol/jss.h>
47 testcase(
"Specify well-known strings as ledger input");
53 params[
"ledger"] =
"validated";
54 resp = env.
rpc(
"json",
"book_changes",
to_string(params));
55 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
56 BEAST_EXPECT(resp[jss::result][jss::status] ==
"success");
57 BEAST_EXPECT(resp[jss::result][jss::validated] ==
true);
59 params[
"ledger"] =
"current";
60 resp = env.
rpc(
"json",
"book_changes",
to_string(params));
61 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
62 BEAST_EXPECT(resp[jss::result][jss::status] ==
"success");
63 BEAST_EXPECT(resp[jss::result][jss::validated] ==
false);
65 params[
"ledger"] =
"closed";
66 resp = env.
rpc(
"json",
"book_changes",
to_string(params));
67 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
68 BEAST_EXPECT(resp[jss::result][jss::status] ==
"success");
73 BEAST_EXPECT(resp[jss::result][jss::validated] ==
true);
76 params[
"ledger"] =
"non_conventional_ledger_input";
77 resp = env.
rpc(
"json",
"book_changes",
to_string(params));
78 BEAST_EXPECT(resp[jss::result].isMember(jss::error));
79 BEAST_EXPECT(resp[jss::result][jss::status] !=
"success");
86 "If ledger_hash or ledger_index is not specified, the behavior "
87 "must default to the `current` ledger");
93 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
94 BEAST_EXPECT(resp[jss::result][jss::status] ==
"success");
109 featurePermissionedDEX};
113 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] = permDex;
127 auto const ledgerIndex = txResult[jss::ledger_index].
asInt();
130 jvParams[jss::ledger_index] = ledgerIndex;
132 auto jv = wsc->invoke(
"book_changes", jvParams);
133 auto jrr = jv[jss::result];
135 BEAST_EXPECT(jrr[jss::changes].size() == 1);
136 BEAST_EXPECT(jrr[jss::changes][0u][jss::domain].asString() ==
to_string(domainID));
142 testcase(
"book_changes skips overflowing rate");
149 auto const big =
MPT{gw.
id(), 1};
150 auto const usd = iouGw[
"USD"];
157 finalFields.
setFieldAmount(sfTakerGets, big(1'800'000'000'000'000'000ull));
162 previousFields.
setFieldAmount(sfTakerGets, big(3'600'000'000'000'000'000ull));
165 STObject modifiedOffer{sfModifiedNode};
166 modifiedOffer.
setFieldU16(sfLedgerEntryType, ltOFFER);
170 STArray affectedNodes{sfAffectedNodes};
171 affectedNodes.
pushBack(std::move(modifiedOffer));
174 metadata->setFieldArray(sfAffectedNodes, affectedNodes);
187 tx->add(*txSerializer);
190 metadata->add(*metaSerializer);
192 ledger->rawTxInsert(
UInt256{1}, txSerializer, metaSerializer);
193 ledger->setImmutable();
194 ledger->setValidated();
200 BEAST_EXPECT(result[jss::type] ==
"bookChanges");
201 BEAST_EXPECT(result[jss::changes].size() == 0);
205 fail(
"Overflowing book-change rate shouldn't throw");
227 for (
auto const& [gets, pays] : crossings)
241 STObject modifiedOffer{sfModifiedNode};
242 modifiedOffer.
setFieldU16(sfLedgerEntryType, ltOFFER);
246 STArray affectedNodes{sfAffectedNodes};
247 affectedNodes.
pushBack(std::move(modifiedOffer));
250 metadata->setFieldArray(sfAffectedNodes, affectedNodes);
255 tx.
add(*txSerializer);
258 metadata->add(*metaSerializer);
260 ledger->rawTxInsert(
UInt256{seq}, txSerializer, metaSerializer);
263 ledger->setImmutable();
264 ledger->setValidated();
272 testcase(
"book_changes skips overflowing volume");
288 auto const half = 5'000'000'000'000'000'000ull;
291 bookChangesFor(env, {{mptA(half), mptB(half)}, {mptA(half), mptB(half)}});
293 BEAST_EXPECT(result[jss::type] ==
"bookChanges");
294 if (BEAST_EXPECT(result[jss::changes].size() == 1))
296 auto const& change = result[jss::changes][0u];
299 BEAST_EXPECT(change[jss::volume_a].asString() ==
std::to_string(half));
300 BEAST_EXPECT(change[jss::volume_b].asString() ==
std::to_string(half));
312 STAmount const bigA{gwA[
"USD"].issue(), UINT64_C(9'000'000'000'000'000), 80};
313 STAmount const bigB{gwB[
"EUR"].issue(), UINT64_C(9'000'000'000'000'000), 80};
317 auto const result =
bookChangesFor(env, {{bigA, bigB}, {bigA, bigB}});
318 BEAST_EXPECT(result[jss::type] ==
"bookChanges");
319 BEAST_EXPECT(result[jss::changes].size() == 1);
323 fail(
"Overflowing book-change volume shouldn't throw");
void fail(String const &reason, char const *file, int line)
Record a failure.
TestcaseT testcase
Memberspace for declaring test cases.
virtual Config & config()=0
std::chrono::time_point< NetClock > time_point
Rules controlling protocol behavior.
void pushBack(STObject const &object)
void setFieldU32(SField const &field, std::uint32_t)
void setFieldAmount(SField const &field, STAmount const &)
void add(Serializer &s) const override
void setFieldU16(SField const &field, std::uint16_t)
static STObject makeInnerObject(SField const &name)
void setFieldObject(SField const &field, STObject const &v)
virtual Family & getNodeFamily()=0
static json::Value bookChangesFor(jtx::Env &env, std::vector< std::pair< STAmount, STAmount > > const &crossings)
void testSkipsOverflowingVolume()
void run() override
Runs the suite.
void testSkipsOverflowingRate()
void testLedgerInputDefaultBehavior()
void testConventionalLedgerInputStrings()
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
A transaction testing environment.
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.
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Converts to MPT Issue or STAmount.
Sets the SendMax on a JTx.
API version numbers used in later API versions.
json::Value computeBookChanges(std::shared_ptr< L const > const &lpAccepted)
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
XrpT const XRP
Converts to XRP Issue or STAmount.
FeatureBitset testableAmendments()
json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpcVersion, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
BaseUInt< 256 > Domain
Domain is a 256-bit hash representing a specific domain.
std::string to_string(BaseUInt< Bits, Tag > const &a)
T static_pointer_cast(T... args)