21#include <test/jtx/WSClient.h>
22#include <xrpld/core/JobQueue.h>
23#include <xrpl/beast/unit_test.h>
24#include <xrpl/protocol/jss.h>
35 using namespace std::chrono_literals;
38 env.
fund(
XRP(10000),
"alice",
"bob");
46 jv[jss::streams].
append(
"transactions");
47 jv = wsc->invoke(
"subscribe", jv);
48 BEAST_EXPECT(jv[jss::status] ==
"success");
49 if (wsc->version() == 2)
52 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
54 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
55 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
63 payment[jss::tx_json] =
pay(
"alice",
"bob",
XRP(1));
64 payment[jss::tx_json][sfLastLedgerSequence.fieldName] = 1;
65 auto jv = wsc->invoke(
"submit", payment);
66 if (wsc->version() == 2)
69 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
71 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
72 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
75 jv[jss::result][jss::engine_result] ==
"tefMAX_LEDGER");
78 payment[jss::tx_json] =
pay(
"alice",
"bob",
XRP(1));
79 payment[jss::tx_json][sfSequence.fieldName] = env.
seq(
"alice") - 1;
80 jv = wsc->invoke(
"submit", payment);
81 if (wsc->version() == 2)
84 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
86 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
87 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
89 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tefPAST_SEQ");
92 payment[jss::tx_json][sfSequence.fieldName] = env.
seq(
"alice") + 1;
93 jv = wsc->invoke(
"submit", payment);
94 if (wsc->version() == 2)
97 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
99 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
100 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
102 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"terPRE_SEQ");
105 payment[jss::tx_json][sfSequence.fieldName] = env.
seq(
"alice");
106 jv = wsc->invoke(
"submit", payment);
107 if (wsc->version() == 2)
110 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
112 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
113 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
115 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tesSUCCESS");
121 jv = wsc->invoke(
"ledger_accept");
122 if (wsc->version() == 2)
125 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
127 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
128 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
130 BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index));
135 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
136 auto const& ff = jv[jss::meta][
"AffectedNodes"][1u]
137 [
"ModifiedNode"][
"FinalFields"];
138 return ff[jss::Account] == Account(
"bob").human() &&
139 ff[
"Balance"] ==
"10001000000";
142 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
143 auto const& ff = jv[jss::meta][
"AffectedNodes"][1u]
144 [
"ModifiedNode"][
"FinalFields"];
145 return ff[jss::Account] == Account(
"bob").human() &&
146 ff[
"Balance"] ==
"10002000000";
154 jv[jss::streams].
append(
"transactions");
155 jv = wsc->invoke(
"unsubscribe", jv);
156 if (wsc->version() == 2)
159 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
161 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
162 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
164 BEAST_EXPECT(jv[jss::status] ==
"success");
184 env.
fund(
XRP(10000),
"alice",
"bob");
192 jv[jss::tx_json] =
pay(
"alice",
"bob",
XRP(1));
193 jv = wsc->invoke(
"submit", jv);
194 if (wsc->version() == 2)
197 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
199 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
200 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
202 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tesSUCCESS");
215 jv[jss::ledger_index_min] = -1;
216 jv[jss::ledger_index_max] = -1;
218 jv = wsc->invoke(
"account_tx", jv);
219 if (wsc->version() == 2)
222 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
224 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
225 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
229 auto ff = jv[jss::result][jss::transactions][0u][jss::meta]
230 [
"AffectedNodes"][1u][
"ModifiedNode"][
"FinalFields"];
231 BEAST_EXPECT(ff[jss::Account] ==
Account(
"bob").human());
232 BEAST_EXPECT(ff[
"Balance"] ==
"10001000000");
239 using namespace std::chrono_literals;
242 env.
fund(
XRP(10000),
"alice",
"bob");
250 jv[jss::tx_json] =
pay(
"alice",
"bob",
XRP(1));
251 jv = wsc->invoke(
"submit", jv);
252 if (wsc->version() == 2)
255 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
257 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
258 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
260 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tesSUCCESS");
263 jv = wsc->invoke(
"ledger_accept");
264 if (wsc->version() == 2)
267 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
269 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
270 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
272 BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index));
283 jv[jss::streams].
append(
"ledger");
284 jv = wsc->invoke(
"subscribe", jv);
285 if (wsc->version() == 2)
288 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
291 jv[jss::ripplerpc] ==
"2.0");
292 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
294 BEAST_EXPECT(jv[jss::status] ==
"success");
298 for (
auto i = 0; i < 8; ++i)
300 auto jv = wsc->invoke(
"ledger_accept");
301 if (wsc->version() == 2)
304 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
306 jv.isMember(jss::ripplerpc) &&
307 jv[jss::ripplerpc] ==
"2.0");
308 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
311 jv[jss::result].isMember(jss::ledger_current_index));
316 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
317 return jval[jss::type] ==
"ledgerClosed";
325 jv[jss::streams].
append(
"ledger");
326 jv = wsc->invoke(
"unsubscribe", jv);
327 if (wsc->version() == 2)
330 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
333 jv[jss::ripplerpc] ==
"2.0");
334 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
336 BEAST_EXPECT(jv[jss::status] ==
"success");
347 jv[jss::streams].
append(
"ledger");
348 jv = wsc->invoke(
"subscribe", jv);
349 if (wsc->version() == 2)
352 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
355 jv[jss::ripplerpc] ==
"2.0");
356 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
358 BEAST_EXPECT(jv[jss::status] ==
"success");
362 for (
auto i = 0; i < 2; ++i)
364 auto jv = wsc->invoke(
"ledger_accept");
365 if (wsc->version() == 2)
368 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
370 jv.isMember(jss::ripplerpc) &&
371 jv[jss::ripplerpc] ==
"2.0");
372 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
375 jv[jss::result].isMember(jss::ledger_current_index));
380 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
381 return jval[jss::type] ==
"ledgerClosed";
389 jv[jss::streams].
append(
"ledger");
390 jv = wsc->invoke(
"unsubscribe", jv);
391 if (wsc->version() == 2)
394 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
397 jv[jss::ripplerpc] ==
"2.0");
398 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
400 BEAST_EXPECT(jv[jss::status] ==
"success");
408 jv[jss::ledger_index_min] = -1;
409 jv[jss::ledger_index_max] = -1;
411 jv = wsc->invoke(
"account_tx", jv);
412 if (wsc->version() == 2)
415 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
417 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
418 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
422 auto ff = jv[jss::result][jss::transactions][0u][jss::meta]
423 [
"AffectedNodes"][1u][
"ModifiedNode"][
"FinalFields"];
424 BEAST_EXPECT(ff[jss::Account] ==
Account(
"bob").human());
425 BEAST_EXPECT(ff[
"Balance"] ==
"10001000000");
432 using namespace std::chrono_literals;
444 jv = wsc->invoke(
"subscribe", jv);
445 if (wsc->version() == 2)
448 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
450 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
451 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
453 BEAST_EXPECT(jv[jss::status] ==
"success");
460 jv[jss::tx_json] =
fset(
"alice", 0);
461 jv[jss::tx_json][jss::Fee] = 10;
462 jv = wsc->invoke(
"submit", jv);
463 if (wsc->version() == 2)
466 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
468 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
469 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
471 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tesSUCCESS");
476 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
477 return jv[jss::transaction][jss::TransactionType] ==
487 jv = wsc->invoke(
"unsubscribe", jv);
488 if (wsc->version() == 2)
491 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
493 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
494 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
496 BEAST_EXPECT(jv[jss::status] ==
"success");
510BEAST_DEFINE_TESTSUITE(RobustTransaction, app,
ripple);
Value & append(const Value &value)
Append value to array at the end.
bool isMember(const char *key) const
Return true if the object has a member named key.
virtual Config & config()=0
virtual JobQueue & getJobQueue()=0
void rendezvous()
Block until no jobs running.
void testReconnectAfterWait()
void run() override
Runs the suite.
void testSequenceRealignment()
void testAccountsProposed()
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
@ arrayValue
array value (ordered list)
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
XRP_t const XRP
Converts to XRP Issue or STAmount.
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, 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.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.