21#include <test/jtx/WSClient.h>
23#include <xrpld/core/JobQueue.h>
25#include <xrpl/beast/unit_test.h>
26#include <xrpl/protocol/jss.h>
37 using namespace std::chrono_literals;
40 env.
fund(
XRP(10000),
"alice",
"bob");
48 jv[jss::streams].
append(
"transactions");
49 jv = wsc->invoke(
"subscribe", jv);
50 BEAST_EXPECT(jv[jss::status] ==
"success");
51 if (wsc->version() == 2)
54 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
56 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
57 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
65 payment[jss::tx_json] =
pay(
"alice",
"bob",
XRP(1));
66 payment[jss::tx_json][sfLastLedgerSequence.fieldName] = 1;
67 auto jv = wsc->invoke(
"submit", payment);
68 if (wsc->version() == 2)
71 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
73 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
74 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
77 jv[jss::result][jss::engine_result] ==
"tefMAX_LEDGER");
80 payment[jss::tx_json] =
pay(
"alice",
"bob",
XRP(1));
81 payment[jss::tx_json][sfSequence.fieldName] = env.
seq(
"alice") - 1;
82 jv = wsc->invoke(
"submit", payment);
83 if (wsc->version() == 2)
86 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
88 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
89 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
91 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tefPAST_SEQ");
94 payment[jss::tx_json][sfSequence.fieldName] = env.
seq(
"alice") + 1;
95 jv = wsc->invoke(
"submit", payment);
96 if (wsc->version() == 2)
99 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
101 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
102 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
104 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"terPRE_SEQ");
107 payment[jss::tx_json][sfSequence.fieldName] = env.
seq(
"alice");
108 jv = wsc->invoke(
"submit", payment);
109 if (wsc->version() == 2)
112 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
114 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
115 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
117 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tesSUCCESS");
123 jv = wsc->invoke(
"ledger_accept");
124 if (wsc->version() == 2)
127 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
129 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
130 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
132 BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index));
137 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
138 auto const& ff = jv[jss::meta][
"AffectedNodes"][1u]
139 [
"ModifiedNode"][
"FinalFields"];
140 return ff[jss::Account] == Account(
"bob").human() &&
141 ff[
"Balance"] ==
"10001000000";
144 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
145 auto const& ff = jv[jss::meta][
"AffectedNodes"][1u]
146 [
"ModifiedNode"][
"FinalFields"];
147 return ff[jss::Account] == Account(
"bob").human() &&
148 ff[
"Balance"] ==
"10002000000";
156 jv[jss::streams].
append(
"transactions");
157 jv = wsc->invoke(
"unsubscribe", jv);
158 if (wsc->version() == 2)
161 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
163 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
164 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
166 BEAST_EXPECT(jv[jss::status] ==
"success");
186 env.
fund(
XRP(10000),
"alice",
"bob");
194 jv[jss::tx_json] =
pay(
"alice",
"bob",
XRP(1));
195 jv = wsc->invoke(
"submit", jv);
196 if (wsc->version() == 2)
199 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
201 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
202 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
204 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tesSUCCESS");
217 jv[jss::ledger_index_min] = -1;
218 jv[jss::ledger_index_max] = -1;
220 jv = wsc->invoke(
"account_tx", jv);
221 if (wsc->version() == 2)
224 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
226 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
227 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
231 auto ff = jv[jss::result][jss::transactions][0u][jss::meta]
232 [
"AffectedNodes"][1u][
"ModifiedNode"][
"FinalFields"];
233 BEAST_EXPECT(ff[jss::Account] ==
Account(
"bob").human());
234 BEAST_EXPECT(ff[
"Balance"] ==
"10001000000");
241 using namespace std::chrono_literals;
244 env.
fund(
XRP(10000),
"alice",
"bob");
252 jv[jss::tx_json] =
pay(
"alice",
"bob",
XRP(1));
253 jv = wsc->invoke(
"submit", jv);
254 if (wsc->version() == 2)
257 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
259 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
260 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
262 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tesSUCCESS");
265 jv = wsc->invoke(
"ledger_accept");
266 if (wsc->version() == 2)
269 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
271 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
272 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
274 BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index));
285 jv[jss::streams].
append(
"ledger");
286 jv = wsc->invoke(
"subscribe", jv);
287 if (wsc->version() == 2)
290 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
293 jv[jss::ripplerpc] ==
"2.0");
294 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
296 BEAST_EXPECT(jv[jss::status] ==
"success");
300 for (
auto i = 0; i < 8; ++i)
302 auto jv = wsc->invoke(
"ledger_accept");
303 if (wsc->version() == 2)
306 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
308 jv.isMember(jss::ripplerpc) &&
309 jv[jss::ripplerpc] ==
"2.0");
310 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
313 jv[jss::result].isMember(jss::ledger_current_index));
318 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
319 return jval[jss::type] ==
"ledgerClosed";
327 jv[jss::streams].
append(
"ledger");
328 jv = wsc->invoke(
"unsubscribe", jv);
329 if (wsc->version() == 2)
332 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
335 jv[jss::ripplerpc] ==
"2.0");
336 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
338 BEAST_EXPECT(jv[jss::status] ==
"success");
349 jv[jss::streams].
append(
"ledger");
350 jv = wsc->invoke(
"subscribe", jv);
351 if (wsc->version() == 2)
354 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
357 jv[jss::ripplerpc] ==
"2.0");
358 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
360 BEAST_EXPECT(jv[jss::status] ==
"success");
364 for (
auto i = 0; i < 2; ++i)
366 auto jv = wsc->invoke(
"ledger_accept");
367 if (wsc->version() == 2)
370 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
372 jv.isMember(jss::ripplerpc) &&
373 jv[jss::ripplerpc] ==
"2.0");
374 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
377 jv[jss::result].isMember(jss::ledger_current_index));
382 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
383 return jval[jss::type] ==
"ledgerClosed";
391 jv[jss::streams].
append(
"ledger");
392 jv = wsc->invoke(
"unsubscribe", jv);
393 if (wsc->version() == 2)
396 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
399 jv[jss::ripplerpc] ==
"2.0");
400 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
402 BEAST_EXPECT(jv[jss::status] ==
"success");
410 jv[jss::ledger_index_min] = -1;
411 jv[jss::ledger_index_max] = -1;
413 jv = wsc->invoke(
"account_tx", jv);
414 if (wsc->version() == 2)
417 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
419 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
420 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
424 auto ff = jv[jss::result][jss::transactions][0u][jss::meta]
425 [
"AffectedNodes"][1u][
"ModifiedNode"][
"FinalFields"];
426 BEAST_EXPECT(ff[jss::Account] ==
Account(
"bob").human());
427 BEAST_EXPECT(ff[
"Balance"] ==
"10001000000");
434 using namespace std::chrono_literals;
446 jv = wsc->invoke(
"subscribe", jv);
447 if (wsc->version() == 2)
450 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
452 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
453 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
455 BEAST_EXPECT(jv[jss::status] ==
"success");
462 jv[jss::tx_json] =
fset(
"alice", 0);
463 jv[jss::tx_json][jss::Fee] =
464 static_cast<int>(env.
current()->fees().base.drops());
465 jv = wsc->invoke(
"submit", jv);
466 if (wsc->version() == 2)
469 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
471 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
472 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
474 BEAST_EXPECT(jv[jss::result][jss::engine_result] ==
"tesSUCCESS");
479 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
480 return jv[jss::transaction][jss::TransactionType] ==
490 jv = wsc->invoke(
"unsubscribe", jv);
491 if (wsc->version() == 2)
494 jv.
isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
496 jv.
isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
497 BEAST_EXPECT(jv.
isMember(jss::id) && jv[jss::id] == 5);
499 BEAST_EXPECT(jv[jss::status] ==
"success");
513BEAST_DEFINE_TESTSUITE(RobustTransaction, app,
ripple);
Value & append(Value const &value)
Append value to array at the end.
bool isMember(char const *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.
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.
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.