21#include <test/jtx/Oracle.h>
22#include <test/jtx/attester.h>
23#include <test/jtx/delegate.h>
24#include <test/jtx/multisign.h>
25#include <test/jtx/xchain_bridge.h>
27#include <xrpl/beast/unit_test.h>
28#include <xrpl/json/json_value.h>
29#include <xrpl/protocol/AccountID.h>
30#include <xrpl/protocol/ErrorCodes.h>
31#include <xrpl/protocol/STXChainBridge.h>
32#include <xrpl/protocol/jss.h>
34#if (defined(__clang_major__) && __clang_major__ < 15)
35#include <experimental/source_location>
38#include <source_location>
78 return pair.first == fieldName;
86 Throw<std::runtime_error>(
111 return "hex string or object";
113 return "length-2 array of Accounts";
115 Throw<std::runtime_error>(
129 if (BEAST_EXPECT(jv.
isMember(jss::status)))
132 if (BEAST_EXPECT(jv.
isMember(jss::error)))
134 jv[jss::error] == err,
135 "Expected error " + err +
", received " +
136 jv[jss::error].asString() +
", at line " +
143 jv[jss::error_message] ==
"",
144 "Expected no error message, received \"" +
145 jv[jss::error_message].asString() +
"\", at line " +
149 else if (BEAST_EXPECT(jv.
isMember(jss::error_message)))
151 jv[jss::error_message] == msg,
152 "Expected error message \"" + msg +
"\", received \"" +
153 jv[jss::error_message].asString() +
"\", at line " +
163 obj[jss::account] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
164 obj[jss::ledger_index] =
"validated";
169 arr[0u] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
170 arr[1u] =
"validated";
184 "0123456789ABCDEFGH",
185 "rJxKV9e9p6wiPw!!!!xrJ4X1n98LosPL1sgcJW",
186 "rPSTrR5yEr11uMkfsz1kHCp9jK4aoa3Avv",
187 "n9K2isxwTxcSHJKxMkJznDoWXAUs7NNy49H9Fknz1pC7oHAH3kH9",
190 "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6B01403D"
201 indices.begin(), indices.end());
206 if (indexSet.
find(i) == indexSet.
end())
214 static auto const& badUInt32Values = remove({2, 3});
215 static auto const& badUInt64Values = remove({2, 3});
216 static auto const& badHashValues = remove({2, 3, 7, 8, 16});
217 static auto const& badAccountValues = remove({12});
218 static auto const& badBlobValues = remove({3, 7, 8, 16});
219 static auto const& badCurrencyValues = remove({14});
220 static auto const& badArrayValues = remove({17, 20});
221 static auto const& badIndexValues = remove({12, 16, 18, 19});
226 return badUInt32Values;
228 return badUInt64Values;
230 return badHashValues;
232 return badAccountValues;
234 return badBlobValues;
236 return badCurrencyValues;
239 return badArrayValues;
241 return badIndexValues;
243 Throw<std::runtime_error>(
254 arr[0u] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
255 arr[1u] =
"r4MrUGTdB57duTnRs6KbsRGQXgkseGb1b5";
267 return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6"
270 return "r4MrUGTdB57duTnRs6KbsRGQXgkseGb1b5";
278 return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6"
281 return twoAccountArray;
283 Throw<std::runtime_error>(
314 "No ledger_entry params provided.",
317 auto tryField = [&](
Json::Value fieldValue) ->
void {
318 correctRequest[fieldName] = fieldValue;
324 auto const expectedErrMsg =
330 for (
auto const& value : badValues)
355 correctRequest[parentFieldName].
removeMember(fieldName);
379 auto tryField = [&](
Json::Value fieldValue) ->
void {
380 correctRequest[parentFieldName][fieldName] = fieldValue;
395 for (
auto const& value : badValues)
444 for (
auto const& subfield : subfields)
446 correctOutput[parentField][subfield.fieldName] =
450 for (
auto const& subfield : subfields)
452 auto const fieldType =
getFieldType(subfield.fieldName);
459 subfield.malformedErrorMsg,
469 using namespace test::jtx;
477 jvParams[jss::account_root] = alice.human();
478 jvParams[jss::ledger_hash] =
479 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
481 auto const jrr = env.
rpc(
482 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
488 jvParams[jss::account_root] = alice.human();
492 auto tryField = [&](
Json::Value fieldValue) ->
void {
493 jvParams[jss::ledger_hash] = fieldValue;
499 auto const expectedErrMsg = fieldValue.
isString()
500 ?
"ledgerHashMalformed"
501 :
"ledgerHashNotString";
506 for (
auto const& value : badValues)
516 jvParams[jss::ledger_index] =
"validated";
517 jvParams[jss::index] =
518 "00000000000000000000000000000000000000000000000000000000000000"
520 auto const jrr = env.
rpc(
521 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
529 jvParams[jss::features] =
530 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
532 jvParams[jss::api_version] = apiVersion;
534 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
542 "No ledger_entry params provided.");
551 using namespace test::jtx;
554 cfg->FEES.reference_fee = 10;
555 Env env{*
this, std::move(cfg)};
565 BEAST_EXPECT(jrr[jss::ledger_hash] ==
ledgerHash);
566 BEAST_EXPECT(jrr[jss::ledger_index] == 3);
573 jvParams[jss::account_root] = alice.human();
576 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
577 BEAST_EXPECT(jrr.
isMember(jss::node));
578 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
579 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"10000000000");
580 accountRootIndex = jrr[jss::index].
asString();
583 constexpr char alicesAcctRootBinary[]{
584 "1100612200800000240000000425000000032D00000000559CE54C3B934E4"
585 "73A995B477E92EC229F99CED5B62BF4D2ACE4DC42719103AE2F6240000002"
586 "540BE4008114AE123A8556F3CF91154711376AFB0F894F832B3D"};
590 jvParams[jss::account_root] = alice.human();
591 jvParams[jss::binary] = 1;
594 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
595 BEAST_EXPECT(jrr.
isMember(jss::node_binary));
596 BEAST_EXPECT(jrr[jss::node_binary] == alicesAcctRootBinary);
601 jvParams[jss::index] = accountRootIndex;
603 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
604 BEAST_EXPECT(!jrr.
isMember(jss::node_binary));
605 BEAST_EXPECT(jrr.
isMember(jss::node));
606 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
607 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"10000000000");
612 jvParams[jss::index] = accountRootIndex;
613 jvParams[jss::binary] = 0;
615 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
616 BEAST_EXPECT(jrr.
isMember(jss::node));
617 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
618 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"10000000000");
623 jvParams[jss::account] = alice.human();
626 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
627 BEAST_EXPECT(jrr.
isMember(jss::node));
628 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
629 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"10000000000");
630 accountRootIndex = jrr[jss::index].
asString();
648 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
657 using namespace test::jtx;
672 jvParams[jss::check] =
to_string(checkId.key);
675 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
677 jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check);
678 BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] ==
"100000000");
686 jvParams[jss::account_root] = alice.human();
688 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
689 accountRootIndex = jrr[jss::index].
asString();
692 jvParams[jss::check] = accountRootIndex;
695 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
697 jrr,
"unexpectedLedgerType",
"Unexpected ledger type.");
710 using namespace test::jtx;
713 Account const issuer{
"issuer"};
716 char const credType[] =
"abcde";
718 env.
fund(
XRP(5000), issuer, alice, bob);
730 !jv[jss::result].
isMember(jss::error) &&
731 jv[jss::result].
isMember(jss::node) &&
732 jv[jss::result][jss::node].
isMember(
733 sfLedgerEntryType.jsonName) &&
734 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] ==
742 !jv[jss::result].
isMember(jss::error) &&
743 jv[jss::result].
isMember(jss::node) &&
744 jv[jss::result][jss::node].
isMember(
745 sfLedgerEntryType.jsonName) &&
746 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] ==
754 "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B"
757 jv[jss::result],
"entryNotFound",
"Entry not found.");
766 {jss::subject,
"malformedRequest"},
767 {jss::issuer,
"malformedRequest"},
768 {jss::credential_type,
"malformedRequest"},
778 using namespace test::jtx;
783 env.
fund(
XRP(10000), alice, bob);
792 jvParams[jss::delegate][jss::account] = alice.human();
793 jvParams[jss::delegate][jss::authorize] = bob.human();
796 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
798 jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate);
799 BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
800 BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == bob.human());
801 delegateIndex = jrr[jss::node][jss::index].
asString();
806 jvParams[jss::delegate] = delegateIndex;
809 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
811 jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate);
812 BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
813 BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == bob.human());
822 {jss::account,
"malformedAddress"},
823 {jss::authorize,
"malformedAddress"},
833 using namespace test::jtx;
839 env.
fund(
XRP(10000), alice, becky);
850 jvParams[jss::deposit_preauth][jss::owner] = alice.human();
851 jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
854 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
857 jrr[jss::node][sfLedgerEntryType.jsonName] ==
858 jss::DepositPreauth);
859 BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
860 BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.human());
861 depositPreauthIndex = jrr[jss::node][jss::index].
asString();
866 jvParams[jss::deposit_preauth] = depositPreauthIndex;
869 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
872 jrr[jss::node][sfLedgerEntryType.jsonName] ==
873 jss::DepositPreauth);
874 BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
875 BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.human());
881 jss::deposit_preauth,
883 {jss::owner,
"malformedOwner"},
884 {jss::authorized,
"malformedAuthorized",
false},
892 testcase(
"Deposit Preauth with credentials");
894 using namespace test::jtx;
897 Account const issuer{
"issuer"};
900 char const credType[] =
"abcde";
902 env.
fund(
XRP(5000), issuer, alice, bob);
916 jvParams[jss::ledger_index] = jss::validated;
917 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
919 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
922 jvParams[jss::deposit_preauth][jss::authorized_credentials]);
925 jo[jss::issuer] = issuer.human();
927 arr.append(std::move(jo));
932 jrr.isObject() && jrr.isMember(jss::result) &&
933 !jrr[jss::result].isMember(jss::error) &&
934 jrr[jss::result].isMember(jss::node) &&
935 jrr[jss::result][jss::node].isMember(
936 sfLedgerEntryType.jsonName) &&
937 jrr[jss::result][jss::node][sfLedgerEntryType.jsonName] ==
938 jss::DepositPreauth);
944 jvParams[jss::ledger_index] = jss::validated;
945 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
947 auto tryField = [&](
Json::Value fieldValue) ->
void {
950 jo[jss::issuer] = fieldValue;
953 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
957 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
958 auto const expectedErrMsg = fieldValue.
isNull()
962 jrr,
"malformedAuthorizedCredentials", expectedErrMsg);
966 for (
auto const& value : badValues)
976 jvParams[jss::ledger_index] = jss::validated;
977 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
979 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
982 jvParams[jss::deposit_preauth][jss::authorized_credentials]);
985 jo[jss::issuer] = issuer.human();
988 arr.append(std::move(jo));
993 "malformedAuthorizedCredentials",
995 jss::authorized_credentials,
"array"));
1001 jvParams[jss::ledger_index] = jss::validated;
1002 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
1004 auto tryField = [&](
Json::Value fieldValue) ->
void {
1007 jo[jss::issuer] = issuer.human();
1008 jo[jss::credential_type] = fieldValue;
1010 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
1014 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1015 auto const expectedErrMsg = fieldValue.
isNull()
1018 jss::credential_type,
"hex string");
1020 jrr,
"malformedAuthorizedCredentials", expectedErrMsg);
1024 for (
auto const& value : badValues)
1034 jvParams[jss::ledger_index] = jss::validated;
1035 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
1036 jvParams[jss::deposit_preauth][jss::authorized] = alice.human();
1038 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
1041 jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1044 jo[jss::issuer] = issuer.human();
1046 arr.append(std::move(jo));
1053 "Must have exactly one of `authorized` and "
1054 "`authorized_credentials`.");
1060 jvParams[jss::ledger_index] = jss::validated;
1061 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
1065 jss::deposit_preauth,
1066 jss::authorized_credentials,
1068 "malformedAuthorizedCredentials",
1075 jvParams[jss::ledger_index] = jss::validated;
1076 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
1077 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
1080 jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1081 arr.append(
"foobar");
1087 "malformedAuthorizedCredentials",
1088 "Invalid field 'authorized_credentials', not array.");
1094 jvParams[jss::ledger_index] = jss::validated;
1095 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
1096 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
1099 jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1102 arr.
append(std::move(payload));
1108 "malformedAuthorizedCredentials",
1109 "Invalid field 'authorized_credentials', not array.");
1115 jvParams[jss::ledger_index] = jss::validated;
1116 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
1117 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
1124 "malformedAuthorizedCredentials",
1125 "Invalid field 'authorized_credentials', not array.");
1141 sizeof(credTypes) /
sizeof(credTypes[0]) >
1145 jvParams[jss::ledger_index] = jss::validated;
1146 jvParams[jss::deposit_preauth][jss::owner] = bob.human();
1147 jvParams[jss::deposit_preauth][jss::authorized_credentials] =
1151 jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1153 for (
auto cred : credTypes)
1156 jo[jss::issuer] = issuer.human();
1158 arr.append(std::move(jo));
1165 "malformedAuthorizedCredentials",
1166 "Invalid field 'authorized_credentials', not array.");
1174 using namespace test::jtx;
1178 auto const USD = gw[
"USD"];
1179 env.
fund(
XRP(10000), alice, gw);
1182 env.
trust(USD(1000), alice);
1187 for (
int d = 1'000'032; d >= 1'000'000; --d)
1197 BEAST_EXPECT(jrr[jss::ledger_hash] ==
ledgerHash);
1198 BEAST_EXPECT(jrr[jss::ledger_index] == 5);
1202 "A33EC6BB85FB5674074C4A3A43373BB17645308F3EAE1933E3E35252162B217D";
1206 jvParams[jss::directory] = dirRootIndex;
1209 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1210 BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].
size() == 32);
1216 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
1218 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1219 BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
1225 jvParams[jss::directory][jss::owner] = alice.human();
1228 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1229 BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
1235 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
1236 jvParams[jss::directory][jss::sub_index] = 1;
1238 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1239 BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
1240 BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].
size() == 2);
1246 jvParams[jss::directory][jss::owner] = alice.human();
1247 jvParams[jss::directory][jss::sub_index] = 1;
1250 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1251 BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
1252 BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].
size() == 2);
1263 "malformedRequest");
1269 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
1299 jvParams[jss::directory][jss::owner] = alice.human();
1300 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
1303 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1307 "Must have exactly one of `owner` and `dir_root` fields.");
1313 jvParams[jss::directory][jss::sub_index] = 1;
1316 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1320 "Must have exactly one of `owner` and `dir_root` fields.");
1328 using namespace test::jtx;
1340 jv[jss::TransactionType] = jss::EscrowCreate;
1341 jv[jss::Account] = account.human();
1342 jv[jss::Destination] = to.human();
1344 jv[sfFinishAfter.jsonName] =
1345 cancelAfter.time_since_epoch().count() + 2;
1349 using namespace std::chrono_literals;
1350 env(escrowCreate(alice, alice,
XRP(333), env.
now() + 2s));
1359 jvParams[jss::escrow][jss::owner] = alice.human();
1360 jvParams[jss::escrow][jss::seq] = env.
seq(alice) - 1;
1362 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1364 jrr[jss::node][jss::Amount] ==
XRP(333).value().getText());
1365 escrowIndex = jrr[jss::index].
asString();
1370 jvParams[jss::escrow] = escrowIndex;
1373 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1375 jrr[jss::node][jss::Amount] ==
XRP(333).value().getText());
1382 {{jss::owner,
"malformedOwner"}, {jss::seq,
"malformedSeq"}});
1390 using namespace test::jtx;
1394 auto const USD = gw[
"USD"];
1395 env.
fund(
XRP(10000), alice, gw);
1398 env(
offer(alice, USD(321),
XRP(322)));
1407 jvParams[jss::offer][jss::account] = alice.human();
1408 jvParams[jss::offer][jss::seq] = env.
seq(alice) - 1;
1411 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1412 BEAST_EXPECT(jrr[jss::node][jss::TakerGets] ==
"322000000");
1413 offerIndex = jrr[jss::index].
asString();
1418 jvParams[jss::offer] = offerIndex;
1420 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1421 BEAST_EXPECT(jrr[jss::node][jss::TakerGets] ==
"322000000");
1429 {{jss::account,
"malformedAddress"},
1430 {jss::seq,
"malformedRequest"}});
1438 using namespace test::jtx;
1453 jv[jss::TransactionType] = jss::PaymentChannelCreate;
1454 jv[jss::Account] = account.human();
1455 jv[jss::Destination] = to.human();
1457 jv[sfSettleDelay.jsonName] = settleDelay.count();
1458 jv[sfPublicKey.jsonName] =
strHex(pk.slice());
1462 env(payChanCreate(alice, env.
master,
XRP(57), 18s, alice.pk()));
1472 jvParams[jss::payment_channel] =
to_string(payChanIndex);
1475 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1476 BEAST_EXPECT(jrr[jss::node][sfAmount.jsonName] ==
"57000000");
1477 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"0");
1478 BEAST_EXPECT(jrr[jss::node][sfSettleDelay.jsonName] == 18);
1486 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1500 using namespace test::jtx;
1504 auto const USD = gw[
"USD"];
1505 env.
fund(
XRP(10000), alice, gw);
1508 env.
trust(USD(999), alice);
1511 env(
pay(gw, alice, USD(97)));
1515 for (
auto const& fieldName : {jss::ripple_state, jss::state})
1523 jvParams[fieldName][jss::accounts][0u] = alice.human();
1524 jvParams[fieldName][jss::accounts][1u] = gw.human();
1525 jvParams[fieldName][jss::currency] =
"USD";
1528 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1530 jrr[jss::node][sfBalance.jsonName][jss::value] ==
"-97");
1532 jrr[jss::node][sfHighLimit.jsonName][jss::value] ==
"999");
1540 {jss::accounts,
"malformedRequest"},
1541 {jss::currency,
"malformedCurrency"},
1549 jvParams[fieldName][jss::accounts][0u] = alice.human();
1550 jvParams[fieldName][jss::currency] =
"USD";
1553 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1557 "Invalid field 'accounts', not length-2 array of "
1565 jvParams[fieldName][jss::accounts][0u] = alice.human();
1566 jvParams[fieldName][jss::accounts][1u] = gw.human();
1567 jvParams[fieldName][jss::accounts][2u] = alice.human();
1568 jvParams[fieldName][jss::currency] =
"USD";
1571 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1575 "Invalid field 'accounts', not length-2 array of "
1582 auto tryField = [&](
Json::Value badAccount) ->
void {
1586 jvParams[fieldName][jss::accounts][0u] = badAccount;
1587 jvParams[fieldName][jss::accounts][1u] = gw.human();
1588 jvParams[fieldName][jss::currency] =
"USD";
1598 jss::accounts,
"array of Accounts"));
1604 jvParams[fieldName][jss::accounts][0u] = alice.human();
1605 jvParams[fieldName][jss::accounts][1u] = badAccount;
1606 jvParams[fieldName][jss::currency] =
"USD";
1616 jss::accounts,
"array of Accounts"));
1621 for (
auto const& value : badValues)
1632 jvParams[fieldName][jss::accounts][0u] = alice.human();
1633 jvParams[fieldName][jss::accounts][1u] = alice.human();
1634 jvParams[fieldName][jss::currency] =
"USD";
1637 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1641 "Cannot have a trustline to self.");
1650 using namespace test::jtx;
1666 jvParams[jss::ticket] =
1670 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1679 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1681 jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Ticket);
1682 BEAST_EXPECT(jrr[jss::node][sfTicketSequence.jsonName] == tkt1);
1688 jvParams[jss::ticket][jss::account] = env.
master.
human();
1689 jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 1;
1692 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1694 jrr[jss::node][jss::index] ==
1701 jvParams[jss::ticket][jss::account] = env.
master.
human();
1702 jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 2;
1705 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1714 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1716 jrr,
"unexpectedLedgerType",
"Unexpected ledger type.");
1725 {jss::account,
"malformedAddress"},
1726 {jss::ticket_seq,
"malformedRequest"},
1735 using namespace test::jtx;
1746 jv[jss::TransactionType] = jss::DIDSet;
1747 jv[jss::Account] = account.human();
1753 env(didCreate(alice));
1761 jvParams[jss::did] = alice.human();
1764 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1766 jrr[jss::node][sfDIDDocument.jsonName] ==
1777 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1788 "malformedAddress");
1795 testcase(
"Invalid Oracle Ledger Entry");
1805 .fee =
static_cast<int>(env.
current()->fees().base.drops())});
1813 {jss::account,
"malformedAccount"},
1814 {jss::oracle_document_id,
"malformedDocumentID"},
1827 auto const baseFee =
1828 static_cast<int>(env.
current()->fees().base.drops());
1831 for (
int i = 0; i < 10; ++i)
1837 env, {.owner = owner, .documentID = i, .fee = baseFee});
1842 env, {.owner = owner, .documentID = i + 10, .fee = baseFee});
1844 oracles.
push_back(oracle1.documentID());
1846 for (
int i = 0; i < accounts.
size(); ++i)
1848 auto const jv = [&]() {
1851 return Oracle::ledgerEntry(env, accounts[i], oracles[i]);
1853 return Oracle::ledgerEntry(
1859 jv[jss::node][jss::Owner] ==
to_string(accounts[i]));
1872 using namespace test::jtx;
1878 MPTTester mptAlice(env, alice, {.holders = {bob}});
1885 mptAlice.authorize({.account = bob, .holderCount = 1});
1890 "00000193B9DDCAF401B5B3B26875986043F82CD0D13B4315";
1894 jvParams[jss::mpt_issuance] =
strHex(mptAlice.issuanceID());
1897 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1899 jrr[jss::node][sfMPTokenMetadata.jsonName] ==
1902 jrr[jss::node][jss::mpt_issuance_id] ==
1903 strHex(mptAlice.issuanceID()));
1908 jvParams[jss::mpt_issuance] = badMptID;
1911 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1918 jvParams[jss::mptoken][jss::account] = bob.
human();
1919 jvParams[jss::mptoken][jss::mpt_issuance_id] =
1920 strHex(mptAlice.issuanceID());
1923 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1925 jrr[jss::node][sfMPTokenIssuanceID.jsonName] ==
1926 strHex(mptAlice.issuanceID()));
1932 jvParams[jss::mptoken][jss::account] = bob.
human();
1933 jvParams[jss::mptoken][jss::mpt_issuance_id] = badMptID;
1936 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1947 "malformedRequest");
1956 using namespace test::jtx;
1959 Account const issuer{
"issuer"};
1963 env.
fund(
XRP(5000), issuer, alice, bob);
1966 auto const seq = env.
seq(alice);
1970 if (!BEAST_EXPECT(objects.size() == 1))
1976 params[jss::ledger_index] = jss::validated;
1977 params[jss::permissioned_domain][jss::account] = alice.human();
1978 params[jss::permissioned_domain][jss::seq] =
seq;
1979 auto jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
1982 !jv[jss::result].
isMember(jss::error) &&
1983 jv[jss::result].
isMember(jss::node) &&
1984 jv[jss::result][jss::node].
isMember(
1985 sfLedgerEntryType.jsonName) &&
1986 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] ==
1987 jss::PermissionedDomain);
1994 params[jss::ledger_index] = jss::validated;
1995 params[jss::permissioned_domain] = pdIdx;
1996 jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
1999 !jv[jss::result].
isMember(jss::error) &&
2000 jv[jss::result].
isMember(jss::node) &&
2001 jv[jss::result][jss::node].
isMember(
2002 sfLedgerEntryType.jsonName) &&
2003 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] ==
2004 jss::PermissionedDomain);
2010 params[jss::ledger_index] = jss::validated;
2011 params[jss::permissioned_domain] =
2012 "12F1F1F1F180D67377B2FAB292A31C922470326268D2B9B74CD1E582645B9A"
2014 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2016 jrr[jss::result],
"entryNotFound",
"Entry not found.");
2022 jss::permissioned_domain,
2024 {jss::account,
"malformedAddress"},
2025 {jss::seq,
"malformedRequest"},
2034 using namespace test::jtx;
2050 env.
rpc(
"ledger_entry",
to_string(checkId.key))[jss::result];
2052 jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check);
2053 BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] ==
"100000000");
2092 if (BEAST_EXPECT(jv.
isMember(jss::status)))
2093 BEAST_EXPECT(jv[jss::status] ==
"error");
2094 if (BEAST_EXPECT(jv.
isMember(jss::error)))
2095 BEAST_EXPECT(jv[jss::error] == err);
2100 jv[jss::error_message] ==
"");
2102 else if (BEAST_EXPECT(jv.
isMember(jss::error_message)))
2103 BEAST_EXPECT(jv[jss::error_message] == msg);
2110 using namespace test::jtx;
2124 jvParams[jss::bridge] =
jvb;
2126 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
2128 BEAST_EXPECT(jrr.
isMember(jss::node));
2129 auto r = jrr[jss::node];
2131 BEAST_EXPECT(r.isMember(jss::Account));
2134 BEAST_EXPECT(r.isMember(jss::Flags));
2136 BEAST_EXPECT(r.isMember(sfLedgerEntryType.jsonName));
2137 BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::Bridge);
2140 BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName));
2141 BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 0);
2144 BEAST_EXPECT(r.isMember(sfXChainAccountClaimCount.jsonName));
2145 BEAST_EXPECT(r[sfXChainAccountClaimCount.jsonName].asInt() == 0);
2147 BEAST_EXPECT(r.isMember(jss::index));
2148 bridge_index = r[jss::index].asString();
2154 jvParams[jss::index] = bridge_index;
2156 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
2158 BEAST_EXPECT(jrr.
isMember(jss::node));
2159 BEAST_EXPECT(jrr[jss::node] == mcBridge);
2166 jvParams[jss::bridge] =
jvb;
2169 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
2184 jvParams[jss::bridge] =
jvb;
2186 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
2188 BEAST_EXPECT(jrr.
isMember(jss::node));
2189 auto r = jrr[jss::node];
2192 BEAST_EXPECT(r.isMember(sfXChainClaimID.jsonName));
2193 BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2);
2200 testcase(
"ledger_entry: xchain_claim_id");
2201 using namespace test::jtx;
2218 jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] =
2221 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
2223 BEAST_EXPECT(jrr.
isMember(jss::node));
2224 auto r = jrr[jss::node];
2226 BEAST_EXPECT(r.isMember(jss::Account));
2229 r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID);
2230 BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 1);
2231 BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0);
2238 jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] =
2241 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
2243 BEAST_EXPECT(jrr.
isMember(jss::node));
2244 auto r = jrr[jss::node];
2246 BEAST_EXPECT(r.isMember(jss::Account));
2247 BEAST_EXPECT(r[jss::Account] ==
scBob.
human());
2249 r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID);
2250 BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2);
2251 BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0);
2258 testcase(
"ledger_entry: xchain_create_account_claim_id");
2259 using namespace test::jtx;
2270 auto const amt =
XRP(1000);
2277 size_t constexpr num_attest = 3;
2290 for (
size_t i = 0; i < num_attest; ++i)
2292 scEnv(attestations[i]);
2299 jvParams[jss::xchain_owned_create_account_claim_id] =
2301 jvParams[jss::xchain_owned_create_account_claim_id]
2302 [jss::xchain_owned_create_account_claim_id] = 1;
2304 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
2306 BEAST_EXPECT(jrr.
isMember(jss::node));
2307 auto r = jrr[jss::node];
2309 BEAST_EXPECT(r.isMember(jss::Account));
2312 BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName));
2313 BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 1);
2316 r.isMember(sfXChainCreateAccountAttestations.jsonName));
2317 auto attest = r[sfXChainCreateAccountAttestations.jsonName];
2318 BEAST_EXPECT(attest.isArray());
2319 BEAST_EXPECT(attest.size() == 3);
2321 sfXChainCreateAccountProofSig.jsonName));
2323 for (
size_t i = 0; i < num_attest; ++i)
2326 [sfXChainCreateAccountProofSig.jsonName];
2328 a[i].isMember(jss::Amount) &&
2331 a[i].isMember(jss::Destination) &&
2334 a[i].isMember(sfAttestationSignerAccount.jsonName) &&
2337 return a[i][sfAttestationSignerAccount.jsonName] ==
2341 a[i].isMember(sfAttestationRewardAccount.jsonName) &&
2346 return a[i][sfAttestationRewardAccount.jsonName] ==
2350 a[i].isMember(sfWasLockingChainSend.jsonName) &&
2351 a[i][sfWasLockingChainSend.jsonName] == 1);
2353 a[i].isMember(sfSignatureReward.jsonName) &&
2354 a[i][sfSignatureReward.jsonName].
asInt() ==
2363 scEnv(attestations[i]);
2369 jvParams[jss::xchain_owned_create_account_claim_id] =
2371 jvParams[jss::xchain_owned_create_account_claim_id]
2372 [jss::xchain_owned_create_account_claim_id] = 1;
2374 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
Lightweight wrapper to tag static string.
constexpr char const * c_str() const
Value & append(Value const &value)
Append value to array at the end.
UInt size() const
Number of values in array or object.
std::string toStyledString() const
void clear()
Remove all object members and array elements.
Value removeMember(char const *key)
Remove and return the named member.
std::string asString() const
Returns the unquoted string value.
bool isNull() const
isNull() tests to see if this field is null.
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.
void testLedgerEntryCreateAccountClaimID()
void testLedgerEntryBridge()
void testLedgerEntryClaimID()
void checkErrorValue(Json::Value const &jv, std::string const &err, std::string const &msg)
void run() override
Runs the suite.
void runLedgerEntryTest(test::jtx::Env &env, Json::StaticString const &parentField, source_location const location=source_location::current())
void testLedgerEntryDelegate()
void testInvalidOracleLedgerEntry()
void testLedgerEntryTicket()
void testLedgerEntryCheck()
void testLedgerEntryOffer()
void testLedgerEntryDepositPreauthCred()
void testLedgerEntryMPT()
std::vector< Json::Value > getBadValues(FieldType fieldType)
void testLedgerEntryDepositPreauth()
void testLedgerEntryPermissionedDomain()
void testOracleLedgerEntry()
void testMalformedSubfield(test::jtx::Env &env, Json::Value correctRequest, Json::StaticString parentFieldName, Json::StaticString fieldName, FieldType typeID, std::string const &expectedError, bool required=true, source_location const location=source_location::current())
void testLedgerEntryAccountRoot()
void testLedgerEntryDID()
void runLedgerEntryTest(test::jtx::Env &env, Json::StaticString const &parentField, std::vector< Subfield > const &subfields, source_location const location=source_location::current())
void testLedgerEntryRippleState()
void checkErrorValue(Json::Value const &jv, std::string const &err, std::string const &msg, source_location const location=source_location::current())
void testLedgerEntryDirectory()
void testLedgerEntryInvalid()
void testLedgerEntryCLI()
Json::Value getCorrectValue(Json::StaticString fieldName)
void run() override
Runs the suite.
void testLedgerEntryPayChan()
void testLedgerEntryEscrow()
void testMalformedField(test::jtx::Env &env, Json::Value correctRequest, Json::StaticString const fieldName, FieldType const typeID, std::string const &expectedError, bool required=true, source_location const location=source_location::current())
void testLedgerEntryCredentials()
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
static Account const master
The master account.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
NetClock::time_point now()
Returns the current network time.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
void create(MPTCreate const &arg=MPTCreate{})
Oracle class facilitates unit-testing of the Price Oracle feature.
Set the expected result code for a JTx The test will fail if the code doesn't match.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
std::string missing_field_message(std::string const &name)
std::string expected_field_message(std::string const &name, std::string const &type)
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Json::Value create(A const &account, A const &dest, STAmount const &sendMax)
Create a check.
Json::Value create(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Json::Value ledgerEntry(jtx::Env &env, jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Json::Value set(jtx::Account const &account, jtx::Account const &authorize, std::vector< std::string > const &permissions)
Json::Value auth(Account const &account, Account const &auth)
Preauthorize for deposit.
Json::Value authCredentials(jtx::Account const &account, std::vector< AuthorizeCredentials > const &auth)
Json::Value setTx(AccountID const &account, Credentials const &credentials, std::optional< uint256 > domain)
std::map< uint256, Json::Value > getObjects(Account const &account, Env &env, bool withType)
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value sidechain_xchain_account_create(Account const &acc, Json::Value const &bridge, Account const &dst, AnyAmount const &amt, AnyAmount const &reward)
constexpr std::size_t UT_XCHAIN_DEFAULT_NUM_SIGNERS
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
JValueVec create_account_attestations(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::AnyAmount const &rewardAmount, std::vector< jtx::Account > const &rewardAccounts, bool wasLockingChainSend, std::uint64_t createCount, jtx::Account const &dst, std::vector< jtx::signer > const &signers, std::size_t const numAtts, std::size_t const fromIdx)
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
require_t required(Args const &... args)
Compose many condition functors into one.
FeatureBitset testable_amendments()
Json::Value xchain_create_claim_id(Account const &acc, Json::Value const &bridge, STAmount const &reward, Account const &otherChainSource)
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
XRP_t const XRP
Converts to XRP Issue or STAmount.
static uint256 ledgerHash(LedgerInfo const &info)
std::vector< std::pair< Json::StaticString, FieldType > > mappings
FieldType getFieldType(Json::StaticString fieldName)
std::string getTypeName(FieldType typeID)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t asfDepositAuth
constexpr std::uint32_t const tfMPTCanTransfer
constexpr std::uint32_t const tfMPTCanTrade
std::string strHex(FwdIt begin, FwdIt end)
std::size_t constexpr maxCredentialsArraySize
The maximum number of credentials can be passed in array.
void forAllApiVersions(Fn const &fn, Args &&... args)
uint256 getTicketIndex(AccountID const &account, std::uint32_t uSequence)
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t const tfMPTCanEscrow
constexpr std::uint32_t const tfMPTRequireAuth
constexpr std::uint32_t const tfMPTCanLock
constexpr std::uint32_t const tfMPTCanClawback
Json::StaticString fieldName
std::string malformedErrorMsg
std::vector< Account > const payee
static constexpr int drop_per_xrp
FeatureBitset const features
std::vector< signer > const signers
void createBridgeObjects(Env &mcEnv, Env &scEnv)
Json::Value const jvXRPBridgeRPC
Set the sequence number on a JTx.
A signer in a SignerList.