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/Feature.h>
24 #include <ripple/protocol/jss.h>
26 #include <test/jtx/WSClient.h>
27 #include <test/jtx/envconfig.h>
39 using namespace std::chrono_literals;
48 stream[jss::streams].append(
"server");
49 auto jv = wsc->invoke(
"subscribe", stream);
50 if (wsc->version() == 2)
53 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
55 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
56 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
58 BEAST_EXPECT(jv[jss::status] ==
"success");
70 for (
int i = 0; i < 5; ++i)
75 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
76 return jv[jss::type] ==
"serverStatus";
82 auto jv = wsc->invoke(
"unsubscribe", stream);
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::status] ==
"success");
97 for (
int i = 0; i < 5; ++i)
102 auto jvo = wsc->getMsg(10ms);
103 BEAST_EXPECTS(!jvo,
"getMsg: " +
to_string(jvo.value()));
110 using namespace std::chrono_literals;
119 stream[jss::streams].append(
"ledger");
120 auto jv = wsc->invoke(
"subscribe", stream);
121 if (wsc->version() == 2)
124 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
126 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
127 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
129 BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 2);
137 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
138 return jv[jss::ledger_index] == 3;
147 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
148 return jv[jss::ledger_index] == 4;
153 auto jv = wsc->invoke(
"unsubscribe", stream);
154 if (wsc->version() == 2)
157 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
159 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
160 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
162 BEAST_EXPECT(jv[jss::status] ==
"success");
168 using namespace std::chrono_literals;
177 stream[jss::streams].append(
"transactions");
178 auto jv = wsc->invoke(
"subscribe", stream);
179 if (wsc->version() == 2)
182 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
184 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
185 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
187 BEAST_EXPECT(jv[jss::status] ==
"success");
195 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
196 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
197 [
"NewFields"][jss::Account] ==
198 Account(
"alice").human();
202 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
203 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
204 [
"FinalFields"][jss::Account] ==
205 Account(
"alice").human();
212 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
213 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
214 [
"NewFields"][jss::Account] == Account(
"bob").human();
218 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
219 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
220 [
"FinalFields"][jss::Account] ==
221 Account(
"bob").human();
227 auto jv = wsc->invoke(
"unsubscribe", stream);
228 if (wsc->version() == 2)
231 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
233 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
234 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
236 BEAST_EXPECT(jv[jss::status] ==
"success");
243 stream[jss::accounts].append(
Account(
"alice").human());
244 auto jv = wsc->invoke(
"subscribe", stream);
245 if (wsc->version() == 2)
248 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
250 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
251 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
253 BEAST_EXPECT(jv[jss::status] ==
"success");
260 BEAST_EXPECT(!wsc->getMsg(10ms));
267 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
268 return jv[jss::meta][
"AffectedNodes"][1u][
"ModifiedNode"]
269 [
"FinalFields"][jss::Account] ==
270 Account(
"alice").human();
273 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
274 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
275 [
"NewFields"][
"LowLimit"][jss::issuer] ==
276 Account(
"alice").human();
281 auto jv = wsc->invoke(
"unsubscribe", stream);
282 if (wsc->version() == 2)
285 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
287 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
288 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
290 BEAST_EXPECT(jv[jss::status] ==
"success");
304 stream[jss::streams].append(
"manifests");
305 auto jv = wsc->invoke(
"subscribe", stream);
306 if (wsc->version() == 2)
309 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
311 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
312 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
314 BEAST_EXPECT(jv[jss::status] ==
"success");
318 auto jv = wsc->invoke(
"unsubscribe", stream);
319 if (wsc->version() == 2)
322 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
324 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
325 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
327 BEAST_EXPECT(jv[jss::status] ==
"success");
336 auto& cfg = env.app().config();
337 if (!BEAST_EXPECT(cfg.section(SECTION_VALIDATION_SEED).empty()))
339 auto const parsedseed =
340 parseBase58<Seed>(cfg.section(SECTION_VALIDATION_SEED).values()[0]);
341 if (!BEAST_EXPECT(parsedseed))
356 stream[jss::streams].append(
"validations");
357 auto jv = wsc->invoke(
"subscribe", stream);
358 if (wsc->version() == 2)
361 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
363 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
364 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
366 BEAST_EXPECT(jv[jss::status] ==
"success");
371 auto validValidationFields = [&env, &valPublicKey](
373 if (jv[jss::type] !=
"validationReceived")
376 if (jv[jss::validation_public_key].asString() != valPublicKey)
379 if (jv[jss::ledger_hash] !=
383 if (jv[jss::ledger_index] !=
390 if (jv[jss::full] !=
true)
393 if (jv.isMember(jss::load_fee))
396 if (!jv.isMember(jss::signature))
399 if (!jv.isMember(jss::signing_time))
402 if (!jv.isMember(jss::cookie))
405 if (!jv.isMember(jss::validated_hash))
410 (env.closed()->info().seq + 1) % 256 == 0;
426 while (env.closed()->info().seq < 300)
429 using namespace std::chrono_literals;
430 BEAST_EXPECT(wsc->findMsg(5s, validValidationFields));
435 auto jv = wsc->invoke(
"unsubscribe", stream);
436 if (wsc->version() == 2)
439 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
441 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
442 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
444 BEAST_EXPECT(jv[jss::status] ==
"success");
451 testcase(
"Subscribe by url");
455 jv[jss::url] =
"http://localhost/events";
456 jv[jss::url_username] =
"admin";
457 jv[jss::url_password] =
"password";
459 jv[jss::streams][0u] =
"validations";
460 auto jr = env.rpc(
"json",
"subscribe",
to_string(jv))[jss::result];
461 BEAST_EXPECT(jr[jss::status] ==
"success");
463 jv[jss::streams][0u] =
"ledger";
464 jr = env.rpc(
"json",
"subscribe",
to_string(jv))[jss::result];
465 BEAST_EXPECT(jr[jss::status] ==
"success");
467 jr = env.rpc(
"json",
"unsubscribe",
to_string(jv))[jss::result];
468 BEAST_EXPECT(jr[jss::status] ==
"success");
470 jv[jss::streams][0u] =
"validations";
471 jr = env.rpc(
"json",
"unsubscribe",
to_string(jv))[jss::result];
472 BEAST_EXPECT(jr[jss::status] ==
"success");
479 auto const method = subscribe ?
"subscribe" :
"unsubscribe";
480 testcase <<
"Error cases for " << method;
486 auto jr = env.rpc(
"json", method,
"{}")[jss::result];
487 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
488 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
493 jv[jss::url] =
"not-a-url";
494 jv[jss::username] =
"admin";
495 jv[jss::password] =
"password";
496 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
499 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
500 BEAST_EXPECT(jr[jss::error_message] ==
"Failed to parse url.");
508 jv[jss::url] =
"ftp://scheme.not.supported.tld";
509 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
512 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
514 jr[jss::error_message] ==
515 "Only http and https is supported.");
522 jv[jss::url] =
"no-url";
524 env_nonadmin.rpc(
"json", method,
to_string(jv))[jss::result];
525 BEAST_EXPECT(jr[jss::error] ==
"noPermission");
527 jr[jss::error_message] ==
528 "You don't have permission for this command.");
540 for (
auto const& f : {jss::accounts_proposed, jss::accounts})
542 for (
auto const& nonArray : nonArrays)
546 auto jr = wsc->invoke(method, jv)[jss::result];
547 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
548 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
554 auto jr = wsc->invoke(method, jv)[jss::result];
555 BEAST_EXPECT(jr[jss::error] ==
"actMalformed");
556 BEAST_EXPECT(jr[jss::error_message] ==
"Account malformed.");
560 for (
auto const& nonArray : nonArrays)
563 jv[jss::books] = nonArray;
564 auto jr = wsc->invoke(method, jv)[jss::result];
565 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
566 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
572 jv[jss::books][0u] = 1;
573 auto jr = wsc->invoke(method, jv)[jss::result];
574 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
575 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
584 auto jr = wsc->invoke(method, jv)[jss::result];
585 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
587 jr[jss::error_message] ==
"Source currency is malformed.");
596 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"ZZZZ";
597 auto jr = wsc->invoke(method, jv)[jss::result];
598 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
600 jr[jss::error_message] ==
"Source currency is malformed.");
609 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
610 jv[jss::books][0u][jss::taker_pays][jss::issuer] = 1;
611 auto jr = wsc->invoke(method, jv)[jss::result];
612 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
614 jr[jss::error_message] ==
"Source issuer is malformed.");
623 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
624 jv[jss::books][0u][jss::taker_pays][jss::issuer] =
626 auto jr = wsc->invoke(method, jv)[jss::result];
627 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
629 jr[jss::error_message] ==
"Source issuer is malformed.");
636 jv[jss::books][0u][jss::taker_pays] =
637 Account{
"gateway"}[
"USD"](1).value().getJson(
640 auto jr = wsc->invoke(method, jv)[jss::result];
643 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
645 jr[jss::error_message] ==
646 "Destination amount/currency/issuer is malformed.");
653 jv[jss::books][0u][jss::taker_pays] =
654 Account{
"gateway"}[
"USD"](1).value().getJson(
656 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"ZZZZ";
657 auto jr = wsc->invoke(method, jv)[jss::result];
660 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
662 jr[jss::error_message] ==
663 "Destination amount/currency/issuer is malformed.");
670 jv[jss::books][0u][jss::taker_pays] =
671 Account{
"gateway"}[
"USD"](1).value().getJson(
673 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
674 jv[jss::books][0u][jss::taker_gets][jss::issuer] = 1;
675 auto jr = wsc->invoke(method, jv)[jss::result];
676 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
678 jr[jss::error_message] ==
"Destination issuer is malformed.");
685 jv[jss::books][0u][jss::taker_pays] =
686 Account{
"gateway"}[
"USD"](1).value().getJson(
688 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
689 jv[jss::books][0u][jss::taker_gets][jss::issuer] =
691 auto jr = wsc->invoke(method, jv)[jss::result];
692 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
694 jr[jss::error_message] ==
"Destination issuer is malformed.");
701 jv[jss::books][0u][jss::taker_pays] =
702 Account{
"gateway"}[
"USD"](1).value().getJson(
704 jv[jss::books][0u][jss::taker_gets] =
705 Account{
"gateway"}[
"USD"](1).value().getJson(
707 auto jr = wsc->invoke(method, jv)[jss::result];
708 BEAST_EXPECT(jr[jss::error] ==
"badMarket");
709 BEAST_EXPECT(jr[jss::error_message] ==
"No such market.");
712 for (
auto const& nonArray : nonArrays)
715 jv[jss::streams] = nonArray;
716 auto jr = wsc->invoke(method, jv)[jss::result];
717 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
718 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
724 jv[jss::streams][0u] = 1;
725 auto jr = wsc->invoke(method, jv)[jss::result];
726 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
727 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
733 jv[jss::streams][0u] =
"not_a_stream";
734 auto jr = wsc->invoke(method, jv)[jss::result];
735 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
736 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
743 testcase(
"HistoryTxStream");
745 using namespace std::chrono_literals;
758 auto goodSubRPC = [](
Json::Value const& subReply) ->
bool {
759 return subReply.isMember(jss::result) &&
760 subReply[jss::result].isMember(jss::status) &&
761 subReply[jss::result][jss::status] == jss::success;
772 bool first_flag =
false;
774 for (
int i = 0; i < numReplies; ++i)
777 auto reply = wsc.
getMsg(100ms);
781 if (r.isMember(jss::account_history_tx_index))
782 idx = r[jss::account_history_tx_index].asInt();
783 if (r.isMember(jss::account_history_tx_first))
785 bool boundary = r.isMember(jss::account_history_boundary);
786 int ledger_idx = r[jss::ledger_index].asInt();
787 if (r.isMember(jss::transaction) &&
788 r[jss::transaction].isMember(jss::hash))
790 auto t{r[jss::transaction]};
792 idx, t[jss::hash].asString(), boundary, ledger_idx);
796 return {
false, first_flag};
799 return {
true, first_flag};
806 auto sendPayments = [](
Env& env,
814 for (
int i = 0; i < newTxns; ++i)
816 auto& from = (i % 2 == 0) ? a : b;
817 auto& to = (i % 2 == 0) ? b : a;
824 for (
int i = 0; i < ledgersToClose; ++i)
834 auto hashCompare = [](IdxHashVec
const& accountVec,
835 IdxHashVec
const& txHistoryVec,
836 bool sizeCompare) ->
bool {
837 if (accountVec.empty() || txHistoryVec.empty())
839 if (sizeCompare && accountVec.size() != (txHistoryVec.size()))
843 for (
auto const& tx : txHistoryVec)
845 txHistoryMap.
emplace(std::get<1>(tx), std::get<0>(tx));
849 if (i >= accountVec.size())
851 auto it = txHistoryMap.
find(std::get<1>(accountVec[i]));
852 if (it == txHistoryMap.
end())
857 auto firstHistoryIndex = getHistoryIndex(0);
858 if (!firstHistoryIndex)
860 for (
std::size_t i = 1; i < accountVec.size(); ++i)
862 if (
auto idx = getHistoryIndex(i);
863 !idx || *idx != *firstHistoryIndex + i)
899 auto checkBoundary = [](IdxHashVec
const& vec,
bool ) {
900 size_t num_tx = vec.size();
901 for (
size_t i = 0; i < num_tx; ++i)
903 auto [idx, hash, boundary, ledger] = vec[i];
904 if ((i + 1 == num_tx || ledger != std::get<3>(vec[i + 1])) !=
924 request[jss::account_history_tx_stream][jss::account] =
926 auto jv = wscTxHistory->invoke(
"subscribe", request);
927 if (!BEAST_EXPECT(goodSubRPC(jv)))
930 jv = wscTxHistory->invoke(
"subscribe", request);
931 BEAST_EXPECT(!goodSubRPC(jv));
936 request[jss::account_history_tx_stream][jss::stop_history_tx_only] =
938 jv = wscTxHistory->invoke(
"unsubscribe", request);
939 if (!BEAST_EXPECT(goodSubRPC(jv)))
942 sendPayments(env, env.
master, alice, 1, 1, 123456);
945 auto r = getTxHash(*wscTxHistory, vec, 1);
946 if (!BEAST_EXPECT(r.first && r.second))
952 request[jss::account_history_tx_stream][jss::stop_history_tx_only] =
954 jv = wscTxHistory->invoke(
"unsubscribe", request);
955 BEAST_EXPECT(goodSubRPC(jv));
957 sendPayments(env, env.
master, alice, 1, 1);
958 r = getTxHash(*wscTxHistory, vec, 1);
959 BEAST_EXPECT(!r.first);
970 request[jss::account_history_tx_stream][jss::account] =
971 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
972 auto jv = wscTxHistory->invoke(
"subscribe", request);
973 if (!BEAST_EXPECT(goodSubRPC(jv)))
975 IdxHashVec genesisFullHistoryVec;
977 !getTxHash(*wscTxHistory, genesisFullHistoryVec, 1).first))
984 sendPayments(env, env.
master, bob, 1, 1, 654321);
986 auto r = getTxHash(*wscTxHistory, genesisFullHistoryVec, 1);
987 if (!BEAST_EXPECT(r.first && r.second))
990 request[jss::account_history_tx_stream][jss::account] = bob.
human();
991 jv = wscTxHistory->invoke(
"subscribe", request);
992 if (!BEAST_EXPECT(goodSubRPC(jv)))
994 IdxHashVec bobFullHistoryVec;
995 r = getTxHash(*wscTxHistory, bobFullHistoryVec, 1);
996 if (!BEAST_EXPECT(r.first && r.second))
999 std::get<1>(bobFullHistoryVec.back()) ==
1000 std::get<1>(genesisFullHistoryVec.back()));
1005 jv = wscTxHistory->invoke(
"unsubscribe", request);
1006 if (!BEAST_EXPECT(goodSubRPC(jv)))
1008 request[jss::account_history_tx_stream][jss::account] =
1009 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1010 jv = wscTxHistory->invoke(
"unsubscribe", request);
1011 BEAST_EXPECT(goodSubRPC(jv));
1017 sendPayments(env, env.
master, bob, 30, 300);
1019 request[jss::account_history_tx_stream][jss::account] = bob.
human();
1020 jv = wscTxHistory->invoke(
"subscribe", request);
1022 bobFullHistoryVec.
clear();
1024 getTxHash(*wscTxHistory, bobFullHistoryVec, 31).second);
1025 jv = wscTxHistory->invoke(
"unsubscribe", request);
1027 request[jss::account_history_tx_stream][jss::account] =
1028 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1029 jv = wscTxHistory->invoke(
"subscribe", request);
1030 genesisFullHistoryVec.
clear();
1032 getTxHash(*wscTxHistory, genesisFullHistoryVec, 31).second);
1033 jv = wscTxHistory->invoke(
"unsubscribe", request);
1036 std::get<1>(bobFullHistoryVec.back()) ==
1037 std::get<1>(genesisFullHistoryVec.back()));
1050 env.
fund(
XRP(222222), accounts);
1056 stream[jss::accounts].append(alice.
human());
1057 auto jv = wscAccount->invoke(
"subscribe", stream);
1059 sendPayments(env, alice, bob, 5, 1);
1060 sendPayments(env, alice, bob, 5, 1);
1061 IdxHashVec accountVec;
1062 if (!BEAST_EXPECT(getTxHash(*wscAccount, accountVec, 10).first))
1068 request[jss::account_history_tx_stream][jss::account] =
1070 jv = wscTxHistory->invoke(
"subscribe", request);
1073 IdxHashVec txHistoryVec;
1074 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, txHistoryVec, 10).first))
1076 if (!BEAST_EXPECT(hashCompare(accountVec, txHistoryVec,
true)))
1081 if (!BEAST_EXPECT(checkBoundary(txHistoryVec,
false)))
1086 IdxHashVec initFundTxns;
1088 getTxHash(*wscTxHistory, initFundTxns, 10).second) ||
1089 !BEAST_EXPECT(checkBoundary(initFundTxns,
false)))
1094 sendPayments(env, alice, bob, 10, 1);
1095 if (!BEAST_EXPECT(getTxHash(*wscAccount, accountVec, 10).first))
1097 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, txHistoryVec, 10).first))
1099 if (!BEAST_EXPECT(hashCompare(accountVec, txHistoryVec,
true)))
1104 if (!BEAST_EXPECT(checkBoundary(txHistoryVec,
false)))
1107 wscTxHistory->invoke(
"unsubscribe", request);
1108 wscAccount->invoke(
"unsubscribe", stream);
1117 auto const USD_a = alice[
"USD"];
1120 env.
fund(
XRP(333333), accounts);
1121 env.
trust(USD_a(20000), carol);
1124 auto mixedPayments = [&]() ->
int {
1125 sendPayments(env, alice, carol, 1, 0);
1126 env(pay(alice, carol, USD_a(100)));
1134 request[jss::account_history_tx_stream][jss::account] =
1137 auto jv = ws->invoke(
"subscribe", request);
1141 getTxHash(*ws, tempVec, 100);
1144 auto count = mixedPayments();
1146 if (!BEAST_EXPECT(getTxHash(*ws, vec1, count).first))
1148 ws->invoke(
"unsubscribe", request);
1157 env.
fund(
XRP(444444), accounts);
1161 auto oneRound = [&](
int numPayments) {
1162 return sendPayments(env, alice, carol, numPayments, 300);
1168 request[jss::account_history_tx_stream][jss::account] =
1171 auto jv = wscLong->invoke(
"subscribe", request);
1175 getTxHash(*wscLong, tempVec, 100);
1179 for (
int kk = 2; kk < 10; ++kk)
1181 auto count = oneRound(kk);
1183 if (!BEAST_EXPECT(getTxHash(*wscLong, vec1, count).first))
1188 auto jv = wscShort->invoke(
"subscribe", request);
1190 if (!BEAST_EXPECT(getTxHash(*wscShort, vec2, count).first))
1192 if (!BEAST_EXPECT(hashCompare(vec1, vec2,
true)))
1194 wscShort->invoke(
"unsubscribe", request);
1202 using namespace test::jtx;