18 #include <ripple/app/main/LoadManager.h>
19 #include <ripple/app/misc/LoadFeeTrack.h>
20 #include <ripple/app/misc/NetworkOPs.h>
21 #include <ripple/beast/unit_test.h>
22 #include <ripple/core/ConfigSections.h>
23 #include <ripple/protocol/jss.h>
25 #include <test/jtx/WSClient.h>
26 #include <test/jtx/envconfig.h>
37 using namespace std::chrono_literals;
46 stream[jss::streams].append(
"server");
47 auto jv = wsc->invoke(
"subscribe", stream);
48 if (wsc->version() == 2)
51 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
53 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
54 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
56 BEAST_EXPECT(jv[jss::status] ==
"success");
68 for (
int i = 0; i < 5; ++i)
73 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
74 return jv[jss::type] ==
"serverStatus";
80 auto jv = wsc->invoke(
"unsubscribe", stream);
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::status] ==
"success");
95 for (
int i = 0; i < 5; ++i)
100 auto jvo = wsc->getMsg(10ms);
101 BEAST_EXPECTS(!jvo,
"getMsg: " +
to_string(jvo.value()));
108 using namespace std::chrono_literals;
117 stream[jss::streams].append(
"ledger");
118 auto jv = wsc->invoke(
"subscribe", stream);
119 if (wsc->version() == 2)
122 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
124 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
125 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
127 BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 2);
135 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
136 return jv[jss::ledger_index] == 3;
145 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
146 return jv[jss::ledger_index] == 4;
151 auto jv = wsc->invoke(
"unsubscribe", stream);
152 if (wsc->version() == 2)
155 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
157 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
158 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
160 BEAST_EXPECT(jv[jss::status] ==
"success");
166 using namespace std::chrono_literals;
175 stream[jss::streams].append(
"transactions");
176 auto jv = wsc->invoke(
"subscribe", stream);
177 if (wsc->version() == 2)
180 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
182 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
183 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
185 BEAST_EXPECT(jv[jss::status] ==
"success");
193 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
194 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
195 [
"NewFields"][jss::Account] ==
196 Account(
"alice").human();
200 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
201 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
202 [
"FinalFields"][jss::Account] ==
203 Account(
"alice").human();
210 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
211 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
212 [
"NewFields"][jss::Account] == Account(
"bob").human();
216 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
217 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
218 [
"FinalFields"][jss::Account] ==
219 Account(
"bob").human();
225 auto jv = wsc->invoke(
"unsubscribe", stream);
226 if (wsc->version() == 2)
229 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
231 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
232 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
234 BEAST_EXPECT(jv[jss::status] ==
"success");
241 stream[jss::accounts].append(
Account(
"alice").human());
242 auto jv = wsc->invoke(
"subscribe", stream);
243 if (wsc->version() == 2)
246 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
248 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
249 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
251 BEAST_EXPECT(jv[jss::status] ==
"success");
258 BEAST_EXPECT(!wsc->getMsg(10ms));
265 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
266 return jv[jss::meta][
"AffectedNodes"][1u][
"ModifiedNode"]
267 [
"FinalFields"][jss::Account] ==
268 Account(
"alice").human();
271 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
272 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
273 [
"NewFields"][
"LowLimit"][jss::issuer] ==
274 Account(
"alice").human();
279 auto jv = wsc->invoke(
"unsubscribe", stream);
280 if (wsc->version() == 2)
283 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
285 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
286 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
288 BEAST_EXPECT(jv[jss::status] ==
"success");
302 stream[jss::streams].append(
"manifests");
303 auto jv = wsc->invoke(
"subscribe", stream);
304 if (wsc->version() == 2)
307 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
309 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
310 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
312 BEAST_EXPECT(jv[jss::status] ==
"success");
316 auto jv = wsc->invoke(
"unsubscribe", stream);
317 if (wsc->version() == 2)
320 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
322 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
323 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
325 BEAST_EXPECT(jv[jss::status] ==
"success");
334 auto& cfg = env.app().config();
335 if (!BEAST_EXPECT(cfg.section(SECTION_VALIDATION_SEED).empty()))
337 auto const parsedseed =
338 parseBase58<Seed>(cfg.section(SECTION_VALIDATION_SEED).values()[0]);
339 if (!BEAST_EXPECT(parsedseed))
354 stream[jss::streams].append(
"validations");
355 auto jv = wsc->invoke(
"subscribe", stream);
356 if (wsc->version() == 2)
359 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
361 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
362 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
364 BEAST_EXPECT(jv[jss::status] ==
"success");
369 auto validValidationFields = [&env, &valPublicKey](
371 if (jv[jss::type] !=
"validationReceived")
374 if (jv[jss::validation_public_key].asString() != valPublicKey)
377 if (jv[jss::ledger_hash] !=
381 if (jv[jss::ledger_index] !=
388 if (jv[jss::full] !=
true)
391 if (jv.isMember(jss::load_fee))
394 if (!jv.isMember(jss::signature))
397 if (!jv.isMember(jss::signing_time))
400 if (!jv.isMember(jss::cookie))
403 if (!jv.isMember(jss::validated_hash))
408 (env.closed()->info().seq + 1) % 256 == 0;
424 while (env.closed()->info().seq < 300)
427 using namespace std::chrono_literals;
428 BEAST_EXPECT(wsc->findMsg(5s, validValidationFields));
433 auto jv = wsc->invoke(
"unsubscribe", stream);
434 if (wsc->version() == 2)
437 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
439 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
440 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
442 BEAST_EXPECT(jv[jss::status] ==
"success");
449 testcase(
"Subscribe by url");
453 jv[jss::url] =
"http://localhost/events";
454 jv[jss::url_username] =
"admin";
455 jv[jss::url_password] =
"password";
457 jv[jss::streams][0u] =
"validations";
458 auto jr = env.rpc(
"json",
"subscribe",
to_string(jv))[jss::result];
459 BEAST_EXPECT(jr[jss::status] ==
"success");
461 jv[jss::streams][0u] =
"ledger";
462 jr = env.rpc(
"json",
"subscribe",
to_string(jv))[jss::result];
463 BEAST_EXPECT(jr[jss::status] ==
"success");
465 jr = env.rpc(
"json",
"unsubscribe",
to_string(jv))[jss::result];
466 BEAST_EXPECT(jr[jss::status] ==
"success");
468 jv[jss::streams][0u] =
"validations";
469 jr = env.rpc(
"json",
"unsubscribe",
to_string(jv))[jss::result];
470 BEAST_EXPECT(jr[jss::status] ==
"success");
477 auto const method = subscribe ?
"subscribe" :
"unsubscribe";
478 testcase <<
"Error cases for " << method;
484 auto jr = env.rpc(
"json", method,
"{}")[jss::result];
485 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
486 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
491 jv[jss::url] =
"not-a-url";
492 jv[jss::username] =
"admin";
493 jv[jss::password] =
"password";
494 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
497 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
498 BEAST_EXPECT(jr[jss::error_message] ==
"Failed to parse url.");
506 jv[jss::url] =
"ftp://scheme.not.supported.tld";
507 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
510 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
512 jr[jss::error_message] ==
513 "Only http and https is supported.");
520 jv[jss::url] =
"no-url";
522 env_nonadmin.rpc(
"json", method,
to_string(jv))[jss::result];
523 BEAST_EXPECT(jr[jss::error] ==
"noPermission");
525 jr[jss::error_message] ==
526 "You don't have permission for this command.");
538 for (
auto const& f : {jss::accounts_proposed, jss::accounts})
540 for (
auto const& nonArray : nonArrays)
544 auto jr = wsc->invoke(method, jv)[jss::result];
545 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
546 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
552 auto jr = wsc->invoke(method, jv)[jss::result];
553 BEAST_EXPECT(jr[jss::error] ==
"actMalformed");
554 BEAST_EXPECT(jr[jss::error_message] ==
"Account malformed.");
558 for (
auto const& nonArray : nonArrays)
561 jv[jss::books] = nonArray;
562 auto jr = wsc->invoke(method, jv)[jss::result];
563 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
564 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
570 jv[jss::books][0u] = 1;
571 auto jr = wsc->invoke(method, jv)[jss::result];
572 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
573 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
582 auto jr = wsc->invoke(method, jv)[jss::result];
583 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
585 jr[jss::error_message] ==
"Source currency is malformed.");
594 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"ZZZZ";
595 auto jr = wsc->invoke(method, jv)[jss::result];
596 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
598 jr[jss::error_message] ==
"Source currency is malformed.");
607 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
608 jv[jss::books][0u][jss::taker_pays][jss::issuer] = 1;
609 auto jr = wsc->invoke(method, jv)[jss::result];
610 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
612 jr[jss::error_message] ==
"Source issuer is malformed.");
621 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
622 jv[jss::books][0u][jss::taker_pays][jss::issuer] =
624 auto jr = wsc->invoke(method, jv)[jss::result];
625 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
627 jr[jss::error_message] ==
"Source issuer is malformed.");
634 jv[jss::books][0u][jss::taker_pays] =
635 Account{
"gateway"}[
"USD"](1).value().getJson(
638 auto jr = wsc->invoke(method, jv)[jss::result];
641 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
643 jr[jss::error_message] ==
644 "Destination amount/currency/issuer is malformed.");
651 jv[jss::books][0u][jss::taker_pays] =
652 Account{
"gateway"}[
"USD"](1).value().getJson(
654 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"ZZZZ";
655 auto jr = wsc->invoke(method, jv)[jss::result];
658 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
660 jr[jss::error_message] ==
661 "Destination amount/currency/issuer is malformed.");
668 jv[jss::books][0u][jss::taker_pays] =
669 Account{
"gateway"}[
"USD"](1).value().getJson(
671 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
672 jv[jss::books][0u][jss::taker_gets][jss::issuer] = 1;
673 auto jr = wsc->invoke(method, jv)[jss::result];
674 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
676 jr[jss::error_message] ==
"Destination issuer is malformed.");
683 jv[jss::books][0u][jss::taker_pays] =
684 Account{
"gateway"}[
"USD"](1).value().getJson(
686 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
687 jv[jss::books][0u][jss::taker_gets][jss::issuer] =
689 auto jr = wsc->invoke(method, jv)[jss::result];
690 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
692 jr[jss::error_message] ==
"Destination issuer is malformed.");
699 jv[jss::books][0u][jss::taker_pays] =
700 Account{
"gateway"}[
"USD"](1).value().getJson(
702 jv[jss::books][0u][jss::taker_gets] =
703 Account{
"gateway"}[
"USD"](1).value().getJson(
705 auto jr = wsc->invoke(method, jv)[jss::result];
706 BEAST_EXPECT(jr[jss::error] ==
"badMarket");
707 BEAST_EXPECT(jr[jss::error_message] ==
"No such market.");
710 for (
auto const& nonArray : nonArrays)
713 jv[jss::streams] = nonArray;
714 auto jr = wsc->invoke(method, jv)[jss::result];
715 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
716 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
722 jv[jss::streams][0u] = 1;
723 auto jr = wsc->invoke(method, jv)[jss::result];
724 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
725 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
731 jv[jss::streams][0u] =
"not_a_stream";
732 auto jr = wsc->invoke(method, jv)[jss::result];
733 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
734 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
741 testcase(
"HistoryTxStream");
743 using namespace std::chrono_literals;
756 auto goodSubRPC = [](
Json::Value const& subReply) ->
bool {
757 return subReply.isMember(jss::result) &&
758 subReply[jss::result].isMember(jss::status) &&
759 subReply[jss::result][jss::status] == jss::success;
770 bool first_flag =
false;
772 for (
int i = 0; i < numReplies; ++i)
775 auto reply = wsc.
getMsg(100ms);
779 if (r.isMember(jss::account_history_tx_index))
780 idx = r[jss::account_history_tx_index].asInt();
781 if (r.isMember(jss::account_history_tx_first))
783 if (r.isMember(jss::transaction) &&
784 r[jss::transaction].isMember(jss::hash))
787 idx, r[jss::transaction][jss::hash].asString());
791 return {
false, first_flag};
794 return {
true, first_flag};
801 auto sendPayments = [](
Env& env,
809 for (
int i = 0; i < newTxns; ++i)
811 auto& from = (i % 2 == 0) ? a : b;
812 auto& to = (i % 2 == 0) ? b : a;
819 for (
int i = 0; i < ledgersToClose; ++i)
829 auto hashCompare = [](IdxHashVec
const& accountVec,
830 IdxHashVec
const& txHistoryVec,
831 bool sizeCompare) ->
bool {
832 if (accountVec.empty() || txHistoryVec.empty())
834 if (sizeCompare && accountVec.size() != (txHistoryVec.size()))
838 for (
auto const& tx : txHistoryVec)
840 txHistoryMap.
emplace(tx.second, tx.first);
844 if (i >= accountVec.size())
846 auto it = txHistoryMap.
find(accountVec[i].second);
847 if (it == txHistoryMap.
end())
852 auto firstHistoryIndex = getHistoryIndex(0);
853 if (!firstHistoryIndex)
855 for (
std::size_t i = 1; i < accountVec.size(); ++i)
857 if (
auto idx = getHistoryIndex(i);
858 !idx || *idx != *firstHistoryIndex + i)
877 request[jss::account_history_tx_stream][jss::account] =
879 auto jv = wscTxHistory->invoke(
"subscribe", request);
880 if (!BEAST_EXPECT(goodSubRPC(jv)))
882 jv = wscTxHistory->invoke(
"subscribe", request);
883 BEAST_EXPECT(!goodSubRPC(jv));
888 request[jss::account_history_tx_stream][jss::stop_history_tx_only] =
890 jv = wscTxHistory->invoke(
"unsubscribe", request);
891 if (!BEAST_EXPECT(goodSubRPC(jv)))
894 sendPayments(env, env.
master, alice, 1, 1, 123456);
897 auto r = getTxHash(*wscTxHistory, vec, 1);
898 if (!BEAST_EXPECT(r.first && r.second))
904 request[jss::account_history_tx_stream][jss::stop_history_tx_only] =
906 jv = wscTxHistory->invoke(
"unsubscribe", request);
907 BEAST_EXPECT(goodSubRPC(jv));
909 sendPayments(env, env.
master, alice, 1, 1);
910 r = getTxHash(*wscTxHistory, vec, 1);
911 BEAST_EXPECT(!r.first);
923 request[jss::account_history_tx_stream][jss::account] =
924 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
925 auto jv = wscTxHistory->invoke(
"subscribe", request);
926 if (!BEAST_EXPECT(goodSubRPC(jv)))
928 IdxHashVec genesisFullHistoryVec;
930 !getTxHash(*wscTxHistory, genesisFullHistoryVec, 1).first))
937 sendPayments(env, env.
master, bob, 1, 1, 654321);
939 auto r = getTxHash(*wscTxHistory, genesisFullHistoryVec, 1);
940 if (!BEAST_EXPECT(r.first && r.second))
943 request[jss::account_history_tx_stream][jss::account] = bob.
human();
944 jv = wscTxHistory->invoke(
"subscribe", request);
945 if (!BEAST_EXPECT(goodSubRPC(jv)))
947 IdxHashVec bobFullHistoryVec;
948 r = getTxHash(*wscTxHistory, bobFullHistoryVec, 1);
949 if (!BEAST_EXPECT(r.first && r.second))
952 bobFullHistoryVec.back().second ==
953 genesisFullHistoryVec.back().second);
958 jv = wscTxHistory->invoke(
"unsubscribe", request);
959 if (!BEAST_EXPECT(goodSubRPC(jv)))
961 request[jss::account_history_tx_stream][jss::account] =
962 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
963 jv = wscTxHistory->invoke(
"unsubscribe", request);
964 BEAST_EXPECT(goodSubRPC(jv));
970 sendPayments(env, env.
master, bob, 30, 300);
972 request[jss::account_history_tx_stream][jss::account] = bob.
human();
973 jv = wscTxHistory->invoke(
"subscribe", request);
975 bobFullHistoryVec.
clear();
977 getTxHash(*wscTxHistory, bobFullHistoryVec, 31).second);
978 jv = wscTxHistory->invoke(
"unsubscribe", request);
980 request[jss::account_history_tx_stream][jss::account] =
981 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
982 jv = wscTxHistory->invoke(
"subscribe", request);
983 genesisFullHistoryVec.
clear();
985 getTxHash(*wscTxHistory, genesisFullHistoryVec, 31).second);
986 jv = wscTxHistory->invoke(
"unsubscribe", request);
989 bobFullHistoryVec.back().second ==
990 genesisFullHistoryVec.back().second);
1003 env.
fund(
XRP(222222), accounts);
1009 stream[jss::accounts].append(alice.
human());
1010 auto jv = wscAccount->invoke(
"subscribe", stream);
1012 sendPayments(env, alice, bob, 5, 1);
1013 sendPayments(env, alice, bob, 5, 1);
1014 IdxHashVec accountVec;
1015 if (!BEAST_EXPECT(getTxHash(*wscAccount, accountVec, 10).first))
1021 request[jss::account_history_tx_stream][jss::account] =
1023 jv = wscTxHistory->invoke(
"subscribe", request);
1026 IdxHashVec txHistoryVec;
1027 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, txHistoryVec, 10).first))
1029 if (!BEAST_EXPECT(hashCompare(accountVec, txHistoryVec,
true)))
1034 IdxHashVec initFundTxns;
1036 getTxHash(*wscTxHistory, initFundTxns, 10).second))
1041 sendPayments(env, alice, bob, 10, 1);
1042 if (!BEAST_EXPECT(getTxHash(*wscAccount, accountVec, 10).first))
1044 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, txHistoryVec, 10).first))
1046 if (!BEAST_EXPECT(hashCompare(accountVec, txHistoryVec,
true)))
1048 wscTxHistory->invoke(
"unsubscribe", request);
1049 wscAccount->invoke(
"unsubscribe", stream);
1058 auto const USD_a = alice[
"USD"];
1061 env.
fund(
XRP(333333), accounts);
1062 env.
trust(USD_a(20000), carol);
1065 auto mixedPayments = [&]() ->
int {
1066 sendPayments(env, alice, carol, 1, 0);
1067 env(
pay(alice, carol, USD_a(100)));
1075 request[jss::account_history_tx_stream][jss::account] =
1078 auto jv = ws->invoke(
"subscribe", request);
1082 getTxHash(*ws, tempVec, 100);
1085 auto count = mixedPayments();
1087 if (!BEAST_EXPECT(getTxHash(*ws, vec1, count).first))
1089 ws->invoke(
"unsubscribe", request);
1098 env.
fund(
XRP(444444), accounts);
1102 auto oneRound = [&](
int numPayments) {
1103 return sendPayments(env, alice, carol, numPayments, 300);
1109 request[jss::account_history_tx_stream][jss::account] =
1112 auto jv = wscLong->invoke(
"subscribe", request);
1116 getTxHash(*wscLong, tempVec, 100);
1120 for (
int kk = 2; kk < 10; ++kk)
1122 auto count = oneRound(kk);
1124 if (!BEAST_EXPECT(getTxHash(*wscLong, vec1, count).first))
1129 auto jv = wscShort->invoke(
"subscribe", request);
1131 if (!BEAST_EXPECT(getTxHash(*wscShort, vec2, count).first))
1133 if (!BEAST_EXPECT(hashCompare(vec1, vec2,
true)))
1135 wscShort->invoke(
"unsubscribe", request);