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/json/json_value.h>
24 #include <ripple/protocol/Feature.h>
25 #include <ripple/protocol/jss.h>
27 #include <test/jtx/WSClient.h>
28 #include <test/jtx/envconfig.h>
40 using namespace std::chrono_literals;
49 stream[jss::streams].append(
"server");
50 auto jv = wsc->invoke(
"subscribe", stream);
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);
59 BEAST_EXPECT(jv[jss::status] ==
"success");
71 for (
int i = 0; i < 5; ++i)
76 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
77 return jv[jss::type] ==
"serverStatus";
83 auto jv = wsc->invoke(
"unsubscribe", stream);
84 if (wsc->version() == 2)
87 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
89 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
90 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
92 BEAST_EXPECT(jv[jss::status] ==
"success");
98 for (
int i = 0; i < 5; ++i)
103 auto jvo = wsc->getMsg(10ms);
104 BEAST_EXPECTS(!jvo,
"getMsg: " +
to_string(jvo.value()));
111 using namespace std::chrono_literals;
120 stream[jss::streams].append(
"ledger");
121 auto jv = wsc->invoke(
"subscribe", stream);
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][jss::ledger_index] == 2);
138 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
139 return jv[jss::ledger_index] == 3;
148 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
149 return jv[jss::ledger_index] == 4;
154 auto jv = wsc->invoke(
"unsubscribe", stream);
155 if (wsc->version() == 2)
158 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
160 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
161 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
163 BEAST_EXPECT(jv[jss::status] ==
"success");
169 using namespace std::chrono_literals;
178 stream[jss::streams].append(
"transactions");
179 auto jv = wsc->invoke(
"subscribe", stream);
180 if (wsc->version() == 2)
183 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
185 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
186 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
188 BEAST_EXPECT(jv[jss::status] ==
"success");
196 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
197 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
198 [
"NewFields"][jss::Account]
199 == Account(
"alice").human() &&
200 jv[jss::transaction][jss::TransactionType]
202 jv[jss::transaction][jss::DeliverMax]
204 jv[jss::transaction][jss::Fee]
206 jv[jss::transaction][jss::Sequence]
211 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
212 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
213 [
"FinalFields"][jss::Account] ==
214 Account(
"alice").human();
221 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
222 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
223 [
"NewFields"][jss::Account]
224 == Account(
"bob").human() &&
225 jv[jss::transaction][jss::TransactionType]
227 jv[jss::transaction][jss::DeliverMax]
229 jv[jss::transaction][jss::Fee]
231 jv[jss::transaction][jss::Sequence]
236 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
237 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
238 [
"FinalFields"][jss::Account] ==
239 Account(
"bob").human();
245 auto jv = wsc->invoke(
"unsubscribe", stream);
246 if (wsc->version() == 2)
249 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
251 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
252 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
254 BEAST_EXPECT(jv[jss::status] ==
"success");
261 stream[jss::accounts].append(
Account(
"alice").human());
262 auto jv = wsc->invoke(
"subscribe", stream);
263 if (wsc->version() == 2)
266 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
268 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
269 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
271 BEAST_EXPECT(jv[jss::status] ==
"success");
278 BEAST_EXPECT(!wsc->getMsg(10ms));
285 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
286 return jv[jss::meta][
"AffectedNodes"][1u][
"ModifiedNode"]
287 [
"FinalFields"][jss::Account] ==
288 Account(
"alice").human();
291 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
292 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
293 [
"NewFields"][
"LowLimit"][jss::issuer] ==
294 Account(
"alice").human();
299 auto jv = wsc->invoke(
"unsubscribe", stream);
300 if (wsc->version() == 2)
303 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
305 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
306 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
308 BEAST_EXPECT(jv[jss::status] ==
"success");
314 testcase(
"transactions API version 2");
316 using namespace std::chrono_literals;
324 stream[jss::api_version] = 2;
326 stream[jss::streams].append(
"transactions");
327 auto jv = wsc->invoke(
"subscribe", stream);
328 if (wsc->version() == 2)
331 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
333 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
334 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
336 BEAST_EXPECT(jv[jss::status] ==
"success");
344 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
345 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
346 [
"NewFields"][jss::Account]
347 == Account(
"alice").human() &&
348 jv[jss::close_time_iso]
349 ==
"2000-01-01T00:00:10Z" &&
350 jv[jss::validated] == true &&
351 jv[jss::ledger_hash] ==
352 "0F1A9E0C109ADEF6DA2BDE19217C12BBEC57174CBDBD212B0EBDC1CEDB"
354 !jv[jss::inLedger] &&
355 jv[jss::ledger_index] == 3 &&
356 jv[jss::tx_json][jss::TransactionType]
358 jv[jss::tx_json][jss::DeliverMax]
360 !jv[jss::tx_json].isMember(jss::Amount) &&
361 jv[jss::tx_json][jss::Fee]
363 jv[jss::tx_json][jss::Sequence]
368 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
369 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
370 [
"FinalFields"][jss::Account] ==
371 Account(
"alice").human();
377 auto jv = wsc->invoke(
"unsubscribe", stream);
378 if (wsc->version() == 2)
381 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
383 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
384 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
386 BEAST_EXPECT(jv[jss::status] ==
"success");
401 stream[jss::streams].append(
"manifests");
402 auto jv = wsc->invoke(
"subscribe", stream);
403 if (wsc->version() == 2)
406 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
408 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
409 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
411 BEAST_EXPECT(jv[jss::status] ==
"success");
415 auto jv = wsc->invoke(
"unsubscribe", stream);
416 if (wsc->version() == 2)
419 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
421 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
422 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
424 BEAST_EXPECT(jv[jss::status] ==
"success");
433 auto& cfg = env.app().config();
434 if (!BEAST_EXPECT(cfg.section(SECTION_VALIDATION_SEED).empty()))
436 auto const parsedseed =
437 parseBase58<Seed>(cfg.section(SECTION_VALIDATION_SEED).values()[0]);
438 if (!BEAST_EXPECT(parsedseed))
453 stream[jss::streams].append(
"validations");
454 auto jv = wsc->invoke(
"subscribe", stream);
455 if (wsc->version() == 2)
458 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
460 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
461 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
463 BEAST_EXPECT(jv[jss::status] ==
"success");
468 auto validValidationFields = [&env, &valPublicKey](
470 if (jv[jss::type] !=
"validationReceived")
473 if (jv[jss::validation_public_key].asString() != valPublicKey)
476 if (jv[jss::ledger_hash] !=
480 if (jv[jss::ledger_index] !=
487 if (jv[jss::full] !=
true)
490 if (jv.isMember(jss::load_fee))
493 if (!jv.isMember(jss::signature))
496 if (!jv.isMember(jss::signing_time))
499 if (!jv.isMember(jss::cookie))
502 if (!jv.isMember(jss::validated_hash))
507 (env.closed()->info().seq + 1) % 256 == 0;
523 while (env.closed()->info().seq < 300)
526 using namespace std::chrono_literals;
527 BEAST_EXPECT(wsc->findMsg(5s, validValidationFields));
532 auto jv = wsc->invoke(
"unsubscribe", stream);
533 if (wsc->version() == 2)
536 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
538 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
539 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
541 BEAST_EXPECT(jv[jss::status] ==
"success");
548 testcase(
"Subscribe by url");
552 jv[jss::url] =
"http://localhost/events";
553 jv[jss::url_username] =
"admin";
554 jv[jss::url_password] =
"password";
556 jv[jss::streams][0u] =
"validations";
557 auto jr = env.rpc(
"json",
"subscribe",
to_string(jv))[jss::result];
558 BEAST_EXPECT(jr[jss::status] ==
"success");
560 jv[jss::streams][0u] =
"ledger";
561 jr = env.rpc(
"json",
"subscribe",
to_string(jv))[jss::result];
562 BEAST_EXPECT(jr[jss::status] ==
"success");
564 jr = env.rpc(
"json",
"unsubscribe",
to_string(jv))[jss::result];
565 BEAST_EXPECT(jr[jss::status] ==
"success");
567 jv[jss::streams][0u] =
"validations";
568 jr = env.rpc(
"json",
"unsubscribe",
to_string(jv))[jss::result];
569 BEAST_EXPECT(jr[jss::status] ==
"success");
576 auto const method = subscribe ?
"subscribe" :
"unsubscribe";
577 testcase <<
"Error cases for " << method;
583 auto jr = env.rpc(
"json", method,
"{}")[jss::result];
584 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
585 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
590 jv[jss::url] =
"not-a-url";
591 jv[jss::username] =
"admin";
592 jv[jss::password] =
"password";
593 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
596 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
597 BEAST_EXPECT(jr[jss::error_message] ==
"Failed to parse url.");
605 jv[jss::url] =
"ftp://scheme.not.supported.tld";
606 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
609 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
611 jr[jss::error_message] ==
612 "Only http and https is supported.");
619 jv[jss::url] =
"no-url";
621 env_nonadmin.rpc(
"json", method,
to_string(jv))[jss::result];
622 BEAST_EXPECT(jr[jss::error] ==
"noPermission");
624 jr[jss::error_message] ==
625 "You don't have permission for this command.");
637 for (
auto const& f : {jss::accounts_proposed, jss::accounts})
639 for (
auto const& nonArray : nonArrays)
643 auto jr = wsc->invoke(method, jv)[jss::result];
644 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
645 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
651 auto jr = wsc->invoke(method, jv)[jss::result];
652 BEAST_EXPECT(jr[jss::error] ==
"actMalformed");
653 BEAST_EXPECT(jr[jss::error_message] ==
"Account malformed.");
657 for (
auto const& nonArray : nonArrays)
660 jv[jss::books] = nonArray;
661 auto jr = wsc->invoke(method, jv)[jss::result];
662 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
663 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
669 jv[jss::books][0u] = 1;
670 auto jr = wsc->invoke(method, jv)[jss::result];
671 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
672 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
681 auto jr = wsc->invoke(method, jv)[jss::result];
682 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
684 jr[jss::error_message] ==
"Source currency is malformed.");
693 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"ZZZZ";
694 auto jr = wsc->invoke(method, jv)[jss::result];
695 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
697 jr[jss::error_message] ==
"Source currency is malformed.");
706 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
707 jv[jss::books][0u][jss::taker_pays][jss::issuer] = 1;
708 auto jr = wsc->invoke(method, jv)[jss::result];
709 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
711 jr[jss::error_message] ==
"Source issuer is malformed.");
720 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
721 jv[jss::books][0u][jss::taker_pays][jss::issuer] =
723 auto jr = wsc->invoke(method, jv)[jss::result];
724 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
726 jr[jss::error_message] ==
"Source issuer is malformed.");
733 jv[jss::books][0u][jss::taker_pays] =
734 Account{
"gateway"}[
"USD"](1).value().getJson(
737 auto jr = wsc->invoke(method, jv)[jss::result];
740 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
742 jr[jss::error_message] ==
743 "Destination amount/currency/issuer is malformed.");
750 jv[jss::books][0u][jss::taker_pays] =
751 Account{
"gateway"}[
"USD"](1).value().getJson(
753 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"ZZZZ";
754 auto jr = wsc->invoke(method, jv)[jss::result];
757 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
759 jr[jss::error_message] ==
760 "Destination amount/currency/issuer is malformed.");
767 jv[jss::books][0u][jss::taker_pays] =
768 Account{
"gateway"}[
"USD"](1).value().getJson(
770 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
771 jv[jss::books][0u][jss::taker_gets][jss::issuer] = 1;
772 auto jr = wsc->invoke(method, jv)[jss::result];
773 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
775 jr[jss::error_message] ==
"Destination issuer is malformed.");
782 jv[jss::books][0u][jss::taker_pays] =
783 Account{
"gateway"}[
"USD"](1).value().getJson(
785 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
786 jv[jss::books][0u][jss::taker_gets][jss::issuer] =
788 auto jr = wsc->invoke(method, jv)[jss::result];
789 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
791 jr[jss::error_message] ==
"Destination issuer is malformed.");
798 jv[jss::books][0u][jss::taker_pays] =
799 Account{
"gateway"}[
"USD"](1).value().getJson(
801 jv[jss::books][0u][jss::taker_gets] =
802 Account{
"gateway"}[
"USD"](1).value().getJson(
804 auto jr = wsc->invoke(method, jv)[jss::result];
805 BEAST_EXPECT(jr[jss::error] ==
"badMarket");
806 BEAST_EXPECT(jr[jss::error_message] ==
"No such market.");
809 for (
auto const& nonArray : nonArrays)
812 jv[jss::streams] = nonArray;
813 auto jr = wsc->invoke(method, jv)[jss::result];
814 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
815 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
821 jv[jss::streams][0u] = 1;
822 auto jr = wsc->invoke(method, jv)[jss::result];
823 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
824 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
830 jv[jss::streams][0u] =
"not_a_stream";
831 auto jr = wsc->invoke(method, jv)[jss::result];
832 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
833 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
840 testcase(
"HistoryTxStream");
842 using namespace std::chrono_literals;
855 auto goodSubRPC = [](
Json::Value const& subReply) ->
bool {
856 return subReply.isMember(jss::result) &&
857 subReply[jss::result].isMember(jss::status) &&
858 subReply[jss::result][jss::status] == jss::success;
869 bool first_flag =
false;
871 for (
int i = 0; i < numReplies; ++i)
874 auto reply = wsc.
getMsg(100ms);
878 if (r.isMember(jss::account_history_tx_index))
879 idx = r[jss::account_history_tx_index].asInt();
880 if (r.isMember(jss::account_history_tx_first))
882 bool boundary = r.isMember(jss::account_history_boundary);
883 int ledger_idx = r[jss::ledger_index].asInt();
884 if (r.isMember(jss::transaction) &&
885 r[jss::transaction].isMember(jss::hash))
887 auto t{r[jss::transaction]};
889 idx, t[jss::hash].asString(), boundary, ledger_idx);
893 return {
false, first_flag};
896 return {
true, first_flag};
903 auto sendPayments = [](
Env& env,
911 for (
int i = 0; i < newTxns; ++i)
913 auto& from = (i % 2 == 0) ? a : b;
914 auto& to = (i % 2 == 0) ? b : a;
921 for (
int i = 0; i < ledgersToClose; ++i)
931 auto hashCompare = [](IdxHashVec
const& accountVec,
932 IdxHashVec
const& txHistoryVec,
933 bool sizeCompare) ->
bool {
934 if (accountVec.empty() || txHistoryVec.empty())
936 if (sizeCompare && accountVec.size() != (txHistoryVec.size()))
940 for (
auto const& tx : txHistoryVec)
942 txHistoryMap.
emplace(std::get<1>(tx), std::get<0>(tx));
946 if (i >= accountVec.size())
948 auto it = txHistoryMap.
find(std::get<1>(accountVec[i]));
949 if (it == txHistoryMap.
end())
954 auto firstHistoryIndex = getHistoryIndex(0);
955 if (!firstHistoryIndex)
957 for (
std::size_t i = 1; i < accountVec.size(); ++i)
959 if (
auto idx = getHistoryIndex(i);
960 !idx || *idx != *firstHistoryIndex + i)
996 auto checkBoundary = [](IdxHashVec
const& vec,
bool ) {
997 size_t num_tx = vec.size();
998 for (
size_t i = 0; i < num_tx; ++i)
1000 auto [idx, hash, boundary, ledger] = vec[i];
1001 if ((i + 1 == num_tx || ledger != std::get<3>(vec[i + 1])) !=
1021 request[jss::account_history_tx_stream][jss::account] =
1023 auto jv = wscTxHistory->invoke(
"subscribe", request);
1024 if (!BEAST_EXPECT(goodSubRPC(jv)))
1027 jv = wscTxHistory->invoke(
"subscribe", request);
1028 BEAST_EXPECT(!goodSubRPC(jv));
1033 request[jss::account_history_tx_stream][jss::stop_history_tx_only] =
1035 jv = wscTxHistory->invoke(
"unsubscribe", request);
1036 if (!BEAST_EXPECT(goodSubRPC(jv)))
1039 sendPayments(env, env.
master, alice, 1, 1, 123456);
1042 auto r = getTxHash(*wscTxHistory, vec, 1);
1043 if (!BEAST_EXPECT(r.first && r.second))
1049 request[jss::account_history_tx_stream][jss::stop_history_tx_only] =
1051 jv = wscTxHistory->invoke(
"unsubscribe", request);
1052 BEAST_EXPECT(goodSubRPC(jv));
1054 sendPayments(env, env.
master, alice, 1, 1);
1055 r = getTxHash(*wscTxHistory, vec, 1);
1056 BEAST_EXPECT(!r.first);
1067 request[jss::account_history_tx_stream][jss::account] =
1068 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1069 auto jv = wscTxHistory->invoke(
"subscribe", request);
1070 if (!BEAST_EXPECT(goodSubRPC(jv)))
1072 IdxHashVec genesisFullHistoryVec;
1074 !getTxHash(*wscTxHistory, genesisFullHistoryVec, 1).first))
1081 sendPayments(env, env.
master, bob, 1, 1, 654321);
1083 auto r = getTxHash(*wscTxHistory, genesisFullHistoryVec, 1);
1084 if (!BEAST_EXPECT(r.first && r.second))
1087 request[jss::account_history_tx_stream][jss::account] = bob.
human();
1088 jv = wscTxHistory->invoke(
"subscribe", request);
1089 if (!BEAST_EXPECT(goodSubRPC(jv)))
1091 IdxHashVec bobFullHistoryVec;
1092 r = getTxHash(*wscTxHistory, bobFullHistoryVec, 1);
1093 if (!BEAST_EXPECT(r.first && r.second))
1096 std::get<1>(bobFullHistoryVec.back()) ==
1097 std::get<1>(genesisFullHistoryVec.back()));
1102 jv = wscTxHistory->invoke(
"unsubscribe", request);
1103 if (!BEAST_EXPECT(goodSubRPC(jv)))
1105 request[jss::account_history_tx_stream][jss::account] =
1106 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1107 jv = wscTxHistory->invoke(
"unsubscribe", request);
1108 BEAST_EXPECT(goodSubRPC(jv));
1114 sendPayments(env, env.
master, bob, 30, 300);
1116 request[jss::account_history_tx_stream][jss::account] = bob.
human();
1117 jv = wscTxHistory->invoke(
"subscribe", request);
1119 bobFullHistoryVec.
clear();
1121 getTxHash(*wscTxHistory, bobFullHistoryVec, 31).second);
1122 jv = wscTxHistory->invoke(
"unsubscribe", request);
1124 request[jss::account_history_tx_stream][jss::account] =
1125 "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1126 jv = wscTxHistory->invoke(
"subscribe", request);
1127 genesisFullHistoryVec.
clear();
1129 getTxHash(*wscTxHistory, genesisFullHistoryVec, 31).second);
1130 jv = wscTxHistory->invoke(
"unsubscribe", request);
1133 std::get<1>(bobFullHistoryVec.back()) ==
1134 std::get<1>(genesisFullHistoryVec.back()));
1147 env.
fund(
XRP(222222), accounts);
1153 stream[jss::accounts].append(alice.
human());
1154 auto jv = wscAccount->invoke(
"subscribe", stream);
1156 sendPayments(env, alice, bob, 5, 1);
1157 sendPayments(env, alice, bob, 5, 1);
1158 IdxHashVec accountVec;
1159 if (!BEAST_EXPECT(getTxHash(*wscAccount, accountVec, 10).first))
1165 request[jss::account_history_tx_stream][jss::account] =
1167 jv = wscTxHistory->invoke(
"subscribe", request);
1170 IdxHashVec txHistoryVec;
1171 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, txHistoryVec, 10).first))
1173 if (!BEAST_EXPECT(hashCompare(accountVec, txHistoryVec,
true)))
1178 if (!BEAST_EXPECT(checkBoundary(txHistoryVec,
false)))
1183 IdxHashVec initFundTxns;
1185 getTxHash(*wscTxHistory, initFundTxns, 10).second) ||
1186 !BEAST_EXPECT(checkBoundary(initFundTxns,
false)))
1191 sendPayments(env, alice, bob, 10, 1);
1192 if (!BEAST_EXPECT(getTxHash(*wscAccount, accountVec, 10).first))
1194 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, txHistoryVec, 10).first))
1196 if (!BEAST_EXPECT(hashCompare(accountVec, txHistoryVec,
true)))
1201 if (!BEAST_EXPECT(checkBoundary(txHistoryVec,
false)))
1204 wscTxHistory->invoke(
"unsubscribe", request);
1205 wscAccount->invoke(
"unsubscribe", stream);
1214 auto const USD_a = alice[
"USD"];
1217 env.
fund(
XRP(333333), accounts);
1218 env.
trust(USD_a(20000), carol);
1221 auto mixedPayments = [&]() ->
int {
1222 sendPayments(env, alice, carol, 1, 0);
1223 env(pay(alice, carol, USD_a(100)));
1231 request[jss::account_history_tx_stream][jss::account] =
1234 auto jv = ws->invoke(
"subscribe", request);
1238 getTxHash(*ws, tempVec, 100);
1241 auto count = mixedPayments();
1243 if (!BEAST_EXPECT(getTxHash(*ws, vec1, count).first))
1245 ws->invoke(
"unsubscribe", request);
1254 env.
fund(
XRP(444444), accounts);
1258 auto oneRound = [&](
int numPayments) {
1259 return sendPayments(env, alice, carol, numPayments, 300);
1265 request[jss::account_history_tx_stream][jss::account] =
1268 auto jv = wscLong->invoke(
"subscribe", request);
1272 getTxHash(*wscLong, tempVec, 100);
1276 for (
int kk = 2; kk < 10; ++kk)
1278 auto count = oneRound(kk);
1280 if (!BEAST_EXPECT(getTxHash(*wscLong, vec1, count).first))
1285 auto jv = wscShort->invoke(
"subscribe", request);
1287 if (!BEAST_EXPECT(getTxHash(*wscShort, vec2, count).first))
1289 if (!BEAST_EXPECT(hashCompare(vec1, vec2,
true)))
1291 wscShort->invoke(
"unsubscribe", request);
1299 using namespace test::jtx;