21#include <xrpl/beast/unit_test.h>
22#include <xrpl/protocol/ErrorCodes.h>
23#include <xrpl/protocol/TxFlags.h>
24#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);
256 auto const lines =
env.rpc(
259 R
"({"account": ")" + alice.human() +
262 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
264 lines[jss::result][jss::error_message] ==
269 auto const lines =
env.rpc(
272 R
"({"account": ")" + alice.human() +
276 lines[jss::result][jss::error_message] ==
281 auto const linesA =
env.rpc(
284 R
"({"account": ")" + alice.human() +
287 BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
288 BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
291 auto marker = linesA[jss::result][jss::marker].asString();
295 R
"({"account": ")" + alice.human() +
306 R
"({"account": ")" + alice.human() +
319 R
"({"account": ")" + alice.human() +
324 linesD[jss::result][jss::error_message] ==
329 auto const lines =
env.rpc(
332 R
"({"account": ")" + alice.human() +
334 R"("marker": true})");
336 lines[jss::result][jss::error_message] ==
341 auto const lines =
env.rpc(
344 R
"({"account": ")" + alice.human() +
348 gw2.human() + R"("})");
349 auto const&
line = lines[jss::result][jss::lines][0u];
357 auto const linesA =
env.rpc(
360 R
"({"account": ")" + gw2.human() +
364 alice.human() + R"("})");
365 auto const&
lineA = linesA[jss::result][jss::lines][0u];
372 BEAST_EXPECT(linesA[jss::result].isMember(jss::marker));
373 auto const marker = linesA[jss::result][jss::marker].asString();
377 R
"({"account": ")" + gw2.human() +
384 alice.human() + R"("})");
392 testAccountLinesMarker()
394 testcase(
"Entry pointed to by marker is not owned by account");
395 using namespace test::jtx;
404 Account
const alice{
"alice"};
405 Account
const becky{
"becky"};
406 Account
const gw1{
"gw1"};
411 Account
const bogie{
"bogie"};
415 auto const EUR =
gw1[
"EUR"];
427 R
"({"account": ")" + alice.human() +
431 aliceObjects[jss::result][jss::account_objects][0u];
432 if (!(aliceSignerList[sfLedgerEntryType.jsonName] == jss::SignerList))
435 "alice's account objects are misordered. "
436 "Please reorder the objects so the SignerList is first.",
444 auto const aliceLines1 =
env.rpc(
447 R
"({"account": ")" + alice.human() + R"(", "limit": 1})");
448 BEAST_EXPECT(aliceLines1[jss::result].isMember(jss::marker));
452 aliceLines1[jss::result][jss::marker].asString();
455 BEAST_EXPECT(markerIndex == aliceSignerList[jss::index].asString());
458 auto const aliceLines2 =
env.rpc(
461 R
"({"account": ")" + alice.human() + R"(", "marker": ")" +
462 aliceMarker + R"("})");
464 BEAST_EXPECT(!aliceLines2[jss::result].isMember(jss::marker));
468 auto const beckyLines =
env.rpc(
471 R
"({"account": ")" + becky.human() + R"(", "marker": ")" +
472 aliceMarker + R"("})");
473 BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message));
477 testAccountLineDelete()
479 testcase(
"Entry pointed to by marker is removed");
480 using namespace test::jtx;
494 Account
const alice{
"alice"};
495 Account
const becky{
"becky"};
496 Account
const cheri{
"cheri"};
497 Account
const gw1{
"gw1"};
498 Account
const gw2{
"gw2"};
502 auto const USD =
gw1[
"USD"];
503 auto const AUD =
gw1[
"AUD"];
504 auto const EUR =
gw2[
"EUR"];
524 auto const linesBeg =
env.rpc(
527 R
"({"account": ")" + alice.human() +
531 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
532 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
535 env(
pay(alice, cheri, EUR(100)));
540 auto const linesEnd =
env.rpc(
543 R
"({"account": ")" + alice.human() +
546 linesBeg[jss::result][jss::marker].asString() + R"("})");
548 linesEnd[jss::result][jss::error_message] ==
553 testAccountLinesWalkMarkers()
555 testcase(
"Marker can point to any appropriate ledger entry type");
556 using namespace test::jtx;
557 using namespace std::chrono_literals;
566 Account
const alice{
"alice"};
567 Account
const becky{
"becky"};
568 Account
const gw1{
"gw1"};
574 Account
const& account,
576 STAmount
const& amount) {
578 jv[jss::TransactionType] = jss::EscrowCreate;
580 jv[jss::Account] = account.human();
581 jv[jss::Destination] = to.human();
584 jv[sfFinishAfter.jsonName] =
finish.time_since_epoch().count();
588 auto payChan = [](Account
const& account,
590 STAmount
const& amount,
592 PublicKey
const& pk) {
594 jv[jss::TransactionType] = jss::PaymentChannelCreate;
596 jv[jss::Account] = account.human();
597 jv[jss::Destination] = to.human();
599 jv[
"SettleDelay"] = settleDelay.count();
600 jv[
"PublicKey"] =
strHex(pk.slice());
609 Account
const bogie{
"bogie"};
618 auto const EUR =
gw1[
"EUR"];
641 env(token::createOffer(alice, beckyNFtokenID,
drops(1)),
642 token::owner(becky));
643 env(token::createOffer(becky, aliceNFtokenID,
drops(1)),
644 token::owner(alice));
646 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
648 token::destination(alice));
649 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
651 token::destination(becky));
653 env(token::createOffer(
gw1, beckyNFtokenID,
drops(1)),
655 token::destination(alice));
656 env(token::createOffer(
gw1, aliceNFtokenID,
drops(1)),
658 token::destination(becky));
660 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
662 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
666 env(check::create(alice, becky,
XRP(50)));
667 env(check::create(becky, alice,
XRP(50)));
670 env(deposit::auth(alice, becky));
671 env(deposit::auth(becky, alice));
675 auto const USDalice = alice[
"USD"];
680 env(ticket::create(alice, 2));
683 auto const BTCbecky = becky[
"BTC"];
692 auto getNextLine = [](Env&
env,
693 Account
const& alice,
696 params[jss::account] = alice.human();
697 params[jss::limit] = 1;
699 params[jss::marker] = *
marker;
701 return env.rpc(
"json",
"account_lines",
to_string(params));
704 auto aliceLines = getNextLine(
env, alice, std::nullopt);
710 auto hasMarker = [](
auto const& aliceLines) {
711 return aliceLines[jss::result].isMember(jss::marker);
713 auto marker = [](
auto const& aliceLines) {
714 return aliceLines[jss::result][jss::marker].asString();
716 auto checkLines = [](
auto const& aliceLines) {
717 return aliceLines.isMember(jss::result) &&
718 !aliceLines[jss::result].isMember(jss::error_message) &&
719 aliceLines[jss::result].isMember(jss::lines) &&
720 aliceLines[jss::result][jss::lines].isArray() &&
721 aliceLines[jss::result][jss::lines].size() <= 1;
730 while (hasMarker(aliceLines))
733 aliceLines = getNextLine(
env, alice,
marker(aliceLines));
735 foundLines += aliceLines[jss::result][jss::lines].size();
743 R
"({"account": ")" + alice.human() +
748 !aliceObjects[jss::result].isMember(jss::error_message));
750 aliceObjects[jss::result].isMember(jss::account_objects));
752 aliceObjects[jss::result][jss::account_objects].isArray());
757 aliceObjects[jss::result][jss::account_objects].
size() ==
758 iterations + expectedNFTs);
768 R
"({"account": ")" + becky.human() +
773 !beckyObjects[jss::result].isMember(jss::error_message));
775 beckyObjects[jss::result].isMember(jss::account_objects));
777 beckyObjects[jss::result][jss::account_objects].isArray());
781 beckyObjects[jss::result][jss::account_objects].
size() ==
782 aliceObjects[jss::result][jss::account_objects].
size() - 2);
792 using namespace test::jtx;
796 auto const lines =
env.rpc(
799 R
"("method" : "account_lines",)"
800 R"("jsonrpc" : "2.0",)"
801 R"("ripplerpc" : "2.0")"
804 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
806 lines.isMember(jss::ripplerpc) &&
807 lines[jss::ripplerpc] ==
"2.0");
811 auto const lines =
env.rpc(
814 R
"("method" : "account_lines",)"
815 R"("jsonrpc" : "2.0",)"
816 R"("ripplerpc" : "2.0",)"
820 lines[jss::error][jss::message] ==
823 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
825 lines.isMember(jss::ripplerpc) &&
826 lines[jss::ripplerpc] ==
"2.0");
827 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
831 auto const lines =
env.rpc(
834 R
"("method" : "account_lines",)"
835 R"("jsonrpc" : "2.0",)"
836 R"("ripplerpc" : "2.0",)"
840 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
842 lines[jss::error][jss::message] ==
845 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
847 lines.isMember(jss::ripplerpc) &&
848 lines[jss::ripplerpc] ==
"2.0");
849 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
851 Account
const alice{
"alice"};
854 auto const lines =
env.rpc(
857 R
"("method" : "account_lines",)"
858 R"("jsonrpc" : "2.0",)"
859 R"("ripplerpc" : "2.0",)"
863 alice.human() + R"("}})");
865 lines[jss::error][jss::message] ==
868 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
870 lines.isMember(jss::ripplerpc) &&
871 lines[jss::ripplerpc] ==
"2.0");
874 env.fund(XRP(10000), alice);
881 auto const lines =
env.rpc(
884 R
"("method" : "account_lines",)"
885 R"("jsonrpc" : "2.0",)"
886 R"("ripplerpc" : "2.0",)"
890 alice.human() + R"("}})");
894 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
896 lines.isMember(jss::ripplerpc) &&
897 lines[jss::ripplerpc] ==
"2.0");
902 auto const lines =
env.rpc(
905 R
"("method" : "account_lines",)"
906 R"("jsonrpc" : "2.0",)"
907 R"("ripplerpc" : "2.0",)"
913 R"("ledger_index": "nonsense"}})");
915 lines[jss::error][jss::message] == "ledgerIndexMalformed");
917 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
919 lines.isMember(jss::ripplerpc) &&
920 lines[jss::ripplerpc] ==
"2.0");
925 auto const lines =
env.rpc(
928 R
"("method" : "account_lines",)"
929 R"("jsonrpc" : "2.0",)"
930 R"("ripplerpc" : "2.0",)"
936 R"("ledger_index": 50000}})");
939 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
941 lines.isMember(jss::ripplerpc) &&
942 lines[jss::ripplerpc] ==
"2.0");
950 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
958 env(trust(alice, gw1Currency(100 + c)));
959 env(pay(
gw1, alice, gw1Currency(50 + c)));
975 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
983 env(trust(alice, gw2Currency(200 + c)));
986 env(pay(
gw2, alice, gw2Currency(100 + c)));
1002 Account
const& account,
1006 auto const linesSeq =
env.rpc(
1009 R
"("method" : "account_lines",)"
1010 R"("jsonrpc" : "2.0",)"
1011 R"("ripplerpc" : "2.0",)"
1014 R"({"account": ")" +
1017 R"("ledger_index": )" +
1019 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
1020 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
1022 linesSeq.isMember(jss::jsonrpc) &&
1023 linesSeq[jss::jsonrpc] ==
"2.0");
1025 linesSeq.isMember(jss::ripplerpc) &&
1026 linesSeq[jss::ripplerpc] ==
"2.0");
1027 BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
1030 auto const linesHash =
env.rpc(
1033 R
"("method" : "account_lines",)"
1034 R"("jsonrpc" : "2.0",)"
1035 R"("ripplerpc" : "2.0",)"
1038 R"({"account": ")" +
1041 R"("ledger_hash": ")" +
1043 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
1044 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
1046 linesHash.isMember(jss::jsonrpc) &&
1047 linesHash[jss::jsonrpc] == "2.0");
1049 linesHash.isMember(jss::ripplerpc) &&
1050 linesHash[jss::ripplerpc] ==
"2.0");
1052 linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
1067 auto const lines =
env.rpc(
1070 R
"("method" : "account_lines",)"
1071 R"("jsonrpc" : "2.0",)"
1072 R"("ripplerpc" : "2.0",)"
1075 R"({"account": ")" +
1078 R"("ledger_hash": ")" +
1081 R"("ledger_index": )" +
1086 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1088 lines.isMember(jss::ripplerpc) &&
1089 lines[jss::ripplerpc] ==
"2.0");
1094 auto const lines =
env.rpc(
1097 R
"("method" : "account_lines",)"
1098 R"("jsonrpc" : "2.0",)"
1099 R"("ripplerpc" : "2.0",)"
1102 R"({"account": ")" +
1103 alice.human() + R"("}})");
1107 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1109 lines.isMember(jss::ripplerpc) &&
1110 lines[jss::ripplerpc] ==
"2.0");
1115 auto const lines =
env.rpc(
1118 R
"("method" : "account_lines",)"
1119 R"("jsonrpc" : "2.0",)"
1120 R"("ripplerpc" : "2.0",)"
1123 R"({"account": ")" +
1127 gw1.human() + R"("}})");
1131 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1133 lines.isMember(jss::ripplerpc) &&
1134 lines[jss::ripplerpc] ==
"2.0");
1139 auto const lines =
env.rpc(
1142 R
"("method" : "account_lines",)"
1143 R"("jsonrpc" : "2.0",)"
1144 R"("ripplerpc" : "2.0",)"
1147 R"({"account": ")" +
1151 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
1153 lines[jss::error][jss::message] ==
1156 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1158 lines.isMember(jss::ripplerpc) &&
1159 lines[jss::ripplerpc] ==
"2.0");
1164 auto const lines =
env.rpc(
1167 R
"("method" : "account_lines",)"
1168 R"("jsonrpc" : "2.0",)"
1169 R"("ripplerpc" : "2.0",)"
1172 R"({"account": ")" +
1175 R"("limit": -1}})");
1177 lines[jss::error][jss::message] ==
1180 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1182 lines.isMember(jss::ripplerpc) &&
1183 lines[jss::ripplerpc] ==
"2.0");
1188 auto const linesA =
env.rpc(
1191 R
"("method" : "account_lines",)"
1192 R"("jsonrpc" : "2.0",)"
1193 R"("ripplerpc" : "2.0",)"
1196 R"({"account": ")" +
1203 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
1205 linesA.isMember(jss::ripplerpc) &&
1206 linesA[jss::ripplerpc] ==
"2.0");
1210 auto marker = linesA[jss::result][jss::marker].asString();
1214 R
"("method" : "account_lines",)"
1215 R"("jsonrpc" : "2.0",)"
1216 R"("ripplerpc" : "2.0",)"
1219 R"({"account": ")" +
1227 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1229 linesB.isMember(jss::ripplerpc) &&
1230 linesB[jss::ripplerpc] ==
"2.0");
1237 R
"("method" : "account_lines",)"
1238 R"("jsonrpc" : "2.0",)"
1239 R"("ripplerpc" : "2.0",)"
1242 R"({"account": ")" +
1251 linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0");
1253 linesC.isMember(jss::ripplerpc) &&
1254 linesC[jss::ripplerpc] ==
"2.0");
1262 R
"("method" : "account_lines",)"
1263 R"("jsonrpc" : "2.0",)"
1264 R"("ripplerpc" : "2.0",)"
1267 R"({"account": ")" +
1273 linesD[jss::error][jss::message] ==
1276 linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0");
1278 linesD.isMember(jss::ripplerpc) &&
1279 linesD[jss::ripplerpc] ==
"2.0");
1284 auto const lines =
env.rpc(
1287 R
"("method" : "account_lines",)"
1288 R"("jsonrpc" : "2.0",)"
1289 R"("ripplerpc" : "2.0",)"
1292 R"({"account": ")" +
1295 R"("marker": true}})");
1297 lines[jss::error][jss::message] ==
1300 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1302 lines.isMember(jss::ripplerpc) &&
1303 lines[jss::ripplerpc] ==
"2.0");
1308 auto const lines =
env.rpc(
1311 R
"("method" : "account_lines",)"
1312 R"("jsonrpc" : "2.0",)"
1313 R"("ripplerpc" : "2.0",)"
1316 R"({"account": ")" +
1321 gw2.human() + R"("}})");
1322 auto const&
line = lines[jss::result][jss::lines][0u];
1328 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1330 lines.isMember(jss::ripplerpc) &&
1331 lines[jss::ripplerpc] ==
"2.0");
1336 auto const linesA =
env.rpc(
1339 R
"("method" : "account_lines",)"
1340 R"("jsonrpc" : "2.0",)"
1341 R"("ripplerpc" : "2.0",)"
1344 R"({"account": ")" +
1349 alice.human() + R"("}})");
1350 auto const&
lineA = linesA[jss::result][jss::lines][0u];
1356 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] ==
"2.0");
1358 linesA.isMember(jss::ripplerpc) &&
1359 linesA[jss::ripplerpc] ==
"2.0");
1364 auto const marker = linesA[jss::result][jss::marker].asString();
1368 R
"("method" : "account_lines",)"
1369 R"("jsonrpc" : "2.0",)"
1370 R"("ripplerpc" : "2.0",)"
1373 R"({"account": ")" +
1381 alice.human() + R"("}})");
1386 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1388 linesB.isMember(jss::ripplerpc) &&
1389 linesB[jss::ripplerpc] ==
"2.0");
1398 testcase(
"V2: account_lines with removed marker");
1400 using namespace test::jtx;
1414 Account
const alice{
"alice"};
1415 Account
const becky{
"becky"};
1416 Account
const cheri{
"cheri"};
1417 Account
const gw1{
"gw1"};
1418 Account
const gw2{
"gw2"};
1419 env.fund(XRP(10000), alice, becky, cheri,
gw1,
gw2);
1422 auto const USD =
gw1[
"USD"];
1423 auto const AUD =
gw1[
"AUD"];
1424 auto const EUR =
gw2[
"EUR"];
1425 env(trust(alice, USD(200)));
1426 env(trust(alice, AUD(200)));
1427 env(trust(becky, EUR(200)));
1428 env(trust(cheri, EUR(200)));
1432 env(pay(
gw2, becky, EUR(100)));
1436 env(offer(alice, EUR(100), XRP(100)));
1440 env(offer(becky, XRP(100), EUR(100)));
1444 auto const linesBeg =
env.rpc(
1447 R
"("method" : "account_lines",)"
1448 R"("jsonrpc" : "2.0",)"
1449 R"("ripplerpc" : "2.0",)"
1452 R"({"account": ")" +
1457 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
1458 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
1460 linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] ==
"2.0");
1462 linesBeg.isMember(jss::ripplerpc) &&
1463 linesBeg[jss::ripplerpc] ==
"2.0");
1464 BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5);
1467 env(pay(alice, cheri, EUR(100)));
1472 auto const linesEnd =
env.rpc(
1475 R
"("method" : "account_lines",)"
1476 R"("jsonrpc" : "2.0",)"
1477 R"("ripplerpc" : "2.0",)"
1480 R"({"account": ")" +
1484 linesBeg[jss::result][jss::marker].asString() + R"("}})");
1486 linesEnd[jss::error][jss::message] ==
1489 linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0");
1491 linesEnd.isMember(jss::ripplerpc) &&
1492 linesEnd[jss::ripplerpc] ==
"2.0");
1500 testAccountLinesMarker();
1501 testAccountLineDelete();
1502 testAccountLinesWalkMarkers();
1508BEAST_DEFINE_TESTSUITE(AccountLines, rpc,
ripple);
bool isMember(const char *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::time_point< NetClock > time_point
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 escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
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.
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
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
constexpr std::uint32_t tfUniversal
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