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"};
578 Account
const& account,
580 STAmount
const& amount) {
582 jv[jss::TransactionType] = jss::EscrowCreate;
583 jv[jss::Account] = account.human();
584 jv[jss::Destination] = to.human();
587 jv[sfFinishAfter.jsonName] =
finish.time_since_epoch().count();
591 auto payChan = [](Account
const& account,
593 STAmount
const& amount,
595 PublicKey
const& pk) {
597 jv[jss::TransactionType] = jss::PaymentChannelCreate;
598 jv[jss::Account] = account.human();
599 jv[jss::Destination] = to.human();
601 jv[
"SettleDelay"] = settleDelay.count();
602 jv[
"PublicKey"] =
strHex(pk.slice());
611 Account
const bogie{
"bogie"};
620 auto const EUR =
gw1[
"EUR"];
643 env(token::createOffer(alice, beckyNFtokenID,
drops(1)),
644 token::owner(becky));
645 env(token::createOffer(becky, aliceNFtokenID,
drops(1)),
646 token::owner(alice));
648 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
650 token::destination(alice));
651 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
653 token::destination(becky));
655 env(token::createOffer(
gw1, beckyNFtokenID,
drops(1)),
657 token::destination(alice));
658 env(token::createOffer(
gw1, aliceNFtokenID,
drops(1)),
660 token::destination(becky));
662 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
664 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
668 env(check::create(alice, becky,
XRP(50)));
669 env(check::create(becky, alice,
XRP(50)));
672 env(deposit::auth(alice, becky));
673 env(deposit::auth(becky, alice));
677 auto const USDalice = alice[
"USD"];
682 env(ticket::create(alice, 2));
685 auto const BTCbecky = becky[
"BTC"];
694 auto getNextLine = [](Env&
env,
695 Account
const& alice,
698 params[jss::account] = alice.human();
699 params[jss::limit] = 1;
701 params[jss::marker] = *
marker;
703 return env.rpc(
"json",
"account_lines",
to_string(params));
706 auto aliceLines = getNextLine(
env, alice, std::nullopt);
712 auto hasMarker = [](
auto const& aliceLines) {
713 return aliceLines[jss::result].isMember(jss::marker);
715 auto marker = [](
auto const& aliceLines) {
716 return aliceLines[jss::result][jss::marker].asString();
718 auto checkLines = [](
auto const& aliceLines) {
719 return aliceLines.isMember(jss::result) &&
720 !aliceLines[jss::result].isMember(jss::error_message) &&
721 aliceLines[jss::result].isMember(jss::lines) &&
722 aliceLines[jss::result][jss::lines].isArray() &&
723 aliceLines[jss::result][jss::lines].size() <= 1;
732 while (hasMarker(aliceLines))
735 aliceLines = getNextLine(
env, alice,
marker(aliceLines));
737 foundLines += aliceLines[jss::result][jss::lines].size();
745 R
"({"account": ")" + alice.human() +
750 !aliceObjects[jss::result].isMember(jss::error_message));
752 aliceObjects[jss::result].isMember(jss::account_objects));
754 aliceObjects[jss::result][jss::account_objects].isArray());
759 aliceObjects[jss::result][jss::account_objects].
size() ==
760 iterations + expectedNFTs);
770 R
"({"account": ")" + becky.human() +
775 !beckyObjects[jss::result].isMember(jss::error_message));
777 beckyObjects[jss::result].isMember(jss::account_objects));
779 beckyObjects[jss::result][jss::account_objects].isArray());
783 beckyObjects[jss::result][jss::account_objects].
size() ==
784 aliceObjects[jss::result][jss::account_objects].
size() - 2);
794 using namespace test::jtx;
798 auto const lines =
env.rpc(
801 R
"("method" : "account_lines",)"
802 R"("jsonrpc" : "2.0",)"
803 R"("ripplerpc" : "2.0")"
806 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
808 lines.isMember(jss::ripplerpc) &&
809 lines[jss::ripplerpc] ==
"2.0");
813 auto const lines =
env.rpc(
816 R
"("method" : "account_lines",)"
817 R"("jsonrpc" : "2.0",)"
818 R"("ripplerpc" : "2.0",)"
822 lines[jss::error][jss::message] ==
825 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
827 lines.isMember(jss::ripplerpc) &&
828 lines[jss::ripplerpc] ==
"2.0");
829 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
833 auto const lines =
env.rpc(
836 R
"("method" : "account_lines",)"
837 R"("jsonrpc" : "2.0",)"
838 R"("ripplerpc" : "2.0",)"
842 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
844 lines[jss::error][jss::message] ==
847 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
849 lines.isMember(jss::ripplerpc) &&
850 lines[jss::ripplerpc] ==
"2.0");
851 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
853 Account
const alice{
"alice"};
856 auto const lines =
env.rpc(
859 R
"("method" : "account_lines",)"
860 R"("jsonrpc" : "2.0",)"
861 R"("ripplerpc" : "2.0",)"
865 alice.human() + R"("}})");
867 lines[jss::error][jss::message] ==
870 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
872 lines.isMember(jss::ripplerpc) &&
873 lines[jss::ripplerpc] ==
"2.0");
876 env.fund(XRP(10000), alice);
883 auto const lines =
env.rpc(
886 R
"("method" : "account_lines",)"
887 R"("jsonrpc" : "2.0",)"
888 R"("ripplerpc" : "2.0",)"
892 alice.human() + R"("}})");
896 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
898 lines.isMember(jss::ripplerpc) &&
899 lines[jss::ripplerpc] ==
"2.0");
904 auto const lines =
env.rpc(
907 R
"("method" : "account_lines",)"
908 R"("jsonrpc" : "2.0",)"
909 R"("ripplerpc" : "2.0",)"
915 R"("ledger_index": "nonsense"}})");
917 lines[jss::error][jss::message] == "ledgerIndexMalformed");
919 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
921 lines.isMember(jss::ripplerpc) &&
922 lines[jss::ripplerpc] ==
"2.0");
927 auto const lines =
env.rpc(
930 R
"("method" : "account_lines",)"
931 R"("jsonrpc" : "2.0",)"
932 R"("ripplerpc" : "2.0",)"
938 R"("ledger_index": 50000}})");
941 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
943 lines.isMember(jss::ripplerpc) &&
944 lines[jss::ripplerpc] ==
"2.0");
952 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
960 env(trust(alice, gw1Currency(100 + c)));
961 env(pay(
gw1, alice, gw1Currency(50 + c)));
977 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
985 env(trust(alice, gw2Currency(200 + c)));
988 env(pay(
gw2, alice, gw2Currency(100 + c)));
1004 Account
const& account,
1008 auto const linesSeq =
env.rpc(
1011 R
"("method" : "account_lines",)"
1012 R"("jsonrpc" : "2.0",)"
1013 R"("ripplerpc" : "2.0",)"
1016 R"({"account": ")" +
1019 R"("ledger_index": )" +
1021 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
1022 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
1024 linesSeq.isMember(jss::jsonrpc) &&
1025 linesSeq[jss::jsonrpc] ==
"2.0");
1027 linesSeq.isMember(jss::ripplerpc) &&
1028 linesSeq[jss::ripplerpc] ==
"2.0");
1029 BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
1032 auto const linesHash =
env.rpc(
1035 R
"("method" : "account_lines",)"
1036 R"("jsonrpc" : "2.0",)"
1037 R"("ripplerpc" : "2.0",)"
1040 R"({"account": ")" +
1043 R"("ledger_hash": ")" +
1045 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
1046 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
1048 linesHash.isMember(jss::jsonrpc) &&
1049 linesHash[jss::jsonrpc] == "2.0");
1051 linesHash.isMember(jss::ripplerpc) &&
1052 linesHash[jss::ripplerpc] ==
"2.0");
1054 linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
1069 auto const lines =
env.rpc(
1072 R
"("method" : "account_lines",)"
1073 R"("jsonrpc" : "2.0",)"
1074 R"("ripplerpc" : "2.0",)"
1077 R"({"account": ")" +
1080 R"("ledger_hash": ")" +
1083 R"("ledger_index": )" +
1088 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1090 lines.isMember(jss::ripplerpc) &&
1091 lines[jss::ripplerpc] ==
"2.0");
1096 auto const lines =
env.rpc(
1099 R
"("method" : "account_lines",)"
1100 R"("jsonrpc" : "2.0",)"
1101 R"("ripplerpc" : "2.0",)"
1104 R"({"account": ")" +
1105 alice.human() + R"("}})");
1109 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1111 lines.isMember(jss::ripplerpc) &&
1112 lines[jss::ripplerpc] ==
"2.0");
1117 auto const lines =
env.rpc(
1120 R
"("method" : "account_lines",)"
1121 R"("jsonrpc" : "2.0",)"
1122 R"("ripplerpc" : "2.0",)"
1125 R"({"account": ")" +
1129 gw1.human() + R"("}})");
1133 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1135 lines.isMember(jss::ripplerpc) &&
1136 lines[jss::ripplerpc] ==
"2.0");
1141 auto const lines =
env.rpc(
1144 R
"("method" : "account_lines",)"
1145 R"("jsonrpc" : "2.0",)"
1146 R"("ripplerpc" : "2.0",)"
1149 R"({"account": ")" +
1153 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
1155 lines[jss::error][jss::message] ==
1158 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1160 lines.isMember(jss::ripplerpc) &&
1161 lines[jss::ripplerpc] ==
"2.0");
1166 auto const lines =
env.rpc(
1169 R
"("method" : "account_lines",)"
1170 R"("jsonrpc" : "2.0",)"
1171 R"("ripplerpc" : "2.0",)"
1174 R"({"account": ")" +
1177 R"("limit": -1}})");
1179 lines[jss::error][jss::message] ==
1182 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1184 lines.isMember(jss::ripplerpc) &&
1185 lines[jss::ripplerpc] ==
"2.0");
1190 auto const linesA =
env.rpc(
1193 R
"("method" : "account_lines",)"
1194 R"("jsonrpc" : "2.0",)"
1195 R"("ripplerpc" : "2.0",)"
1198 R"({"account": ")" +
1205 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
1207 linesA.isMember(jss::ripplerpc) &&
1208 linesA[jss::ripplerpc] ==
"2.0");
1212 auto marker = linesA[jss::result][jss::marker].asString();
1216 R
"("method" : "account_lines",)"
1217 R"("jsonrpc" : "2.0",)"
1218 R"("ripplerpc" : "2.0",)"
1221 R"({"account": ")" +
1229 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1231 linesB.isMember(jss::ripplerpc) &&
1232 linesB[jss::ripplerpc] ==
"2.0");
1239 R
"("method" : "account_lines",)"
1240 R"("jsonrpc" : "2.0",)"
1241 R"("ripplerpc" : "2.0",)"
1244 R"({"account": ")" +
1253 linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0");
1255 linesC.isMember(jss::ripplerpc) &&
1256 linesC[jss::ripplerpc] ==
"2.0");
1264 R
"("method" : "account_lines",)"
1265 R"("jsonrpc" : "2.0",)"
1266 R"("ripplerpc" : "2.0",)"
1269 R"({"account": ")" +
1275 linesD[jss::error][jss::message] ==
1278 linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0");
1280 linesD.isMember(jss::ripplerpc) &&
1281 linesD[jss::ripplerpc] ==
"2.0");
1286 auto const lines =
env.rpc(
1289 R
"("method" : "account_lines",)"
1290 R"("jsonrpc" : "2.0",)"
1291 R"("ripplerpc" : "2.0",)"
1294 R"({"account": ")" +
1297 R"("marker": true}})");
1299 lines[jss::error][jss::message] ==
1302 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1304 lines.isMember(jss::ripplerpc) &&
1305 lines[jss::ripplerpc] ==
"2.0");
1310 auto const lines =
env.rpc(
1313 R
"("method" : "account_lines",)"
1314 R"("jsonrpc" : "2.0",)"
1315 R"("ripplerpc" : "2.0",)"
1318 R"({"account": ")" +
1323 gw2.human() + R"("}})");
1324 auto const&
line = lines[jss::result][jss::lines][0u];
1330 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1332 lines.isMember(jss::ripplerpc) &&
1333 lines[jss::ripplerpc] ==
"2.0");
1338 auto const linesA =
env.rpc(
1341 R
"("method" : "account_lines",)"
1342 R"("jsonrpc" : "2.0",)"
1343 R"("ripplerpc" : "2.0",)"
1346 R"({"account": ")" +
1351 alice.human() + R"("}})");
1352 auto const&
lineA = linesA[jss::result][jss::lines][0u];
1358 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] ==
"2.0");
1360 linesA.isMember(jss::ripplerpc) &&
1361 linesA[jss::ripplerpc] ==
"2.0");
1366 auto const marker = linesA[jss::result][jss::marker].asString();
1370 R
"("method" : "account_lines",)"
1371 R"("jsonrpc" : "2.0",)"
1372 R"("ripplerpc" : "2.0",)"
1375 R"({"account": ")" +
1383 alice.human() + R"("}})");
1388 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1390 linesB.isMember(jss::ripplerpc) &&
1391 linesB[jss::ripplerpc] ==
"2.0");
1400 testcase(
"V2: account_lines with removed marker");
1402 using namespace test::jtx;
1416 Account
const alice{
"alice"};
1417 Account
const becky{
"becky"};
1418 Account
const cheri{
"cheri"};
1419 Account
const gw1{
"gw1"};
1420 Account
const gw2{
"gw2"};
1421 env.fund(XRP(10000), alice, becky, cheri,
gw1,
gw2);
1424 auto const USD =
gw1[
"USD"];
1425 auto const AUD =
gw1[
"AUD"];
1426 auto const EUR =
gw2[
"EUR"];
1427 env(trust(alice, USD(200)));
1428 env(trust(alice, AUD(200)));
1429 env(trust(becky, EUR(200)));
1430 env(trust(cheri, EUR(200)));
1434 env(pay(
gw2, becky, EUR(100)));
1438 env(offer(alice, EUR(100), XRP(100)));
1442 env(offer(becky, XRP(100), EUR(100)));
1446 auto const linesBeg =
env.rpc(
1449 R
"("method" : "account_lines",)"
1450 R"("jsonrpc" : "2.0",)"
1451 R"("ripplerpc" : "2.0",)"
1454 R"({"account": ")" +
1459 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
1460 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
1462 linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] ==
"2.0");
1464 linesBeg.isMember(jss::ripplerpc) &&
1465 linesBeg[jss::ripplerpc] ==
"2.0");
1466 BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5);
1469 env(pay(alice, cheri, EUR(100)));
1474 auto const linesEnd =
env.rpc(
1477 R
"("method" : "account_lines",)"
1478 R"("jsonrpc" : "2.0",)"
1479 R"("ripplerpc" : "2.0",)"
1482 R"({"account": ")" +
1486 linesBeg[jss::result][jss::marker].asString() + R"("}})");
1488 linesEnd[jss::error][jss::message] ==
1491 linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0");
1493 linesEnd.isMember(jss::ripplerpc) &&
1494 linesEnd[jss::ripplerpc] ==
"2.0");
1502 testAccountLinesMarker();
1503 testAccountLineDelete();
1504 testAccountLinesWalkMarkers();
1510BEAST_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::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
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