20 #include <ripple/beast/unit_test.h>
21 #include <ripple/protocol/ErrorCodes.h>
22 #include <ripple/protocol/jss.h>
23 #include <ripple/rpc/impl/RPCHelpers.h>
26 #include <boost/container/flat_set.hpp>
40 boost::container::flat_set<std::string>
created;
41 boost::container::flat_set<std::string>
deleted;
42 boost::container::flat_set<std::string>
modified;
52 auto buildSet = [](
auto&& init) {
53 boost::container::flat_set<std::string> r;
54 r.reserve(init.size());
70 BEAST_EXPECT(
txNode[jss::validated].asBool() ==
true);
76 boost::container::flat_set<std::string> createdNodes;
77 boost::container::flat_set<std::string> deletedNodes;
78 boost::container::flat_set<std::string> modifiedNodes;
100 "Unexpected or unlabeled node type in metadata.",
105 BEAST_EXPECT(createdNodes == sane.
created);
106 BEAST_EXPECT(deletedNodes == sane.
deleted);
107 BEAST_EXPECT(modifiedNodes == sane.
modified);
113 using namespace test::jtx;
124 return j.isMember(jss::result) &&
125 (j[jss::result][jss::status] ==
"success") &&
126 (j[jss::result][jss::transactions].size() == 2) &&
127 (j[jss::result][jss::transactions][0u][jss::tx]
128 [jss::TransactionType] == jss::AccountSet) &&
129 (j[jss::result][jss::transactions][1u][jss::tx]
130 [jss::TransactionType] == jss::Payment);
134 return j.isMember(jss::result) &&
135 (j[jss::result][jss::status] ==
"success") &&
136 (j[jss::result][jss::transactions].size() == 0);
141 j[jss::result].
isMember(jss::error) &&
151 jParms[jss::account] =
"0xDEADBEEF";
157 jParms[jss::account] = A1.human();
158 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(jParms))));
163 p[jss::ledger_index_min] = -1;
164 p[jss::ledger_index_max] = -1;
165 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
167 p[jss::ledger_index_min] = 0;
168 p[jss::ledger_index_max] = 100;
169 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
171 p[jss::ledger_index_min] = 1;
172 p[jss::ledger_index_max] = 2;
173 BEAST_EXPECT(noTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
175 p[jss::ledger_index_min] = 2;
176 p[jss::ledger_index_max] = 1;
186 p[jss::ledger_index_min] = -1;
187 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
189 p[jss::ledger_index_min] = 1;
190 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
192 p[jss::ledger_index_min] = env.
current()->info().seq;
202 p[jss::ledger_index_max] = -1;
203 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
205 p[jss::ledger_index_max] = env.
current()->info().seq;
206 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
208 p[jss::ledger_index_max] = env.
closed()->info().seq;
209 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
211 p[jss::ledger_index_max] = env.
closed()->info().seq - 1;
212 BEAST_EXPECT(noTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
219 p[jss::ledger_index] = env.
closed()->info().seq;
220 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
222 p[jss::ledger_index] = env.
closed()->info().seq - 1;
223 BEAST_EXPECT(noTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
225 p[jss::ledger_index] = env.
current()->info().seq;
230 p[jss::ledger_index] = env.
current()->info().seq + 1;
240 BEAST_EXPECT(hasTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
243 BEAST_EXPECT(noTxs(env.
rpc(
"json",
"account_tx",
to_string(p))));
252 using namespace test::jtx;
253 using namespace std::chrono_literals;
259 auto const USD{gw[
"USD"]};
261 env.
fund(
XRP(1000000), alice, gw);
268 env(
pay(alice, gw,
XRP(100)));
275 env(
trust(alice, USD(200)),
sig(alie));
277 env(offer(alice, USD(50),
XRP(150)),
sig(alie));
282 cancelOffer[jss::Account] = alice.human();
283 cancelOffer[jss::OfferSequence] = offerSeq;
284 cancelOffer[jss::TransactionType] = jss::OfferCancel;
285 env(cancelOffer,
sig(alie));
290 env(signers(alice, 1, {{
"bogie", 1}, {
"demon", 1}}),
sig(alie));
295 auto escrow = [](
Account const& account,
299 escro[jss::TransactionType] = jss::EscrowCreate;
301 escro[jss::Account] = account.human();
302 escro[jss::Destination] = to.human();
311 nextTime.time_since_epoch().count();
314 env(escrowWithFinish,
sig(alie));
318 nextTime.time_since_epoch().count();
320 nextTime.time_since_epoch().count() + 1;
323 env(escrowWithCancel,
sig(alie));
328 escrowFinish[jss::TransactionType] = jss::EscrowFinish;
330 escrowFinish[jss::Account] = alice.human();
333 env(escrowFinish,
sig(alie));
337 escrowCancel[jss::TransactionType] = jss::EscrowCancel;
339 escrowCancel[jss::Account] = alice.human();
342 env(escrowCancel,
sig(alie));
351 payChanCreate[jss::TransactionType] = jss::PaymentChannelCreate;
353 payChanCreate[jss::Account] = alice.human();
354 payChanCreate[jss::Destination] = gw.human();
355 payChanCreate[jss::Amount] =
360 env(payChanCreate,
sig(alie));
368 payChanFund[jss::TransactionType] = jss::PaymentChannelFund;
370 payChanFund[jss::Account] = alice.human();
372 payChanFund[jss::Amount] =
374 env(payChanFund,
sig(alie));
379 payChanClaim[jss::TransactionType] = jss::PaymentChannelClaim;
380 payChanClaim[jss::Flags] =
tfClose;
381 payChanClaim[jss::Account] = gw.human();
392 env(check::create(alice, gw,
XRP(300)),
sig(alie));
395 env(check::create(gw, alice,
XRP(200)));
398 env(check::cash(alice, gwCheckId,
XRP(200)),
sig(alie));
399 env(check::cancel(alice, aliceCheckId),
sig(alie));
405 env(ticket::create(alice, 1),
sig(alie));
414 params[jss::account] = alice.human();
415 params[jss::ledger_index_min] = -1;
416 params[jss::ledger_index_max] = -1;
421 BEAST_EXPECT(result[jss::result][jss::status] ==
"success");
422 BEAST_EXPECT(result[jss::result][jss::transactions].isArray());
424 Json::Value const& txs{result[jss::result][jss::transactions]};
431 {0, jss::DepositPreauth, {jss::DepositPreauth}, {jss::Ticket}, {jss::AccountRoot, jss::DirectoryNode}},
432 {1, jss::TicketCreate, {jss::Ticket}, {}, {jss::AccountRoot, jss::DirectoryNode}},
433 {2, jss::CheckCancel, {}, {jss::Check}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
434 {3, jss::CheckCash, {}, {jss::Check}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
435 {4, jss::CheckCreate, {jss::Check}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
436 {5, jss::CheckCreate, {jss::Check}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
437 {6, jss::PaymentChannelClaim, {}, {jss::PayChannel}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
438 {7, jss::PaymentChannelFund, {}, {}, {jss::AccountRoot, jss::PayChannel}},
439 {8, jss::PaymentChannelCreate, {jss::PayChannel}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
440 {9, jss::EscrowCancel, {}, {jss::Escrow}, {jss::AccountRoot, jss::DirectoryNode}},
441 {10, jss::EscrowFinish, {}, {jss::Escrow}, {jss::AccountRoot, jss::DirectoryNode}},
442 {11, jss::EscrowCreate, {jss::Escrow}, {}, {jss::AccountRoot, jss::DirectoryNode}},
443 {12, jss::EscrowCreate, {jss::Escrow}, {}, {jss::AccountRoot, jss::DirectoryNode}},
444 {13, jss::SignerListSet, {jss::SignerList}, {}, {jss::AccountRoot, jss::DirectoryNode}},
445 {14, jss::OfferCancel, {}, {jss::Offer, jss::DirectoryNode}, {jss::AccountRoot, jss::DirectoryNode}},
446 {15, jss::OfferCreate, {jss::Offer, jss::DirectoryNode}, {}, {jss::AccountRoot, jss::DirectoryNode}},
447 {16, jss::TrustSet, {jss::RippleState, jss::DirectoryNode, jss::DirectoryNode}, {}, {jss::AccountRoot, jss::AccountRoot}},
448 {17, jss::SetRegularKey, {}, {}, {jss::AccountRoot}},
449 {18, jss::Payment, {}, {}, {jss::AccountRoot, jss::AccountRoot}},
450 {19, jss::AccountSet, {}, {}, {jss::AccountRoot}},
451 {20, jss::AccountSet, {}, {}, {jss::AccountRoot}},
452 {21, jss::Payment, {jss::AccountRoot}, {}, {jss::AccountRoot}},
457 std::size(sanity) == result[jss::result][jss::transactions].size());
459 for (
unsigned int index{0}; index <
std::size(sanity); ++index)
471 using namespace test::jtx;
472 using namespace std::chrono_literals;
478 env.
fund(
XRP(10000), alice, becky);
483 BEAST_EXPECT(env.
closed()->exists(beckyAcctKey));
495 auto const beckyPreDelBalance{env.
balance(becky)};
497 auto const acctDelFee{
drops(env.
current()->fees().increment)};
502 BEAST_EXPECT(!env.
closed()->exists(beckyAcctKey));
514 { 0, jss::Payment, {}, {}, {jss::AccountRoot, jss::AccountRoot}},
515 { 1, jss::Payment, {jss::AccountRoot}, {}, {jss::AccountRoot}},
516 { 2, jss::AccountDelete, {}, {jss::AccountRoot}, {jss::AccountRoot}},
517 { 3, jss::AccountSet, {}, {}, {jss::AccountRoot}},
518 { 4, jss::AccountSet, {}, {}, {jss::AccountRoot}},
519 { 5, jss::Payment, {jss::AccountRoot}, {}, {jss::AccountRoot}}
527 params[jss::account] = becky.human();
528 params[jss::ledger_index_min] = -1;
529 params[jss::ledger_index_max] = -1;
534 BEAST_EXPECT(result[jss::result][jss::status] ==
"success");
535 BEAST_EXPECT(result[jss::result][jss::transactions].isArray());
538 constexpr
unsigned int beckyDeletedOffest = 2;
541 result[jss::result][jss::transactions].size() +
544 Json::Value const& txs{result[jss::result][jss::transactions]};
546 for (
unsigned int index = beckyDeletedOffest;
550 checkSanity(txs[index - beckyDeletedOffest], sanity[index]);
560 env(
pay(alice, becky,
XRP(45)));
564 BEAST_EXPECT(env.
closed()->exists(beckyAcctKey));
568 env(
pay(becky, alice,
XRP(20)));
574 params[jss::account] = becky.human();
575 params[jss::ledger_index_min] = -1;
576 params[jss::ledger_index_max] = -1;
581 BEAST_EXPECT(result[jss::result][jss::status] ==
"success");
582 BEAST_EXPECT(result[jss::result][jss::transactions].isArray());
585 std::size(sanity) == result[jss::result][jss::transactions].size());
587 Json::Value const& txs{result[jss::result][jss::transactions]};
589 for (
unsigned int index = 0; index <
std::size(sanity); ++index)