22#include <xrpl/beast/unit_test.h>
23#include <xrpl/protocol/ErrorCodes.h>
24#include <xrpl/protocol/TxFlags.h>
25#include <xrpl/protocol/jss.h>
38 using namespace test::jtx;
42 auto const lines =
env.rpc(
"json",
"account_lines",
"{ }");
44 lines[jss::result][jss::error_message] ==
49 auto const lines =
env.rpc(
53 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
55 lines[jss::result][jss::error_message] ==
60 auto testInvalidAccountParam = [&](
auto const& param) {
62 params[jss::account] = param;
64 "json",
"account_lines",
to_string(params))[jss::result];
67 jrr[jss::error_message] ==
"Invalid field 'account'.");
70 testInvalidAccountParam(1);
71 testInvalidAccountParam(1.1);
72 testInvalidAccountParam(
true);
77 Account
const alice{
"alice"};
80 auto const lines =
env.rpc(
83 R
"({"account": ")" + alice.human() + R"("})");
85 lines[jss::result][jss::error_message] ==
88 env.fund(XRP(10000), alice);
95 auto const lines =
env.rpc(
98 R
"({"account": ")" + alice.human() + R"("})");
100 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0);
104 auto const lines =
env.rpc(
107 R
"({"account": ")" + alice.human() +
109 R"("ledger_index": "nonsense"})");
111 lines[jss::result][jss::error_message] ==
112 "ledgerIndexMalformed");
116 auto const lines =
env.rpc(
119 R
"({"account": ")" + alice.human() +
121 R"("ledger_index": 50000})");
123 lines[jss::result][jss::error_message] == "ledgerNotFound");
126 Account
const gw1{
"gw1"};
127 env.fund(XRP(10000),
gw1);
130 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
138 env(trust(alice, gw1Currency(100 + c)));
139 env(pay(
gw1, alice, gw1Currency(50 + c)));
147 Account
const gw2{
"gw2"};
148 env.fund(XRP(10000),
gw2);
155 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
163 env(trust(alice, gw2Currency(200 + c)));
166 env(pay(
gw2, alice, gw2Currency(100 + c)));
182 Account
const& account,
186 auto const linesSeq =
env.rpc(
189 R
"({"account": ")" + account.human() +
191 R"("ledger_index": )" +
193 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
194 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
197 auto const linesHash =
env.rpc(
200 R
"({"account": ")" + account.human() +
202 R"("ledger_hash": ")" +
204 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
205 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
220 auto const lines =
env.rpc(
223 R
"({"account": ")" + alice.human() +
225 R"("ledger_hash": ")" +
228 R"("ledger_index": )" +
231 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
235 auto const lines =
env.rpc(
238 R
"({"account": ")" + alice.human() + R"("})");
240 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52);
244 auto const lines =
env.rpc(
247 R
"({"account": ")" + alice.human() +
250 gw1.human() + R"("})");
252 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
255 auto const&
line = lines[jss::result][jss::lines][0u];
260 auto const lines =
env.rpc(
263 R
"({"account": ")" + alice.human() +
266 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
268 lines[jss::result][jss::error_message] ==
273 auto const lines =
env.rpc(
276 R
"({"account": ")" + alice.human() +
280 lines[jss::result][jss::error_message] ==
285 auto const linesA =
env.rpc(
288 R
"({"account": ")" + alice.human() +
291 BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
292 BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
295 auto marker = linesA[jss::result][jss::marker].asString();
299 R
"({"account": ")" + alice.human() +
310 R
"({"account": ")" + alice.human() +
323 R
"({"account": ")" + alice.human() +
328 linesD[jss::result][jss::error_message] ==
333 auto const lines =
env.rpc(
336 R
"({"account": ")" + alice.human() +
338 R"("marker": true})");
340 lines[jss::result][jss::error_message] ==
345 auto const lines =
env.rpc(
348 R
"({"account": ")" + alice.human() +
352 gw2.human() + R"("})");
353 auto const&
line = lines[jss::result][jss::lines][0u];
361 auto const linesA =
env.rpc(
364 R
"({"account": ")" + gw2.human() +
368 alice.human() + R"("})");
369 auto const&
lineA = linesA[jss::result][jss::lines][0u];
376 BEAST_EXPECT(linesA[jss::result].isMember(jss::marker));
377 auto const marker = linesA[jss::result][jss::marker].asString();
381 R
"({"account": ")" + gw2.human() +
388 alice.human() + R"("})");
396 testAccountLinesMarker()
398 testcase(
"Entry pointed to by marker is not owned by account");
399 using namespace test::jtx;
408 Account
const alice{
"alice"};
409 Account
const becky{
"becky"};
410 Account
const gw1{
"gw1"};
415 Account
const bogie{
"bogie"};
419 auto const EUR =
gw1[
"EUR"];
431 R
"({"account": ")" + alice.human() +
435 aliceObjects[jss::result][jss::account_objects][0u];
436 if (!(aliceSignerList[sfLedgerEntryType.jsonName] == jss::SignerList))
439 "alice's account objects are misordered. "
440 "Please reorder the objects so the SignerList is first.",
448 auto const aliceLines1 =
env.rpc(
451 R
"({"account": ")" + alice.human() + R"(", "limit": 1})");
452 BEAST_EXPECT(aliceLines1[jss::result].isMember(jss::marker));
456 aliceLines1[jss::result][jss::marker].asString();
459 BEAST_EXPECT(markerIndex == aliceSignerList[jss::index].asString());
462 auto const aliceLines2 =
env.rpc(
465 R
"({"account": ")" + alice.human() + R"(", "marker": ")" +
466 aliceMarker + R"("})");
468 BEAST_EXPECT(!aliceLines2[jss::result].isMember(jss::marker));
472 auto const beckyLines =
env.rpc(
475 R
"({"account": ")" + becky.human() + R"(", "marker": ")" +
476 aliceMarker + R"("})");
477 BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message));
481 testAccountLineDelete()
483 testcase(
"Entry pointed to by marker is removed");
484 using namespace test::jtx;
498 Account
const alice{
"alice"};
499 Account
const becky{
"becky"};
500 Account
const cheri{
"cheri"};
501 Account
const gw1{
"gw1"};
502 Account
const gw2{
"gw2"};
506 auto const USD =
gw1[
"USD"];
507 auto const AUD =
gw1[
"AUD"];
508 auto const EUR =
gw2[
"EUR"];
528 auto const linesBeg =
env.rpc(
531 R
"({"account": ")" + alice.human() +
535 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
536 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
539 env(
pay(alice, cheri, EUR(100)));
544 auto const linesEnd =
env.rpc(
547 R
"({"account": ")" + alice.human() +
550 linesBeg[jss::result][jss::marker].asString() + R"("})");
552 linesEnd[jss::result][jss::error_message] ==
557 testAccountLinesWalkMarkers()
559 testcase(
"Marker can point to any appropriate ledger entry type");
560 using namespace test::jtx;
561 using namespace std::chrono_literals;
570 Account
const alice{
"alice"};
571 Account
const becky{
"becky"};
572 Account
const gw1{
"gw1"};
576 auto payChan = [](Account
const& account,
578 STAmount
const& amount,
580 PublicKey
const& pk) {
582 jv[jss::TransactionType] = jss::PaymentChannelCreate;
583 jv[jss::Account] = account.human();
584 jv[jss::Destination] = to.human();
586 jv[
"SettleDelay"] = settleDelay.count();
587 jv[
"PublicKey"] =
strHex(pk.slice());
596 Account
const bogie{
"bogie"};
605 auto const EUR =
gw1[
"EUR"];
611 env(escrow::create(alice, becky,
XRP(1000)),
612 escrow::finish_time(
env.now() + 1s));
613 env(escrow::create(becky, alice,
XRP(1000)),
614 escrow::finish_time(
env.now() + 1s));
630 env(token::createOffer(alice, beckyNFtokenID,
drops(1)),
631 token::owner(becky));
632 env(token::createOffer(becky, aliceNFtokenID,
drops(1)),
633 token::owner(alice));
635 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
637 token::destination(alice));
638 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
640 token::destination(becky));
642 env(token::createOffer(
gw1, beckyNFtokenID,
drops(1)),
644 token::destination(alice));
645 env(token::createOffer(
gw1, aliceNFtokenID,
drops(1)),
647 token::destination(becky));
649 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
651 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
655 env(check::create(alice, becky,
XRP(50)));
656 env(check::create(becky, alice,
XRP(50)));
659 env(deposit::auth(alice, becky));
660 env(deposit::auth(becky, alice));
664 auto const USDalice = alice[
"USD"];
669 env(ticket::create(alice, 2));
672 auto const BTCbecky = becky[
"BTC"];
681 auto getNextLine = [](Env&
env,
682 Account
const& alice,
685 params[jss::account] = alice.human();
686 params[jss::limit] = 1;
688 params[jss::marker] = *
marker;
690 return env.rpc(
"json",
"account_lines",
to_string(params));
693 auto aliceLines = getNextLine(
env, alice, std::nullopt);
699 auto hasMarker = [](
auto const& aliceLines) {
700 return aliceLines[jss::result].isMember(jss::marker);
702 auto marker = [](
auto const& aliceLines) {
703 return aliceLines[jss::result][jss::marker].asString();
705 auto checkLines = [](
auto const& aliceLines) {
706 return aliceLines.isMember(jss::result) &&
707 !aliceLines[jss::result].isMember(jss::error_message) &&
708 aliceLines[jss::result].isMember(jss::lines) &&
709 aliceLines[jss::result][jss::lines].isArray() &&
710 aliceLines[jss::result][jss::lines].size() <= 1;
719 while (hasMarker(aliceLines))
722 aliceLines = getNextLine(
env, alice,
marker(aliceLines));
724 foundLines += aliceLines[jss::result][jss::lines].size();
732 R
"({"account": ")" + alice.human() +
737 !aliceObjects[jss::result].isMember(jss::error_message));
739 aliceObjects[jss::result].isMember(jss::account_objects));
741 aliceObjects[jss::result][jss::account_objects].isArray());
746 aliceObjects[jss::result][jss::account_objects].
size() ==
747 iterations + expectedNFTs);
757 R
"({"account": ")" + becky.human() +
762 !beckyObjects[jss::result].isMember(jss::error_message));
764 beckyObjects[jss::result].isMember(jss::account_objects));
766 beckyObjects[jss::result][jss::account_objects].isArray());
770 beckyObjects[jss::result][jss::account_objects].
size() ==
771 aliceObjects[jss::result][jss::account_objects].
size() - 2);
781 using namespace test::jtx;
785 auto const lines =
env.rpc(
788 R
"("method" : "account_lines",)"
789 R"("jsonrpc" : "2.0",)"
790 R"("ripplerpc" : "2.0")"
793 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
795 lines.isMember(jss::ripplerpc) &&
796 lines[jss::ripplerpc] ==
"2.0");
800 auto const lines =
env.rpc(
803 R
"("method" : "account_lines",)"
804 R"("jsonrpc" : "2.0",)"
805 R"("ripplerpc" : "2.0",)"
809 lines[jss::error][jss::message] ==
812 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
814 lines.isMember(jss::ripplerpc) &&
815 lines[jss::ripplerpc] ==
"2.0");
816 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
820 auto const lines =
env.rpc(
823 R
"("method" : "account_lines",)"
824 R"("jsonrpc" : "2.0",)"
825 R"("ripplerpc" : "2.0",)"
829 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
831 lines[jss::error][jss::message] ==
834 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
836 lines.isMember(jss::ripplerpc) &&
837 lines[jss::ripplerpc] ==
"2.0");
838 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
840 Account
const alice{
"alice"};
843 auto const lines =
env.rpc(
846 R
"("method" : "account_lines",)"
847 R"("jsonrpc" : "2.0",)"
848 R"("ripplerpc" : "2.0",)"
852 alice.human() + R"("}})");
854 lines[jss::error][jss::message] ==
857 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
859 lines.isMember(jss::ripplerpc) &&
860 lines[jss::ripplerpc] ==
"2.0");
863 env.fund(XRP(10000), alice);
870 auto const lines =
env.rpc(
873 R
"("method" : "account_lines",)"
874 R"("jsonrpc" : "2.0",)"
875 R"("ripplerpc" : "2.0",)"
879 alice.human() + R"("}})");
883 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
885 lines.isMember(jss::ripplerpc) &&
886 lines[jss::ripplerpc] ==
"2.0");
891 auto const lines =
env.rpc(
894 R
"("method" : "account_lines",)"
895 R"("jsonrpc" : "2.0",)"
896 R"("ripplerpc" : "2.0",)"
902 R"("ledger_index": "nonsense"}})");
904 lines[jss::error][jss::message] == "ledgerIndexMalformed");
906 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
908 lines.isMember(jss::ripplerpc) &&
909 lines[jss::ripplerpc] ==
"2.0");
914 auto const lines =
env.rpc(
917 R
"("method" : "account_lines",)"
918 R"("jsonrpc" : "2.0",)"
919 R"("ripplerpc" : "2.0",)"
925 R"("ledger_index": 50000}})");
928 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
930 lines.isMember(jss::ripplerpc) &&
931 lines[jss::ripplerpc] ==
"2.0");
939 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
947 env(trust(alice, gw1Currency(100 + c)));
948 env(pay(
gw1, alice, gw1Currency(50 + c)));
964 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
972 env(trust(alice, gw2Currency(200 + c)));
975 env(pay(
gw2, alice, gw2Currency(100 + c)));
991 Account
const& account,
995 auto const linesSeq =
env.rpc(
998 R
"("method" : "account_lines",)"
999 R"("jsonrpc" : "2.0",)"
1000 R"("ripplerpc" : "2.0",)"
1003 R"({"account": ")" +
1006 R"("ledger_index": )" +
1008 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
1009 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
1011 linesSeq.isMember(jss::jsonrpc) &&
1012 linesSeq[jss::jsonrpc] ==
"2.0");
1014 linesSeq.isMember(jss::ripplerpc) &&
1015 linesSeq[jss::ripplerpc] ==
"2.0");
1016 BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
1019 auto const linesHash =
env.rpc(
1022 R
"("method" : "account_lines",)"
1023 R"("jsonrpc" : "2.0",)"
1024 R"("ripplerpc" : "2.0",)"
1027 R"({"account": ")" +
1030 R"("ledger_hash": ")" +
1032 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
1033 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
1035 linesHash.isMember(jss::jsonrpc) &&
1036 linesHash[jss::jsonrpc] == "2.0");
1038 linesHash.isMember(jss::ripplerpc) &&
1039 linesHash[jss::ripplerpc] ==
"2.0");
1041 linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
1056 auto const lines =
env.rpc(
1059 R
"("method" : "account_lines",)"
1060 R"("jsonrpc" : "2.0",)"
1061 R"("ripplerpc" : "2.0",)"
1064 R"({"account": ")" +
1067 R"("ledger_hash": ")" +
1070 R"("ledger_index": )" +
1075 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1077 lines.isMember(jss::ripplerpc) &&
1078 lines[jss::ripplerpc] ==
"2.0");
1083 auto const lines =
env.rpc(
1086 R
"("method" : "account_lines",)"
1087 R"("jsonrpc" : "2.0",)"
1088 R"("ripplerpc" : "2.0",)"
1091 R"({"account": ")" +
1092 alice.human() + R"("}})");
1096 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1098 lines.isMember(jss::ripplerpc) &&
1099 lines[jss::ripplerpc] ==
"2.0");
1104 auto const lines =
env.rpc(
1107 R
"("method" : "account_lines",)"
1108 R"("jsonrpc" : "2.0",)"
1109 R"("ripplerpc" : "2.0",)"
1112 R"({"account": ")" +
1116 gw1.human() + R"("}})");
1120 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1122 lines.isMember(jss::ripplerpc) &&
1123 lines[jss::ripplerpc] ==
"2.0");
1128 auto const lines =
env.rpc(
1131 R
"("method" : "account_lines",)"
1132 R"("jsonrpc" : "2.0",)"
1133 R"("ripplerpc" : "2.0",)"
1136 R"({"account": ")" +
1140 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
1142 lines[jss::error][jss::message] ==
1145 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1147 lines.isMember(jss::ripplerpc) &&
1148 lines[jss::ripplerpc] ==
"2.0");
1153 auto const lines =
env.rpc(
1156 R
"("method" : "account_lines",)"
1157 R"("jsonrpc" : "2.0",)"
1158 R"("ripplerpc" : "2.0",)"
1161 R"({"account": ")" +
1164 R"("limit": -1}})");
1166 lines[jss::error][jss::message] ==
1169 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1171 lines.isMember(jss::ripplerpc) &&
1172 lines[jss::ripplerpc] ==
"2.0");
1177 auto const linesA =
env.rpc(
1180 R
"("method" : "account_lines",)"
1181 R"("jsonrpc" : "2.0",)"
1182 R"("ripplerpc" : "2.0",)"
1185 R"({"account": ")" +
1192 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
1194 linesA.isMember(jss::ripplerpc) &&
1195 linesA[jss::ripplerpc] ==
"2.0");
1199 auto marker = linesA[jss::result][jss::marker].asString();
1203 R
"("method" : "account_lines",)"
1204 R"("jsonrpc" : "2.0",)"
1205 R"("ripplerpc" : "2.0",)"
1208 R"({"account": ")" +
1216 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1218 linesB.isMember(jss::ripplerpc) &&
1219 linesB[jss::ripplerpc] ==
"2.0");
1226 R
"("method" : "account_lines",)"
1227 R"("jsonrpc" : "2.0",)"
1228 R"("ripplerpc" : "2.0",)"
1231 R"({"account": ")" +
1240 linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0");
1242 linesC.isMember(jss::ripplerpc) &&
1243 linesC[jss::ripplerpc] ==
"2.0");
1251 R
"("method" : "account_lines",)"
1252 R"("jsonrpc" : "2.0",)"
1253 R"("ripplerpc" : "2.0",)"
1256 R"({"account": ")" +
1262 linesD[jss::error][jss::message] ==
1265 linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0");
1267 linesD.isMember(jss::ripplerpc) &&
1268 linesD[jss::ripplerpc] ==
"2.0");
1273 auto const lines =
env.rpc(
1276 R
"("method" : "account_lines",)"
1277 R"("jsonrpc" : "2.0",)"
1278 R"("ripplerpc" : "2.0",)"
1281 R"({"account": ")" +
1284 R"("marker": true}})");
1286 lines[jss::error][jss::message] ==
1289 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1291 lines.isMember(jss::ripplerpc) &&
1292 lines[jss::ripplerpc] ==
"2.0");
1297 auto const lines =
env.rpc(
1300 R
"("method" : "account_lines",)"
1301 R"("jsonrpc" : "2.0",)"
1302 R"("ripplerpc" : "2.0",)"
1305 R"({"account": ")" +
1310 gw2.human() + R"("}})");
1311 auto const&
line = lines[jss::result][jss::lines][0u];
1317 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1319 lines.isMember(jss::ripplerpc) &&
1320 lines[jss::ripplerpc] ==
"2.0");
1325 auto const linesA =
env.rpc(
1328 R
"("method" : "account_lines",)"
1329 R"("jsonrpc" : "2.0",)"
1330 R"("ripplerpc" : "2.0",)"
1333 R"({"account": ")" +
1338 alice.human() + R"("}})");
1339 auto const&
lineA = linesA[jss::result][jss::lines][0u];
1345 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] ==
"2.0");
1347 linesA.isMember(jss::ripplerpc) &&
1348 linesA[jss::ripplerpc] ==
"2.0");
1353 auto const marker = linesA[jss::result][jss::marker].asString();
1357 R
"("method" : "account_lines",)"
1358 R"("jsonrpc" : "2.0",)"
1359 R"("ripplerpc" : "2.0",)"
1362 R"({"account": ")" +
1370 alice.human() + R"("}})");
1375 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1377 linesB.isMember(jss::ripplerpc) &&
1378 linesB[jss::ripplerpc] ==
"2.0");
1387 testcase(
"V2: account_lines with removed marker");
1389 using namespace test::jtx;
1403 Account
const alice{
"alice"};
1404 Account
const becky{
"becky"};
1405 Account
const cheri{
"cheri"};
1406 Account
const gw1{
"gw1"};
1407 Account
const gw2{
"gw2"};
1408 env.fund(XRP(10000), alice, becky, cheri,
gw1,
gw2);
1411 auto const USD =
gw1[
"USD"];
1412 auto const AUD =
gw1[
"AUD"];
1413 auto const EUR =
gw2[
"EUR"];
1414 env(trust(alice, USD(200)));
1415 env(trust(alice, AUD(200)));
1416 env(trust(becky, EUR(200)));
1417 env(trust(cheri, EUR(200)));
1421 env(pay(
gw2, becky, EUR(100)));
1425 env(offer(alice, EUR(100), XRP(100)));
1429 env(offer(becky, XRP(100), EUR(100)));
1433 auto const linesBeg =
env.rpc(
1436 R
"("method" : "account_lines",)"
1437 R"("jsonrpc" : "2.0",)"
1438 R"("ripplerpc" : "2.0",)"
1441 R"({"account": ")" +
1446 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
1447 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
1449 linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] ==
"2.0");
1451 linesBeg.isMember(jss::ripplerpc) &&
1452 linesBeg[jss::ripplerpc] ==
"2.0");
1453 BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5);
1456 env(pay(alice, cheri, EUR(100)));
1461 auto const linesEnd =
env.rpc(
1464 R
"("method" : "account_lines",)"
1465 R"("jsonrpc" : "2.0",)"
1466 R"("ripplerpc" : "2.0",)"
1469 R"({"account": ")" +
1473 linesBeg[jss::result][jss::marker].asString() + R"("}})");
1475 linesEnd[jss::error][jss::message] ==
1478 linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0");
1480 linesEnd.isMember(jss::ripplerpc) &&
1481 linesEnd[jss::ripplerpc] ==
"2.0");
1489 testAccountLinesMarker();
1490 testAccountLineDelete();
1491 testAccountLinesWalkMarkers();
1497BEAST_DEFINE_TESTSUITE(AccountLines, rpc,
ripple);
bool isMember(char const *key) const
Return true if the object has a member named key.
testcase_t testcase
Memberspace for declaring test cases.
void fail(String const &reason, char const *file, int line)
Record a failure.
std::chrono::duration< rep, period > duration
BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool()==true)
BEAST_EXPECT(linesB[jss::result][jss::lines].isArray())
BEAST_EXPECT(ledger3Info.seq==3)
BEAST_EXPECT(linesEnd.isMember(jss::ripplerpc) &&linesEnd[jss::ripplerpc]=="2.0")
BEAST_EXPECT(line[jss::peer_authorized].asBool()==true)
BEAST_EXPECT(linesD.isMember(jss::id) &&linesD[jss::id]==5)
BEAST_EXPECT(line[jss::no_ripple].asBool()==true)
BEAST_EXPECT(linesD[jss::error][jss::message]==RPC::make_error(rpcINVALID_PARAMS)[jss::error_message])
testAccountLinesHistory(alice, ledger4Info, 26)
auto testAccountLinesHistory
BEAST_EXPECT(linesB.isMember(jss::ripplerpc) &&linesB[jss::ripplerpc]=="2.0")
BEAST_EXPECT(linesC.isMember(jss::jsonrpc) &&linesC[jss::jsonrpc]=="2.0")
void testAccountLineDelete2()
BEAST_EXPECT(ledger4Info.seq==4)
BEAST_EXPECT(lines[jss::result][jss::lines].size()==26)
BEAST_EXPECT(linesA.isMember(jss::ripplerpc) &&linesA[jss::ripplerpc]=="2.0")
BEAST_EXPECT(linesB.isMember(jss::jsonrpc) &&linesB[jss::jsonrpc]=="2.0")
BEAST_EXPECT(linesD.isMember(jss::ripplerpc) &&linesD[jss::ripplerpc]=="2.0")
LedgerInfo const ledger3Info
BEAST_EXPECT(lineA[jss::no_ripple_peer].asBool()==true)
BEAST_EXPECT(lineA[jss::freeze_peer].asBool()==true)
BEAST_EXPECT(linesC[jss::result][jss::lines].size()==3)
BEAST_EXPECT(linesC.isMember(jss::ripplerpc) &&linesC[jss::ripplerpc]=="2.0")
BEAST_EXPECT(linesC[jss::result][jss::lines].isArray())
BEAST_EXPECT(ledger58Info.seq==58)
BEAST_EXPECT(linesA[jss::result].isMember(jss::marker))
BEAST_EXPECT(linesEnd[jss::error][jss::message]==RPC::make_error(rpcINVALID_PARAMS)[jss::error_message])
env(fset(gw2, asfRequireAuth))
LedgerInfo const ledger4Info
std::vector< IOU > gw1Currencies
BEAST_EXPECT(lines[jss::result][jss::lines].size()==0)
BEAST_EXPECT(lines.isMember(jss::id) &&lines[jss::id]==5)
BEAST_EXPECT(lines[jss::error][jss::message]=="ledgerIndexMalformed")
BEAST_EXPECT(lines.isMember(jss::jsonrpc) &&lines[jss::jsonrpc]=="2.0")
BEAST_EXPECT(linesA[jss::result][jss::lines].isArray())
BEAST_EXPECT(lines[jss::error][jss::message]==RPC::expected_field_message(jss::limit, "unsigned integer"))
BEAST_EXPECT(lines.isMember(jss::ripplerpc) &&lines[jss::ripplerpc]=="2.0")
BEAST_EXPECT(linesB.isMember(jss::id) &&linesB[jss::id]==5)
BEAST_EXPECT(linesB[jss::result][jss::lines].size()==25)
BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker))
LedgerInfo const ledger58Info
BEAST_EXPECT(linesC.isMember(jss::id) &&linesC[jss::id]==5)
testAccountLinesHistory(alice, ledger58Info, 52)
BEAST_EXPECT(linesD.isMember(jss::jsonrpc) &&linesD[jss::jsonrpc]=="2.0")
BEAST_EXPECT(lines[jss::result][jss::lines].isArray())
BEAST_EXPECT(linesEnd.isMember(jss::id) &&linesEnd[jss::id]==5)
BEAST_EXPECT(linesB[jss::result][jss::lines].size()==51)
BEAST_EXPECT(lines[jss::error][jss::message]==RPC::expected_field_message(jss::marker, "string"))
BEAST_EXPECT(linesEnd.isMember(jss::jsonrpc) &&linesEnd[jss::jsonrpc]=="2.0")
BEAST_EXPECT(linesA.isMember(jss::id) &&linesA[jss::id]==5)
void run() override
Runs the suite.
BEAST_EXPECT(lines[jss::error][jss::message]=="ledgerNotFound")
BEAST_EXPECT(lineA[jss::authorized].asBool()==true)
BEAST_EXPECT(lines[jss::error][jss::message]==RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message])
BEAST_EXPECT(lines[jss::result][jss::lines].size()==52)
BEAST_EXPECT(linesA.isMember(jss::jsonrpc) &&linesA[jss::jsonrpc]=="2.0")
BEAST_EXPECT(line[jss::deep_freeze].asBool()==true)
testAccountLinesHistory(alice, ledger3Info, 0)
BEAST_EXPECT(lines[jss::error][jss::message]==RPC::make_error(rpcACT_MALFORMED)[jss::error_message])
std::vector< IOU > gw2Currencies
BEAST_EXPECT(line[jss::freeze].asBool()==true)
BEAST_EXPECT(linesA[jss::result][jss::lines].size()==1)
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
std::string expected_field_message(std::string const &name, std::string const &type)
Json::Value missing_field_error(std::string const &name)
Keylet signers(AccountID const &account) noexcept
A SignerList.
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Json::Value trust(AccountID const &account, STAmount const &amount, std::uint32_t flags=0)
Json::Value pay(Account const &account, AccountID const &to, STAmount const &amount)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
XRP_t const XRP
Converts to XRP Issue or STAmount.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t tfSetDeepFreeze
constexpr std::uint32_t const tfSellNFToken
std::string strHex(FwdIt begin, FwdIt end)
constexpr std::uint32_t tfSetfAuth
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t asfRequireAuth
constexpr std::uint32_t tfSetFreeze
constexpr std::uint32_t tfSetNoRipple
constexpr std::uint32_t const tfTransferable