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)));
178 Account
const& account,
182 auto const linesSeq =
env.rpc(
185 R
"({"account": ")" + account.human() +
187 R"("ledger_index": )" +
189 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
190 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
193 auto const linesHash =
env.rpc(
196 R
"({"account": ")" + account.human() +
198 R"("ledger_hash": ")" +
200 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
201 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
216 auto const lines =
env.rpc(
219 R
"({"account": ")" + alice.human() +
221 R"("ledger_hash": ")" +
224 R"("ledger_index": )" +
227 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
231 auto const lines =
env.rpc(
234 R
"({"account": ")" + alice.human() + R"("})");
236 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52);
240 auto const lines =
env.rpc(
243 R
"({"account": ")" + alice.human() +
246 gw1.human() + R"("})");
248 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
252 auto const lines =
env.rpc(
255 R
"({"account": ")" + alice.human() +
258 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
260 lines[jss::result][jss::error_message] ==
265 auto const lines =
env.rpc(
268 R
"({"account": ")" + alice.human() +
272 lines[jss::result][jss::error_message] ==
277 auto const linesA =
env.rpc(
280 R
"({"account": ")" + alice.human() +
283 BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
284 BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
287 auto marker = linesA[jss::result][jss::marker].asString();
291 R
"({"account": ")" + alice.human() +
302 R
"({"account": ")" + alice.human() +
315 R
"({"account": ")" + alice.human() +
320 linesD[jss::result][jss::error_message] ==
325 auto const lines =
env.rpc(
328 R
"({"account": ")" + alice.human() +
330 R"("marker": true})");
332 lines[jss::result][jss::error_message] ==
337 auto const lines =
env.rpc(
340 R
"({"account": ")" + alice.human() +
344 gw2.human() + R"("})");
345 auto const&
line = lines[jss::result][jss::lines][0u];
352 auto const linesA =
env.rpc(
355 R
"({"account": ")" + gw2.human() +
359 alice.human() + R"("})");
360 auto const&
lineA = linesA[jss::result][jss::lines][0u];
366 BEAST_EXPECT(linesA[jss::result].isMember(jss::marker));
367 auto const marker = linesA[jss::result][jss::marker].asString();
371 R
"({"account": ")" + gw2.human() +
378 alice.human() + R"("})");
386 testAccountLinesMarker()
388 testcase(
"Entry pointed to by marker is not owned by account");
389 using namespace test::jtx;
398 Account
const alice{
"alice"};
399 Account
const becky{
"becky"};
400 Account
const gw1{
"gw1"};
405 Account
const bogie{
"bogie"};
409 auto const EUR =
gw1[
"EUR"];
421 R
"({"account": ")" + alice.human() +
425 aliceObjects[jss::result][jss::account_objects][0u];
426 if (!(aliceSignerList[sfLedgerEntryType.jsonName] == jss::SignerList))
429 "alice's account objects are misordered. "
430 "Please reorder the objects so the SignerList is first.",
438 auto const aliceLines1 =
env.rpc(
441 R
"({"account": ")" + alice.human() + R"(", "limit": 1})");
442 BEAST_EXPECT(aliceLines1[jss::result].isMember(jss::marker));
446 aliceLines1[jss::result][jss::marker].asString();
449 BEAST_EXPECT(markerIndex == aliceSignerList[jss::index].asString());
452 auto const aliceLines2 =
env.rpc(
455 R
"({"account": ")" + alice.human() + R"(", "marker": ")" +
456 aliceMarker + R"("})");
458 BEAST_EXPECT(!aliceLines2[jss::result].isMember(jss::marker));
462 auto const beckyLines =
env.rpc(
465 R
"({"account": ")" + becky.human() + R"(", "marker": ")" +
466 aliceMarker + R"("})");
467 BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message));
471 testAccountLineDelete()
473 testcase(
"Entry pointed to by marker is removed");
474 using namespace test::jtx;
488 Account
const alice{
"alice"};
489 Account
const becky{
"becky"};
490 Account
const cheri{
"cheri"};
491 Account
const gw1{
"gw1"};
492 Account
const gw2{
"gw2"};
496 auto const USD =
gw1[
"USD"];
497 auto const AUD =
gw1[
"AUD"];
498 auto const EUR =
gw2[
"EUR"];
518 auto const linesBeg =
env.rpc(
521 R
"({"account": ")" + alice.human() +
525 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
526 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
529 env(
pay(alice, cheri, EUR(100)));
534 auto const linesEnd =
env.rpc(
537 R
"({"account": ")" + alice.human() +
540 linesBeg[jss::result][jss::marker].asString() + R"("})");
542 linesEnd[jss::result][jss::error_message] ==
547 testAccountLinesWalkMarkers()
549 testcase(
"Marker can point to any appropriate ledger entry type");
550 using namespace test::jtx;
551 using namespace std::chrono_literals;
560 Account
const alice{
"alice"};
561 Account
const becky{
"becky"};
562 Account
const gw1{
"gw1"};
568 Account
const& account,
570 STAmount
const& amount) {
572 jv[jss::TransactionType] = jss::EscrowCreate;
574 jv[jss::Account] = account.human();
575 jv[jss::Destination] = to.human();
578 jv[sfFinishAfter.jsonName] =
finish.time_since_epoch().count();
582 auto payChan = [](Account
const& account,
584 STAmount
const& amount,
586 PublicKey
const& pk) {
588 jv[jss::TransactionType] = jss::PaymentChannelCreate;
590 jv[jss::Account] = account.human();
591 jv[jss::Destination] = to.human();
593 jv[
"SettleDelay"] = settleDelay.count();
594 jv[
"PublicKey"] =
strHex(pk.slice());
603 Account
const bogie{
"bogie"};
612 auto const EUR =
gw1[
"EUR"];
635 env(token::createOffer(alice, beckyNFtokenID,
drops(1)),
636 token::owner(becky));
637 env(token::createOffer(becky, aliceNFtokenID,
drops(1)),
638 token::owner(alice));
640 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
642 token::destination(alice));
643 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
645 token::destination(becky));
647 env(token::createOffer(
gw1, beckyNFtokenID,
drops(1)),
649 token::destination(alice));
650 env(token::createOffer(
gw1, aliceNFtokenID,
drops(1)),
652 token::destination(becky));
654 env(token::createOffer(becky, beckyNFtokenID,
drops(1)),
656 env(token::createOffer(alice, aliceNFtokenID,
drops(1)),
660 env(check::create(alice, becky,
XRP(50)));
661 env(check::create(becky, alice,
XRP(50)));
664 env(deposit::auth(alice, becky));
665 env(deposit::auth(becky, alice));
669 auto const USDalice = alice[
"USD"];
674 env(ticket::create(alice, 2));
677 auto const BTCbecky = becky[
"BTC"];
686 auto getNextLine = [](Env&
env,
687 Account
const& alice,
690 params[jss::account] = alice.human();
691 params[jss::limit] = 1;
693 params[jss::marker] = *
marker;
695 return env.rpc(
"json",
"account_lines",
to_string(params));
698 auto aliceLines = getNextLine(
env, alice, std::nullopt);
704 auto hasMarker = [](
auto const& aliceLines) {
705 return aliceLines[jss::result].isMember(jss::marker);
707 auto marker = [](
auto const& aliceLines) {
708 return aliceLines[jss::result][jss::marker].asString();
710 auto checkLines = [](
auto const& aliceLines) {
711 return aliceLines.isMember(jss::result) &&
712 !aliceLines[jss::result].isMember(jss::error_message) &&
713 aliceLines[jss::result].isMember(jss::lines) &&
714 aliceLines[jss::result][jss::lines].isArray() &&
715 aliceLines[jss::result][jss::lines].size() <= 1;
724 while (hasMarker(aliceLines))
727 aliceLines = getNextLine(
env, alice,
marker(aliceLines));
729 foundLines += aliceLines[jss::result][jss::lines].size();
737 R
"({"account": ")" + alice.human() +
742 !aliceObjects[jss::result].isMember(jss::error_message));
744 aliceObjects[jss::result].isMember(jss::account_objects));
746 aliceObjects[jss::result][jss::account_objects].isArray());
751 aliceObjects[jss::result][jss::account_objects].
size() ==
752 iterations + expectedNFTs);
762 R
"({"account": ")" + becky.human() +
767 !beckyObjects[jss::result].isMember(jss::error_message));
769 beckyObjects[jss::result].isMember(jss::account_objects));
771 beckyObjects[jss::result][jss::account_objects].isArray());
775 beckyObjects[jss::result][jss::account_objects].
size() ==
776 aliceObjects[jss::result][jss::account_objects].
size() - 2);
786 using namespace test::jtx;
790 auto const lines =
env.rpc(
793 R
"("method" : "account_lines",)"
794 R"("jsonrpc" : "2.0",)"
795 R"("ripplerpc" : "2.0")"
798 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
800 lines.isMember(jss::ripplerpc) &&
801 lines[jss::ripplerpc] ==
"2.0");
805 auto const lines =
env.rpc(
808 R
"("method" : "account_lines",)"
809 R"("jsonrpc" : "2.0",)"
810 R"("ripplerpc" : "2.0",)"
814 lines[jss::error][jss::message] ==
817 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
819 lines.isMember(jss::ripplerpc) &&
820 lines[jss::ripplerpc] ==
"2.0");
821 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
825 auto const lines =
env.rpc(
828 R
"("method" : "account_lines",)"
829 R"("jsonrpc" : "2.0",)"
830 R"("ripplerpc" : "2.0",)"
834 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
836 lines[jss::error][jss::message] ==
839 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
841 lines.isMember(jss::ripplerpc) &&
842 lines[jss::ripplerpc] ==
"2.0");
843 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
845 Account
const alice{
"alice"};
848 auto const lines =
env.rpc(
851 R
"("method" : "account_lines",)"
852 R"("jsonrpc" : "2.0",)"
853 R"("ripplerpc" : "2.0",)"
857 alice.human() + R"("}})");
859 lines[jss::error][jss::message] ==
862 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
864 lines.isMember(jss::ripplerpc) &&
865 lines[jss::ripplerpc] ==
"2.0");
868 env.fund(XRP(10000), alice);
875 auto const lines =
env.rpc(
878 R
"("method" : "account_lines",)"
879 R"("jsonrpc" : "2.0",)"
880 R"("ripplerpc" : "2.0",)"
884 alice.human() + R"("}})");
888 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
890 lines.isMember(jss::ripplerpc) &&
891 lines[jss::ripplerpc] ==
"2.0");
896 auto const lines =
env.rpc(
899 R
"("method" : "account_lines",)"
900 R"("jsonrpc" : "2.0",)"
901 R"("ripplerpc" : "2.0",)"
907 R"("ledger_index": "nonsense"}})");
909 lines[jss::error][jss::message] == "ledgerIndexMalformed");
911 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
913 lines.isMember(jss::ripplerpc) &&
914 lines[jss::ripplerpc] ==
"2.0");
919 auto const lines =
env.rpc(
922 R
"("method" : "account_lines",)"
923 R"("jsonrpc" : "2.0",)"
924 R"("ripplerpc" : "2.0",)"
930 R"("ledger_index": 50000}})");
933 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
935 lines.isMember(jss::ripplerpc) &&
936 lines[jss::ripplerpc] ==
"2.0");
944 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
952 env(trust(alice, gw1Currency(100 + c)));
953 env(pay(
gw1, alice, gw1Currency(50 + c)));
969 for (
char c = 0; c <= (
'Z' -
'A'); ++c)
977 env(trust(alice, gw2Currency(200 + c)));
980 env(pay(
gw2, alice, gw2Currency(100 + c)));
992 Account
const& account,
996 auto const linesSeq =
env.rpc(
999 R
"("method" : "account_lines",)"
1000 R"("jsonrpc" : "2.0",)"
1001 R"("ripplerpc" : "2.0",)"
1004 R"({"account": ")" +
1007 R"("ledger_index": )" +
1009 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
1010 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
1012 linesSeq.isMember(jss::jsonrpc) &&
1013 linesSeq[jss::jsonrpc] ==
"2.0");
1015 linesSeq.isMember(jss::ripplerpc) &&
1016 linesSeq[jss::ripplerpc] ==
"2.0");
1017 BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
1020 auto const linesHash =
env.rpc(
1023 R
"("method" : "account_lines",)"
1024 R"("jsonrpc" : "2.0",)"
1025 R"("ripplerpc" : "2.0",)"
1028 R"({"account": ")" +
1031 R"("ledger_hash": ")" +
1033 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
1034 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
1036 linesHash.isMember(jss::jsonrpc) &&
1037 linesHash[jss::jsonrpc] == "2.0");
1039 linesHash.isMember(jss::ripplerpc) &&
1040 linesHash[jss::ripplerpc] ==
"2.0");
1042 linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
1057 auto const lines =
env.rpc(
1060 R
"("method" : "account_lines",)"
1061 R"("jsonrpc" : "2.0",)"
1062 R"("ripplerpc" : "2.0",)"
1065 R"({"account": ")" +
1068 R"("ledger_hash": ")" +
1071 R"("ledger_index": )" +
1076 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1078 lines.isMember(jss::ripplerpc) &&
1079 lines[jss::ripplerpc] ==
"2.0");
1084 auto const lines =
env.rpc(
1087 R
"("method" : "account_lines",)"
1088 R"("jsonrpc" : "2.0",)"
1089 R"("ripplerpc" : "2.0",)"
1092 R"({"account": ")" +
1093 alice.human() + R"("}})");
1097 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1099 lines.isMember(jss::ripplerpc) &&
1100 lines[jss::ripplerpc] ==
"2.0");
1105 auto const lines =
env.rpc(
1108 R
"("method" : "account_lines",)"
1109 R"("jsonrpc" : "2.0",)"
1110 R"("ripplerpc" : "2.0",)"
1113 R"({"account": ")" +
1117 gw1.human() + R"("}})");
1121 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1123 lines.isMember(jss::ripplerpc) &&
1124 lines[jss::ripplerpc] ==
"2.0");
1129 auto const lines =
env.rpc(
1132 R
"("method" : "account_lines",)"
1133 R"("jsonrpc" : "2.0",)"
1134 R"("ripplerpc" : "2.0",)"
1137 R"({"account": ")" +
1141 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
1143 lines[jss::error][jss::message] ==
1146 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
1148 lines.isMember(jss::ripplerpc) &&
1149 lines[jss::ripplerpc] ==
"2.0");
1154 auto const lines =
env.rpc(
1157 R
"("method" : "account_lines",)"
1158 R"("jsonrpc" : "2.0",)"
1159 R"("ripplerpc" : "2.0",)"
1162 R"({"account": ")" +
1165 R"("limit": -1}})");
1167 lines[jss::error][jss::message] ==
1170 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1172 lines.isMember(jss::ripplerpc) &&
1173 lines[jss::ripplerpc] ==
"2.0");
1178 auto const linesA =
env.rpc(
1181 R
"("method" : "account_lines",)"
1182 R"("jsonrpc" : "2.0",)"
1183 R"("ripplerpc" : "2.0",)"
1186 R"({"account": ")" +
1193 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
1195 linesA.isMember(jss::ripplerpc) &&
1196 linesA[jss::ripplerpc] ==
"2.0");
1200 auto marker = linesA[jss::result][jss::marker].asString();
1204 R
"("method" : "account_lines",)"
1205 R"("jsonrpc" : "2.0",)"
1206 R"("ripplerpc" : "2.0",)"
1209 R"({"account": ")" +
1217 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1219 linesB.isMember(jss::ripplerpc) &&
1220 linesB[jss::ripplerpc] ==
"2.0");
1227 R
"("method" : "account_lines",)"
1228 R"("jsonrpc" : "2.0",)"
1229 R"("ripplerpc" : "2.0",)"
1232 R"({"account": ")" +
1241 linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0");
1243 linesC.isMember(jss::ripplerpc) &&
1244 linesC[jss::ripplerpc] ==
"2.0");
1252 R
"("method" : "account_lines",)"
1253 R"("jsonrpc" : "2.0",)"
1254 R"("ripplerpc" : "2.0",)"
1257 R"({"account": ")" +
1263 linesD[jss::error][jss::message] ==
1266 linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0");
1268 linesD.isMember(jss::ripplerpc) &&
1269 linesD[jss::ripplerpc] ==
"2.0");
1274 auto const lines =
env.rpc(
1277 R
"("method" : "account_lines",)"
1278 R"("jsonrpc" : "2.0",)"
1279 R"("ripplerpc" : "2.0",)"
1282 R"({"account": ")" +
1285 R"("marker": true}})");
1287 lines[jss::error][jss::message] ==
1290 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] ==
"2.0");
1292 lines.isMember(jss::ripplerpc) &&
1293 lines[jss::ripplerpc] ==
"2.0");
1298 auto const lines =
env.rpc(
1301 R
"("method" : "account_lines",)"
1302 R"("jsonrpc" : "2.0",)"
1303 R"("ripplerpc" : "2.0",)"
1306 R"({"account": ")" +
1311 gw2.human() + R"("}})");
1312 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];
1344 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] ==
"2.0");
1346 linesA.isMember(jss::ripplerpc) &&
1347 linesA[jss::ripplerpc] ==
"2.0");
1352 auto const marker = linesA[jss::result][jss::marker].asString();
1356 R
"("method" : "account_lines",)"
1357 R"("jsonrpc" : "2.0",)"
1358 R"("ripplerpc" : "2.0",)"
1361 R"({"account": ")" +
1369 alice.human() + R"("}})");
1374 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
1376 linesB.isMember(jss::ripplerpc) &&
1377 linesB[jss::ripplerpc] ==
"2.0");
1386 testcase(
"V2: account_lines with removed marker");
1388 using namespace test::jtx;
1402 Account
const alice{
"alice"};
1403 Account
const becky{
"becky"};
1404 Account
const cheri{
"cheri"};
1405 Account
const gw1{
"gw1"};
1406 Account
const gw2{
"gw2"};
1407 env.fund(XRP(10000), alice, becky, cheri,
gw1,
gw2);
1410 auto const USD =
gw1[
"USD"];
1411 auto const AUD =
gw1[
"AUD"];
1412 auto const EUR =
gw2[
"EUR"];
1413 env(trust(alice, USD(200)));
1414 env(trust(alice, AUD(200)));
1415 env(trust(becky, EUR(200)));
1416 env(trust(cheri, EUR(200)));
1420 env(pay(
gw2, becky, EUR(100)));
1424 env(offer(alice, EUR(100), XRP(100)));
1428 env(offer(becky, XRP(100), EUR(100)));
1432 auto const linesBeg =
env.rpc(
1435 R
"("method" : "account_lines",)"
1436 R"("jsonrpc" : "2.0",)"
1437 R"("ripplerpc" : "2.0",)"
1440 R"({"account": ")" +
1445 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
1446 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
1448 linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] ==
"2.0");
1450 linesBeg.isMember(jss::ripplerpc) &&
1451 linesBeg[jss::ripplerpc] ==
"2.0");
1452 BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5);
1455 env(pay(alice, cheri, EUR(100)));
1460 auto const linesEnd =
env.rpc(
1463 R
"("method" : "account_lines",)"
1464 R"("jsonrpc" : "2.0",)"
1465 R"("ripplerpc" : "2.0",)"
1468 R"({"account": ")" +
1472 linesBeg[jss::result][jss::marker].asString() + R"("}})");
1474 linesEnd[jss::error][jss::message] ==
1477 linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0");
1479 linesEnd.isMember(jss::ripplerpc) &&
1480 linesEnd[jss::ripplerpc] ==
"2.0");
1488 testAccountLinesMarker();
1489 testAccountLineDelete();
1490 testAccountLinesWalkMarkers();
1496BEAST_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(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")
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 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