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>
37 using namespace test::jtx;
41 auto const lines =
env.rpc(
"json",
"account_lines",
"{ }");
43 lines[jss::result][jss::error_message] ==
48 auto const lines =
env.rpc(
52 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
54 lines[jss::result][jss::error_message] ==
59 auto testInvalidAccountParam = [&](
auto const& param) {
61 params[jss::account] = param;
63 "json",
"account_lines",
to_string(params))[jss::result];
66 jrr[jss::error_message] ==
"Invalid field 'account'.");
69 testInvalidAccountParam(1);
70 testInvalidAccountParam(1.1);
71 testInvalidAccountParam(
true);
76 Account
const alice{
"alice"};
79 auto const lines =
env.rpc(
82 R
"({"account": ")" + alice.human() + R"("})");
84 lines[jss::result][jss::error_message] ==
87 env.fund(XRP(10000), alice);
94 auto const lines =
env.rpc(
97 R
"({"account": ")" + alice.human() + R"("})");
99 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0);
103 auto const lines =
env.rpc(
106 R
"({"account": ")" + alice.human() +
108 R"("ledger_index": "nonsense"})");
110 lines[jss::result][jss::error_message] ==
111 "ledgerIndexMalformed");
115 auto const lines =
env.rpc(
118 R
"({"account": ")" + alice.human() +
120 R"("ledger_index": 50000})");
122 lines[jss::result][jss::error_message] == "ledgerNotFound");
125 Account
const gw1{
"gw1"};
126 env.fund(XRP(10000),
gw1);
129 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
137 env(trust(alice, gw1Currency(100 + c)));
138 env(pay(
gw1, alice, gw1Currency(50 + c)));
146 Account
const gw2{
"gw2"};
147 env.fund(XRP(10000),
gw2);
154 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
162 env(trust(alice, gw2Currency(200 + c)));
165 env(pay(
gw2, alice, gw2Currency(100 + c)));
181 Account
const& account,
185 auto const linesSeq =
env.rpc(
188 R
"({"account": ")" + account.human() +
190 R"("ledger_index": )" +
192 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
193 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
196 auto const linesHash =
env.rpc(
199 R
"({"account": ")" + account.human() +
201 R"("ledger_hash": ")" +
203 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
204 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
219 auto const lines =
env.rpc(
222 R
"({"account": ")" + alice.human() +
224 R"("ledger_hash": ")" +
227 R"("ledger_index": )" +
230 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
234 auto const lines =
env.rpc(
237 R
"({"account": ")" + alice.human() + R"("})");
239 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52);
243 auto const lines =
env.rpc(
246 R
"({"account": ")" + alice.human() +
249 gw1.human() + R"("})");
251 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
255 auto const lines =
env.rpc(
258 R
"({"account": ")" + alice.human() +
261 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
263 lines[jss::result][jss::error_message] ==
268 auto const lines =
env.rpc(
271 R
"({"account": ")" + alice.human() +
275 lines[jss::result][jss::error_message] ==
280 auto const linesA =
env.rpc(
283 R
"({"account": ")" + alice.human() +
286 BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
287 BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
290 auto marker = linesA[jss::result][jss::marker].asString();
294 R
"({"account": ")" + alice.human() +
305 R
"({"account": ")" + alice.human() +
318 R
"({"account": ")" + alice.human() +
323 linesD[jss::result][jss::error_message] ==
328 auto const lines =
env.rpc(
331 R
"({"account": ")" + alice.human() +
333 R"("marker": true})");
335 lines[jss::result][jss::error_message] ==
340 auto const lines =
env.rpc(
343 R
"({"account": ")" + alice.human() +
347 gw2.human() + R"("})");
348 auto const&
line = lines[jss::result][jss::lines][0u];
356 auto const linesA =
env.rpc(
359 R
"({"account": ")" + gw2.human() +
363 alice.human() + R"("})");
364 auto const&
lineA = linesA[jss::result][jss::lines][0u];
371 BEAST_EXPECT(linesA[jss::result].isMember(jss::marker));
372 auto const marker = linesA[jss::result][jss::marker].asString();
376 R
"({"account": ")" + gw2.human() +
383 alice.human() + R"("})");
391 testAccountLinesMarker()
393 testcase(
"Entry pointed to by marker is not owned by account");
394 using namespace test::jtx;
403 Account
const alice{
"alice"};
404 Account
const becky{
"becky"};
405 Account
const gw1{
"gw1"};
410 Account
const bogie{
"bogie"};
414 auto const EUR =
gw1[
"EUR"];
426 R
"({"account": ")" + alice.human() +
430 aliceObjects[jss::result][jss::account_objects][0u];
431 if (!(aliceSignerList[sfLedgerEntryType.jsonName] == jss::SignerList))
434 "alice's account objects are misordered. "
435 "Please reorder the objects so the SignerList is first.",
443 auto const aliceLines1 =
env.rpc(
446 R
"({"account": ")" + alice.human() + R"(", "limit": 1})");
447 BEAST_EXPECT(aliceLines1[jss::result].isMember(jss::marker));
451 aliceLines1[jss::result][jss::marker].asString();
454 BEAST_EXPECT(markerIndex == aliceSignerList[jss::index].asString());
457 auto const aliceLines2 =
env.rpc(
460 R
"({"account": ")" + alice.human() + R"(", "marker": ")" +
461 aliceMarker + R"("})");
463 BEAST_EXPECT(!aliceLines2[jss::result].isMember(jss::marker));
467 auto const beckyLines =
env.rpc(
470 R
"({"account": ")" + becky.human() + R"(", "marker": ")" +
471 aliceMarker + R"("})");
472 BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message));
476 testAccountLineDelete()
478 testcase(
"Entry pointed to by marker is removed");
479 using namespace test::jtx;
493 Account
const alice{
"alice"};
494 Account
const becky{
"becky"};
495 Account
const cheri{
"cheri"};
496 Account
const gw1{
"gw1"};
497 Account
const gw2{
"gw2"};
501 auto const USD =
gw1[
"USD"];
502 auto const AUD =
gw1[
"AUD"];
503 auto const EUR =
gw2[
"EUR"];
523 auto const linesBeg =
env.rpc(
526 R
"({"account": ")" + alice.human() +
530 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
531 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
534 env(
pay(alice, cheri, EUR(100)));
539 auto const linesEnd =
env.rpc(
542 R
"({"account": ")" + alice.human() +
545 linesBeg[jss::result][jss::marker].asString() + R"("})");
547 linesEnd[jss::result][jss::error_message] ==
552 testAccountLinesWalkMarkers()
554 testcase(
"Marker can point to any appropriate ledger entry type");
555 using namespace test::jtx;
556 using namespace std::chrono_literals;
565 Account
const alice{
"alice"};
566 Account
const becky{
"becky"};
567 Account
const gw1{
"gw1"};
573 Account
const& account,
575 STAmount
const& amount) {
577 jv[jss::TransactionType] = jss::EscrowCreate;
579 jv[jss::Account] = account.human();
580 jv[jss::Destination] = to.human();
583 jv[sfFinishAfter.jsonName] =
finish.time_since_epoch().count();
587 auto payChan = [](Account
const& account,
589 STAmount
const& amount,
591 PublicKey
const& pk) {
593 jv[jss::TransactionType] = jss::PaymentChannelCreate;
595 jv[jss::Account] = account.human();
596 jv[jss::Destination] = to.human();
598 jv[
"SettleDelay"] = settleDelay.count();
599 jv[
"PublicKey"] =
strHex(pk.slice());
608 Account
const bogie{
"bogie"};
617 auto const EUR =
gw1[
"EUR"];
640 env(token::createOffer(alice, beckyNFtokenID,
drops(1)),
641 token::owner(becky));
642 env(token::createOffer(becky, aliceNFtokenID,
drops(1)),
643 token::owner(alice));
645 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
647 token::destination(alice));
648 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
650 token::destination(becky));
652 env(token::createOffer(
gw1, beckyNFtokenID,
drops(1)),
654 token::destination(alice));
655 env(token::createOffer(
gw1, aliceNFtokenID,
drops(1)),
657 token::destination(becky));
659 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
661 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
665 env(check::create(alice, becky,
XRP(50)));
666 env(check::create(becky, alice,
XRP(50)));
669 env(deposit::auth(alice, becky));
670 env(deposit::auth(becky, alice));
674 auto const USDalice = alice[
"USD"];
679 env(ticket::create(alice, 2));
682 auto const BTCbecky = becky[
"BTC"];
691 auto getNextLine = [](Env&
env,
692 Account
const& alice,
695 params[jss::account] = alice.human();
696 params[jss::limit] = 1;
698 params[jss::marker] = *
marker;
700 return env.rpc(
"json",
"account_lines",
to_string(params));
703 auto aliceLines = getNextLine(
env, alice, std::nullopt);
709 auto hasMarker = [](
auto const& aliceLines) {
710 return aliceLines[jss::result].isMember(jss::marker);
712 auto marker = [](
auto const& aliceLines) {
713 return aliceLines[jss::result][jss::marker].asString();
715 auto checkLines = [](
auto const& aliceLines) {
716 return aliceLines.isMember(jss::result) &&
717 !aliceLines[jss::result].isMember(jss::error_message) &&
718 aliceLines[jss::result].isMember(jss::lines) &&
719 aliceLines[jss::result][jss::lines].isArray() &&
720 aliceLines[jss::result][jss::lines].size() <= 1;
729 while (hasMarker(aliceLines))
732 aliceLines = getNextLine(
env, alice,
marker(aliceLines));
734 foundLines += aliceLines[jss::result][jss::lines].size();
742 R
"({"account": ")" + alice.human() +
747 !aliceObjects[jss::result].isMember(jss::error_message));
749 aliceObjects[jss::result].isMember(jss::account_objects));
751 aliceObjects[jss::result][jss::account_objects].isArray());
756 aliceObjects[jss::result][jss::account_objects].
size() ==
757 iterations + expectedNFTs);
767 R
"({"account": ")" + becky.human() +
772 !beckyObjects[jss::result].isMember(jss::error_message));
774 beckyObjects[jss::result].isMember(jss::account_objects));
776 beckyObjects[jss::result][jss::account_objects].isArray());
780 beckyObjects[jss::result][jss::account_objects].
size() ==
781 aliceObjects[jss::result][jss::account_objects].
size() - 2);
791 using namespace test::jtx;
795 auto const lines =
env.rpc(
798 R
"("method" : "account_lines",)"
799 R"("jsonrpc" : "2.0",)"
800 R"("ripplerpc" : "2.0")"
803 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
805 lines.isMember(jss::ripplerpc) &&
806 lines[jss::ripplerpc] ==
"2.0");
810 auto const lines =
env.rpc(
813 R
"("method" : "account_lines",)"
814 R"("jsonrpc" : "2.0",)"
815 R"("ripplerpc" : "2.0",)"
819 lines[jss::error][jss::message] ==
822 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
824 lines.isMember(jss::ripplerpc) &&
825 lines[jss::ripplerpc] ==
"2.0");
826 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
830 auto const lines =
env.rpc(
833 R
"("method" : "account_lines",)"
834 R"("jsonrpc" : "2.0",)"
835 R"("ripplerpc" : "2.0",)"
839 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
841 lines[jss::error][jss::message] ==
844 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
846 lines.isMember(jss::ripplerpc) &&
847 lines[jss::ripplerpc] ==
"2.0");
848 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
850 Account
const alice{
"alice"};
853 auto const lines =
env.rpc(
856 R
"("method" : "account_lines",)"
857 R"("jsonrpc" : "2.0",)"
858 R"("ripplerpc" : "2.0",)"
862 alice.human() + R"("}})");
864 lines[jss::error][jss::message] ==
867 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
869 lines.isMember(jss::ripplerpc) &&
870 lines[jss::ripplerpc] ==
"2.0");
873 env.fund(XRP(10000), alice);
880 auto const lines =
env.rpc(
883 R
"("method" : "account_lines",)"
884 R"("jsonrpc" : "2.0",)"
885 R"("ripplerpc" : "2.0",)"
889 alice.human() + R"("}})");
893 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
895 lines.isMember(jss::ripplerpc) &&
896 lines[jss::ripplerpc] ==
"2.0");
901 auto const lines =
env.rpc(
904 R
"("method" : "account_lines",)"
905 R"("jsonrpc" : "2.0",)"
906 R"("ripplerpc" : "2.0",)"
912 R"("ledger_index": "nonsense"}})");
914 lines[jss::error][jss::message] == "ledgerIndexMalformed");
916 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
918 lines.isMember(jss::ripplerpc) &&
919 lines[jss::ripplerpc] ==
"2.0");
924 auto const lines =
env.rpc(
927 R
"("method" : "account_lines",)"
928 R"("jsonrpc" : "2.0",)"
929 R"("ripplerpc" : "2.0",)"
935 R"("ledger_index": 50000}})");
938 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
940 lines.isMember(jss::ripplerpc) &&
941 lines[jss::ripplerpc] ==
"2.0");
949 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
957 env(trust(alice, gw1Currency(100 + c)));
958 env(pay(
gw1, alice, gw1Currency(50 + c)));
974 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
982 env(trust(alice, gw2Currency(200 + c)));
985 env(pay(
gw2, alice, gw2Currency(100 + c)));
1001 Account
const& account,
1005 auto const linesSeq =
env.rpc(
1008 R
"("method" : "account_lines",)"
1009 R"("jsonrpc" : "2.0",)"
1010 R"("ripplerpc" : "2.0",)"
1013 R"({"account": ")" +
1016 R"("ledger_index": )" +
1018 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
1019 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
1021 linesSeq.isMember(jss::jsonrpc) &&
1022 linesSeq[jss::jsonrpc] ==
"2.0");
1024 linesSeq.isMember(jss::ripplerpc) &&
1025 linesSeq[jss::ripplerpc] ==
"2.0");
1026 BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
1029 auto const linesHash =
env.rpc(
1032 R
"("method" : "account_lines",)"
1033 R"("jsonrpc" : "2.0",)"
1034 R"("ripplerpc" : "2.0",)"
1037 R"({"account": ")" +
1040 R"("ledger_hash": ")" +
1042 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
1043 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
1045 linesHash.isMember(jss::jsonrpc) &&
1046 linesHash[jss::jsonrpc] == "2.0");
1048 linesHash.isMember(jss::ripplerpc) &&
1049 linesHash[jss::ripplerpc] ==
"2.0");
1051 linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
1066 auto const lines =
env.rpc(
1069 R
"("method" : "account_lines",)"
1070 R"("jsonrpc" : "2.0",)"
1071 R"("ripplerpc" : "2.0",)"
1074 R"({"account": ")" +
1077 R"("ledger_hash": ")" +
1080 R"("ledger_index": )" +
1085 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1087 lines.isMember(jss::ripplerpc) &&
1088 lines[jss::ripplerpc] ==
"2.0");
1093 auto const lines =
env.rpc(
1096 R
"("method" : "account_lines",)"
1097 R"("jsonrpc" : "2.0",)"
1098 R"("ripplerpc" : "2.0",)"
1101 R"({"account": ")" +
1102 alice.human() + R"("}})");
1106 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1108 lines.isMember(jss::ripplerpc) &&
1109 lines[jss::ripplerpc] ==
"2.0");
1114 auto const lines =
env.rpc(
1117 R
"("method" : "account_lines",)"
1118 R"("jsonrpc" : "2.0",)"
1119 R"("ripplerpc" : "2.0",)"
1122 R"({"account": ")" +
1126 gw1.human() + R"("}})");
1130 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1132 lines.isMember(jss::ripplerpc) &&
1133 lines[jss::ripplerpc] ==
"2.0");
1138 auto const lines =
env.rpc(
1141 R
"("method" : "account_lines",)"
1142 R"("jsonrpc" : "2.0",)"
1143 R"("ripplerpc" : "2.0",)"
1146 R"({"account": ")" +
1150 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
1152 lines[jss::error][jss::message] ==
1155 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1157 lines.isMember(jss::ripplerpc) &&
1158 lines[jss::ripplerpc] ==
"2.0");
1163 auto const lines =
env.rpc(
1166 R
"("method" : "account_lines",)"
1167 R"("jsonrpc" : "2.0",)"
1168 R"("ripplerpc" : "2.0",)"
1171 R"({"account": ")" +
1174 R"("limit": -1}})");
1176 lines[jss::error][jss::message] ==
1179 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1181 lines.isMember(jss::ripplerpc) &&
1182 lines[jss::ripplerpc] ==
"2.0");
1187 auto const linesA =
env.rpc(
1190 R
"("method" : "account_lines",)"
1191 R"("jsonrpc" : "2.0",)"
1192 R"("ripplerpc" : "2.0",)"
1195 R"({"account": ")" +
1202 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
1204 linesA.isMember(jss::ripplerpc) &&
1205 linesA[jss::ripplerpc] ==
"2.0");
1209 auto marker = linesA[jss::result][jss::marker].asString();
1213 R
"("method" : "account_lines",)"
1214 R"("jsonrpc" : "2.0",)"
1215 R"("ripplerpc" : "2.0",)"
1218 R"({"account": ")" +
1226 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1228 linesB.isMember(jss::ripplerpc) &&
1229 linesB[jss::ripplerpc] ==
"2.0");
1236 R
"("method" : "account_lines",)"
1237 R"("jsonrpc" : "2.0",)"
1238 R"("ripplerpc" : "2.0",)"
1241 R"({"account": ")" +
1250 linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0");
1252 linesC.isMember(jss::ripplerpc) &&
1253 linesC[jss::ripplerpc] ==
"2.0");
1261 R
"("method" : "account_lines",)"
1262 R"("jsonrpc" : "2.0",)"
1263 R"("ripplerpc" : "2.0",)"
1266 R"({"account": ")" +
1272 linesD[jss::error][jss::message] ==
1275 linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0");
1277 linesD.isMember(jss::ripplerpc) &&
1278 linesD[jss::ripplerpc] ==
"2.0");
1283 auto const lines =
env.rpc(
1286 R
"("method" : "account_lines",)"
1287 R"("jsonrpc" : "2.0",)"
1288 R"("ripplerpc" : "2.0",)"
1291 R"({"account": ")" +
1294 R"("marker": true}})");
1296 lines[jss::error][jss::message] ==
1299 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1301 lines.isMember(jss::ripplerpc) &&
1302 lines[jss::ripplerpc] ==
"2.0");
1307 auto const lines =
env.rpc(
1310 R
"("method" : "account_lines",)"
1311 R"("jsonrpc" : "2.0",)"
1312 R"("ripplerpc" : "2.0",)"
1315 R"({"account": ")" +
1320 gw2.human() + R"("}})");
1321 auto const&
line = lines[jss::result][jss::lines][0u];
1327 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1329 lines.isMember(jss::ripplerpc) &&
1330 lines[jss::ripplerpc] ==
"2.0");
1335 auto const linesA =
env.rpc(
1338 R
"("method" : "account_lines",)"
1339 R"("jsonrpc" : "2.0",)"
1340 R"("ripplerpc" : "2.0",)"
1343 R"({"account": ")" +
1348 alice.human() + R"("}})");
1349 auto const&
lineA = linesA[jss::result][jss::lines][0u];
1355 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] ==
"2.0");
1357 linesA.isMember(jss::ripplerpc) &&
1358 linesA[jss::ripplerpc] ==
"2.0");
1363 auto const marker = linesA[jss::result][jss::marker].asString();
1367 R
"("method" : "account_lines",)"
1368 R"("jsonrpc" : "2.0",)"
1369 R"("ripplerpc" : "2.0",)"
1372 R"({"account": ")" +
1380 alice.human() + R"("}})");
1385 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1387 linesB.isMember(jss::ripplerpc) &&
1388 linesB[jss::ripplerpc] ==
"2.0");
1397 testcase(
"V2: account_lines with removed marker");
1399 using namespace test::jtx;
1413 Account
const alice{
"alice"};
1414 Account
const becky{
"becky"};
1415 Account
const cheri{
"cheri"};
1416 Account
const gw1{
"gw1"};
1417 Account
const gw2{
"gw2"};
1418 env.fund(XRP(10000), alice, becky, cheri,
gw1,
gw2);
1421 auto const USD =
gw1[
"USD"];
1422 auto const AUD =
gw1[
"AUD"];
1423 auto const EUR =
gw2[
"EUR"];
1424 env(trust(alice, USD(200)));
1425 env(trust(alice, AUD(200)));
1426 env(trust(becky, EUR(200)));
1427 env(trust(cheri, EUR(200)));
1431 env(pay(
gw2, becky, EUR(100)));
1435 env(offer(alice, EUR(100), XRP(100)));
1439 env(offer(becky, XRP(100), EUR(100)));
1443 auto const linesBeg =
env.rpc(
1446 R
"("method" : "account_lines",)"
1447 R"("jsonrpc" : "2.0",)"
1448 R"("ripplerpc" : "2.0",)"
1451 R"({"account": ")" +
1456 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
1457 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
1459 linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] ==
"2.0");
1461 linesBeg.isMember(jss::ripplerpc) &&
1462 linesBeg[jss::ripplerpc] ==
"2.0");
1463 BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5);
1466 env(pay(alice, cheri, EUR(100)));
1471 auto const linesEnd =
env.rpc(
1474 R
"("method" : "account_lines",)"
1475 R"("jsonrpc" : "2.0",)"
1476 R"("ripplerpc" : "2.0",)"
1479 R"({"account": ")" +
1483 linesBeg[jss::result][jss::marker].asString() + R"("}})");
1485 linesEnd[jss::error][jss::message] ==
1488 linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0");
1490 linesEnd.isMember(jss::ripplerpc) &&
1491 linesEnd[jss::ripplerpc] ==
"2.0");
1499 testAccountLinesMarker();
1500 testAccountLineDelete();
1501 testAccountLinesWalkMarkers();
1507BEAST_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