1#include <test/jtx/AMM.h>
2#include <test/jtx/Account.h>
3#include <test/jtx/Env.h>
4#include <test/jtx/Oracle.h>
5#include <test/jtx/TestHelpers.h>
6#include <test/jtx/amount.h>
7#include <test/jtx/attester.h>
8#include <test/jtx/credentials.h>
9#include <test/jtx/delegate.h>
10#include <test/jtx/deposit.h>
11#include <test/jtx/envconfig.h>
12#include <test/jtx/flags.h>
13#include <test/jtx/mpt.h>
14#include <test/jtx/multisign.h>
15#include <test/jtx/offer.h>
16#include <test/jtx/pay.h>
17#include <test/jtx/permissioned_domains.h>
18#include <test/jtx/ticket.h>
19#include <test/jtx/token.h>
20#include <test/jtx/txflags.h>
21#include <test/jtx/xchain_bridge.h>
23#include <xrpl/basics/Number.h>
24#include <xrpl/basics/StringUtilities.h>
25#include <xrpl/basics/base_uint.h>
26#include <xrpl/basics/chrono.h>
27#include <xrpl/basics/contract.h>
28#include <xrpl/basics/strHex.h>
29#include <xrpl/beast/unit_test/suite.h>
30#include <xrpl/beast/utility/Journal.h>
31#include <xrpl/core/ServiceRegistry.h>
32#include <xrpl/core/StartUpType.h>
33#include <xrpl/json/json_value.h>
34#include <xrpl/json/to_string.h>
35#include <xrpl/ledger/OpenView.h>
36#include <xrpl/protocol/AccountID.h>
37#include <xrpl/protocol/ApiVersion.h>
38#include <xrpl/protocol/Asset.h>
39#include <xrpl/protocol/ErrorCodes.h>
40#include <xrpl/protocol/Feature.h>
41#include <xrpl/protocol/Indexes.h>
42#include <xrpl/protocol/Keylet.h>
43#include <xrpl/protocol/Protocol.h>
44#include <xrpl/protocol/SField.h>
45#include <xrpl/protocol/STArray.h>
46#include <xrpl/protocol/STVector256.h>
47#include <xrpl/protocol/STXChainBridge.h>
48#include <xrpl/protocol/TxFlags.h>
49#include <xrpl/protocol/jss.h>
58#include <source_location>
104 gMappings, [&fieldName](
auto const& pair) {
return pair.first == fieldName; });
130 return "hex string or object";
134 return "length-2 array of Accounts";
153 if (BEAST_EXPECT(jv.
isMember(jss::status)))
154 BEAST_EXPECTS(jv[jss::status] ==
"error",
std::to_string(location.line()));
155 if (BEAST_EXPECT(jv.
isMember(jss::error)))
158 jv[jss::error] == err,
159 "Expected error " + err +
", received " + jv[jss::error].asString() +
", at line " +
166 "Expected no error message, received \"" + jv[jss::error_message].asString() +
169 else if (BEAST_EXPECT(jv.
isMember(jss::error_message)))
172 jv[jss::error_message] == msg,
173 "Expected error message \"" + msg +
"\", received \"" +
174 jv[jss::error_message].asString() +
"\", at line " +
184 obj[jss::account] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
185 obj[jss::ledger_index] =
"validated";
190 arr[0u] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
191 arr[1u] =
"validated";
205 "0123456789ABCDEFGH",
206 "rJxKV9e9p6wiPw!!!!xrJ4X1n98LosPL1sgcJW",
207 "rPSTrR5yEr11uMkfsz1kHCp9jK4aoa3Avv",
208 "n9K2isxwTxcSHJKxMkJznDoWXAUs7NNy49H9Fknz1pC7oHAH3kH9",
211 "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6B01403D"
233 static auto const& kBadAccountValues = remove({12});
234 static auto const& kBadArrayValues = remove({17, 20});
235 static auto const& kBadBlobValues = remove({3, 7, 8, 16});
236 static auto const& kBadCurrencyValues = remove({14});
237 static auto const& kBadHashValues = remove({2, 3, 7, 8, 16});
238 static auto const& kBadFixedHashValues = remove({1, 2, 3, 4, 7, 8, 16});
239 static auto const& kBadIndexValues = remove({12, 16, 18, 19});
240 static auto const& kBadUInt32Values = remove({2, 3});
241 static auto const& kBadUInt64Values = remove({2, 3});
242 static auto const& kBadIssueValues = remove({});
247 return kBadAccountValues;
250 return kBadArrayValues;
252 return kBadBlobValues;
254 return kBadCurrencyValues;
256 return kBadHashValues;
258 return kBadIndexValues;
260 return kBadFixedHashValues;
262 return kBadIssueValues;
264 return kBadUInt32Values;
266 return kBadUInt64Values;
269 "unknown type " +
std::to_string(
static_cast<uint8_t
>(fieldType)));
278 arr[0u] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
279 arr[1u] =
"r4MrUGTdB57duTnRs6KbsRGQXgkseGb1b5";
284 arr[jss::currency] =
"XRP";
292 return "r4MrUGTdB57duTnRs6KbsRGQXgkseGb1b5";
300 return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6"
305 return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6"
308 return kTwoAccountArray;
333 apiVersion,
"json",
"ledger_entry",
to_string(correctRequest))[jss::result];
341 jrr,
"invalidParams",
"No ledger_entry params provided.", location);
344 auto tryField = [&](
json::Value fieldValue) ->
void {
345 correctRequest[fieldName] = fieldValue;
347 apiVersion,
"json",
"ledger_entry",
to_string(correctRequest))[jss::result];
348 auto const expectedErrMsg =
354 for (
auto const& value : badValues)
379 correctRequest[parentFieldName].
removeMember(fieldName);
381 apiVersion,
"json",
"ledger_entry",
to_string(correctRequest))[jss::result];
387 apiVersion,
"json",
"ledger_entry",
to_string(correctRequest))[jss::result];
391 auto tryField = [&](
json::Value fieldValue) ->
void {
392 correctRequest[parentFieldName][fieldName] = fieldValue;
395 apiVersion,
"json",
"ledger_entry",
to_string(correctRequest))[jss::result];
404 for (
auto const& value : badValues)
453 for (
auto const& subfield : subfields)
455 correctOutput[parentField][subfield.fieldName] =
getCorrectValue(subfield.fieldName);
458 for (
auto const& subfield : subfields)
460 auto const fieldType =
getFieldType(subfield.fieldName);
467 subfield.malformedErrorMsg,
485 jvParams[jss::account_root] = alice.
human();
486 jvParams[jss::ledger_hash] =
487 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
489 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
495 jvParams[jss::account_root] = alice.
human();
499 auto tryField = [&](
json::Value fieldValue) ->
void {
500 jvParams[jss::ledger_hash] = fieldValue;
502 apiVersion,
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
504 jrr,
"invalidParams",
"Invalid field 'ledger_hash', not hex string.");
508 for (
auto const& value : badValues)
518 jvParams[jss::ledger_index] =
"validated";
519 jvParams[jss::index] =
520 "00000000000000000000000000000000000000000000000000000000000000"
522 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
530 jvParams[jss::features] =
531 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
533 jvParams[jss::api_version] = apiVersion;
535 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
543 checkErrorValue(jrr,
"invalidParams",
"No ledger_entry params provided.");
556 cfg->fees.referenceFee = 10;
557 Env env{*
this, std::move(cfg)};
567 BEAST_EXPECT(jrr[jss::ledger_hash] ==
ledgerHash);
568 BEAST_EXPECT(jrr[jss::ledger_index] == 3);
575 jvParams[jss::account_root] = alice.
human();
578 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
579 BEAST_EXPECT(jrr.
isMember(jss::node));
580 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.
human());
581 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"10000000000");
582 accountRootIndex = jrr[jss::index].
asString();
585 static constexpr char kAliceAcctRootBinary[]{
586 "1100612200800000240000000425000000032D00000000559CE54C3B934E4"
587 "73A995B477E92EC229F99CED5B62BF4D2ACE4DC42719103AE2F6240000002"
588 "540BE4008114AE123A8556F3CF91154711376AFB0F894F832B3D"};
592 jvParams[jss::account_root] = alice.
human();
593 jvParams[jss::binary] = 1;
596 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
597 BEAST_EXPECT(jrr.
isMember(jss::node_binary));
598 BEAST_EXPECT(jrr[jss::node_binary] == kAliceAcctRootBinary);
603 jvParams[jss::index] = accountRootIndex;
605 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
606 BEAST_EXPECT(!jrr.
isMember(jss::node_binary));
607 BEAST_EXPECT(jrr.
isMember(jss::node));
608 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.
human());
609 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"10000000000");
614 jvParams[jss::index] = accountRootIndex;
615 jvParams[jss::binary] = 0;
617 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
618 BEAST_EXPECT(jrr.
isMember(jss::node));
619 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.
human());
620 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"10000000000");
625 jvParams[jss::account] = alice.
human();
628 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
629 BEAST_EXPECT(jrr.
isMember(jss::node));
630 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.
human());
631 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"10000000000");
632 accountRootIndex = jrr[jss::index].
asString();
643 jvParams[jss::account_root] =
Account(
"bob").human();
646 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
672 "42426C4D4F1009EE67080A9B7965B44656D7"
673 "714D104A72F9B4369F97ABF044EE"));
676 "4C97EBA926031A7CF7D7B36FDE3ED66DDA54"
677 "21192D63DE53FFB46E43B9DC8373"));
680 "03BDC0099C4E14163ADA272C1B6F6FABB448"
681 "CC3E51F522F978041E4B57D9158C"));
684 "35291ADD2D79EB6991343BDA0912269C817D"
685 "0F094B02226C1C14AD2858962ED4"));
686 sle->setFieldV256(sfAmendments,
STVector256(enabledAmendments));
692 majority1.setFieldH256(
695 "7BB62DC13EC72B775091E9C71BF8CF97E122"
696 "647693B50C5E87A80DFD6FCFAC50"));
697 majority1.setFieldU32(sfCloseTime, 779561310);
698 majorities.
pushBack(std::move(majority1));
701 majority2.setFieldH256(
704 "755C971C29971C9F20C6F080F2ED96F87884"
705 "E40AD19554A5EBECDCEC8A1F77FE"));
706 majority2.setFieldU32(sfCloseTime, 779561310);
707 majorities.
pushBack(std::move(majority2));
709 sle->setFieldArray(sfMajorities, majorities);
720 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
721 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Amendments);
743 AMM const amm(env, alice,
XRP(10), usd(1000));
749 auto const result = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
751 result.isObject() && result.isMember(jss::result) &&
752 !result[jss::result].isMember(jss::error) &&
753 result[jss::result].isMember(jss::node) &&
754 result[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) &&
755 result[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::AMM);
763 obj[jss::currency] =
"XRP";
764 ammParams[jss::asset] = obj;
768 ammParams[jss::asset2] =
toJson(usd.
raw());
770 jvParams[jss::amm] = ammParams;
771 auto const result = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
773 result.isObject() && result.isMember(jss::result) &&
774 !result[jss::result].isMember(jss::error) &&
775 result[jss::result].isMember(jss::node) &&
776 result[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) &&
777 result[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::AMM);
785 {.fieldName = jss::asset, .malformedErrorMsg =
"malformedRequest"},
786 {.fieldName = jss::asset2, .malformedErrorMsg =
"malformedRequest"},
789 auto getIOU = [&](
Env& env) ->
PrettyAsset {
return alice[
"USD"]; };
791 return MPTTester({.env = env, .issuer = alice});
816 jvParams[jss::check] =
to_string(checkId.key);
819 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
820 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check);
821 BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] ==
"100000000");
829 jvParams[jss::account_root] = alice.
human();
831 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
832 accountRootIndex = jrr[jss::index].
asString();
835 jvParams[jss::check] = accountRootIndex;
838 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
839 checkErrorValue(jrr,
"unexpectedLedgerType",
"Unexpected ledger type.");
855 Account const issuer{
"issuer"};
858 char const credType[] =
"abcde";
860 env.
fund(
XRP(5000), issuer, alice, bob);
872 !jv[jss::result].
isMember(jss::error) && jv[jss::result].
isMember(jss::node) &&
873 jv[jss::result][jss::node].
isMember(sfLedgerEntryType.jsonName) &&
874 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::Credential);
881 !jv[jss::result].
isMember(jss::error) && jv[jss::result].
isMember(jss::node) &&
882 jv[jss::result][jss::node].
isMember(sfLedgerEntryType.jsonName) &&
883 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::Credential);
890 "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B"
901 {.fieldName = jss::subject, .malformedErrorMsg =
"malformedRequest"},
902 {.fieldName = jss::issuer, .malformedErrorMsg =
"malformedRequest"},
903 {.fieldName = jss::credential_type, .malformedErrorMsg =
"malformedRequest"},
918 env.
fund(
XRP(10000), alice, bob);
927 jvParams[jss::delegate][jss::account] = alice.
human();
928 jvParams[jss::delegate][jss::authorize] = bob.
human();
931 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
932 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate);
933 BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.
human());
934 BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == bob.
human());
935 delegateIndex = jrr[jss::node][jss::index].
asString();
940 jvParams[jss::delegate] = delegateIndex;
943 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
944 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate);
945 BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.
human());
946 BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == bob.
human());
955 {.fieldName = jss::account, .malformedErrorMsg =
"malformedAddress"},
956 {.fieldName = jss::authorize, .malformedErrorMsg =
"malformedAddress"},
972 env.
fund(
XRP(10000), alice, becky);
983 jvParams[jss::deposit_preauth][jss::owner] = alice.
human();
984 jvParams[jss::deposit_preauth][jss::authorized] = becky.
human();
987 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
989 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::DepositPreauth);
990 BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.
human());
991 BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.
human());
992 depositPreauthIndex = jrr[jss::node][jss::index].
asString();
997 jvParams[jss::deposit_preauth] = depositPreauthIndex;
1000 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1002 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::DepositPreauth);
1003 BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.
human());
1004 BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.
human());
1010 jss::deposit_preauth,
1012 {.fieldName = jss::owner, .malformedErrorMsg =
"malformedOwner"},
1013 {.fieldName = jss::authorized,
1014 .malformedErrorMsg =
"malformedAuthorized",
1023 testcase(
"Deposit Preauth with credentials");
1028 Account const issuer{
"issuer"};
1031 char const credType[] =
"abcde";
1033 env.
fund(
XRP(5000), issuer, alice, bob);
1038 env(
fset(bob, asfDepositAuth));
1047 jvParams[jss::ledger_index] = jss::validated;
1048 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1051 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1054 jo[jss::issuer] = issuer.
human();
1056 arr.append(std::move(jo));
1057 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
1060 jrr.isObject() && jrr.isMember(jss::result) &&
1061 !jrr[jss::result].isMember(jss::error) && jrr[jss::result].isMember(jss::node) &&
1062 jrr[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) &&
1063 jrr[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::DepositPreauth);
1069 jvParams[jss::ledger_index] = jss::validated;
1070 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1072 auto tryField = [&](
json::Value fieldValue) ->
void {
1075 jo[jss::issuer] = fieldValue;
1078 jvParams[jss::deposit_preauth][jss::authorized_credentials] = arr;
1081 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1082 auto const expectedErrMsg = fieldValue.
isNull()
1085 checkErrorValue(jrr,
"malformedAuthorizedCredentials", expectedErrMsg);
1089 for (
auto const& value : badValues)
1099 jvParams[jss::ledger_index] = jss::validated;
1100 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1103 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1106 jo[jss::issuer] = issuer.
human();
1109 arr.append(std::move(jo));
1110 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
1113 "malformedAuthorizedCredentials",
1120 jvParams[jss::ledger_index] = jss::validated;
1121 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1123 auto tryField = [&](
json::Value fieldValue) ->
void {
1126 jo[jss::issuer] = issuer.
human();
1127 jo[jss::credential_type] = fieldValue;
1129 jvParams[jss::deposit_preauth][jss::authorized_credentials] = arr;
1132 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1133 auto const expectedErrMsg = fieldValue.
isNull()
1136 checkErrorValue(jrr,
"malformedAuthorizedCredentials", expectedErrMsg);
1140 for (
auto const& value : badValues)
1150 jvParams[jss::ledger_index] = jss::validated;
1151 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1152 jvParams[jss::deposit_preauth][jss::authorized] = alice.
human();
1155 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1158 jo[jss::issuer] = issuer.
human();
1160 arr.append(std::move(jo));
1162 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
1166 "Must have exactly one of `authorized` and "
1167 "`authorized_credentials`.");
1173 jvParams[jss::ledger_index] = jss::validated;
1174 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1178 jss::deposit_preauth,
1179 jss::authorized_credentials,
1181 "malformedAuthorizedCredentials",
1188 jvParams[jss::ledger_index] = jss::validated;
1189 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1191 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1192 arr.append(
"foobar");
1194 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
1197 "malformedAuthorizedCredentials",
1198 "Invalid field 'authorized_credentials', not array of objects.");
1204 jvParams[jss::ledger_index] = jss::validated;
1205 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1207 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1210 arr.
append(std::move(payload));
1212 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
1215 "malformedAuthorizedCredentials",
1216 "Invalid field 'authorized_credentials', not array of objects.");
1222 jvParams[jss::ledger_index] = jss::validated;
1223 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1226 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
1229 "malformedAuthorizedCredentials",
1230 "Invalid field 'authorized_credentials', array empty.");
1236 "cred1",
"cred2",
"cred3",
"cred4",
"cred5",
"cred6",
"cred7",
"cred8",
"cred9"};
1240 jvParams[jss::ledger_index] = jss::validated;
1241 jvParams[jss::deposit_preauth][jss::owner] = bob.
human();
1244 auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]);
1246 for (
auto cred : kCredTypes)
1249 jo[jss::issuer] = issuer.
human();
1251 arr.append(std::move(jo));
1254 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(jvParams));
1257 "malformedAuthorizedCredentials",
1258 "Invalid field 'authorized_credentials', array too long.");
1270 auto const usd = gw[
"USD"];
1271 env.
fund(
XRP(10000), alice, gw);
1274 env.
trust(usd(1000), alice);
1279 for (
int d = 1'000'032; d >= 1'000'000; --d)
1289 BEAST_EXPECT(jrr[jss::ledger_hash] ==
ledgerHash);
1290 BEAST_EXPECT(jrr[jss::ledger_index] == 5);
1294 "A33EC6BB85FB5674074C4A3A43373BB17645308F3EAE1933E3E35252162B217D";
1298 jvParams[jss::directory] = dirRootIndex;
1301 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1302 BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].
size() == 32);
1308 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
1310 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1311 BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
1317 jvParams[jss::directory][jss::owner] = alice.
human();
1320 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1321 BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
1327 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
1328 jvParams[jss::directory][jss::sub_index] = 1;
1330 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1331 BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
1332 BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].
size() == 2);
1338 jvParams[jss::directory][jss::owner] = alice.
human();
1339 jvParams[jss::directory][jss::sub_index] = 1;
1342 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1343 BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
1344 BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].
size() == 2);
1357 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
1387 jvParams[jss::directory][jss::owner] = alice.
human();
1388 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
1391 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1393 jrr,
"malformedRequest",
"Must have exactly one of `owner` and `dir_root` fields.");
1399 jvParams[jss::directory][jss::sub_index] = 1;
1402 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1404 jrr,
"malformedRequest",
"Must have exactly one of `owner` and `dir_root` fields.");
1424 jv[jss::TransactionType] = jss::EscrowCreate;
1425 jv[jss::Account] = account.human();
1426 jv[jss::Destination] = to.human();
1428 jv[sfFinishAfter.jsonName] = cancelAfter.time_since_epoch().count() + 2;
1432 using namespace std::chrono_literals;
1433 env(escrowCreate(alice, alice,
XRP(333), env.
now() + 2s));
1442 jvParams[jss::escrow][jss::owner] = alice.
human();
1443 jvParams[jss::escrow][jss::seq] = env.
seq(alice) - 1;
1445 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1446 BEAST_EXPECT(jrr[jss::node][jss::Amount] ==
XRP(333).value().getText());
1447 escrowIndex = jrr[jss::index].
asString();
1452 jvParams[jss::escrow] = escrowIndex;
1455 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1456 BEAST_EXPECT(jrr[jss::node][jss::Amount] ==
XRP(333).value().getText());
1463 {{.fieldName = jss::owner, .malformedErrorMsg =
"malformedOwner"},
1464 {.fieldName = jss::seq, .malformedErrorMsg =
"malformedSeq"}});
1481 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1482 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::FeeSettings);
1503 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1504 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::LedgerHashes);
1520 Account const issuer{
"issuer"};
1522 env.
fund(
XRP(1000), issuer, buyer);
1534 jvParams[jss::nft_offer] =
to_string(offerID);
1536 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1537 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::NFTokenOffer);
1538 BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == issuer.
human());
1539 BEAST_EXPECT(jrr[jss::node][sfNFTokenID.jsonName] ==
to_string(nftokenID0));
1540 BEAST_EXPECT(jrr[jss::node][sfAmount.jsonName] ==
"1");
1555 Account const issuer{
"issuer"};
1562 BEAST_EXPECT(env.
le(nftpage) !=
nullptr);
1566 jvParams[jss::nft_page] =
to_string(nftpage.key);
1568 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1569 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
1597 "ED58F6770DB5DD77E59D28CB650EC3816E2FC95021BB56E720C9A1"
1599 disabledValidator.setFieldVL(sfPublicKey, *pubKeyBlob);
1600 disabledValidator.setFieldU32(sfFirstLedgerSequence, 91371264);
1601 disabledValidators.
pushBack(std::move(disabledValidator));
1603 sle->setFieldArray(sfDisabledValidators, disabledValidators);
1607 "8D47FFE664BE6C335108DF689537625855A6"
1608 "A95160CC6D351341B9"
1610 sle->setFieldU32(sfPreviousTxnLgrSeq, 91442944);
1621 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1622 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::NegativeUNL);
1638 auto const usd = gw[
"USD"];
1639 env.
fund(
XRP(10000), alice, gw);
1642 env(
offer(alice, usd(321),
XRP(322)));
1651 jvParams[jss::offer][jss::account] = alice.
human();
1652 jvParams[jss::offer][jss::seq] = env.
seq(alice) - 1;
1655 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1656 BEAST_EXPECT(jrr[jss::node][jss::TakerGets] ==
"322000000");
1657 offerIndex = jrr[jss::index].
asString();
1662 jvParams[jss::offer] = offerIndex;
1664 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1665 BEAST_EXPECT(jrr[jss::node][jss::TakerGets] ==
"322000000");
1673 {{.fieldName = jss::account, .malformedErrorMsg =
"malformedAddress"},
1674 {.fieldName = jss::seq, .malformedErrorMsg =
"malformedRequest"}});
1697 jv[jss::TransactionType] = jss::PaymentChannelCreate;
1698 jv[jss::Account] = account.human();
1699 jv[jss::Destination] = to.human();
1701 jv[sfSettleDelay.jsonName] = settleDelay.count();
1702 jv[sfPublicKey.jsonName] =
strHex(pk.slice());
1706 env(payChanCreate(alice, env.
master,
XRP(57), 18s, alice.
pk()));
1715 jvParams[jss::payment_channel] =
to_string(payChanIndex);
1718 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1719 BEAST_EXPECT(jrr[jss::node][sfAmount.jsonName] ==
"57000000");
1720 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] ==
"0");
1721 BEAST_EXPECT(jrr[jss::node][sfSettleDelay.jsonName] == 18);
1729 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1747 auto const usd = gw[
"USD"];
1748 env.
fund(
XRP(10000), alice, gw);
1751 env.
trust(usd(999), alice);
1754 env(
pay(gw, alice, usd(97)));
1758 for (
auto const& fieldName : {jss::ripple_state, jss::state})
1766 jvParams[fieldName][jss::accounts][0u] = alice.
human();
1767 jvParams[fieldName][jss::accounts][1u] = gw.
human();
1768 jvParams[fieldName][jss::currency] =
"USD";
1771 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1772 BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName][jss::value] ==
"-97");
1773 BEAST_EXPECT(jrr[jss::node][sfHighLimit.jsonName][jss::value] ==
"999");
1781 {.fieldName = jss::accounts, .malformedErrorMsg =
"malformedRequest"},
1782 {.fieldName = jss::currency, .malformedErrorMsg =
"malformedCurrency"},
1790 jvParams[fieldName][jss::accounts][0u] = alice.
human();
1791 jvParams[fieldName][jss::currency] =
"USD";
1794 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1798 "Invalid field 'accounts', not length-2 array of "
1806 jvParams[fieldName][jss::accounts][0u] = alice.
human();
1807 jvParams[fieldName][jss::accounts][1u] = gw.
human();
1808 jvParams[fieldName][jss::accounts][2u] = alice.
human();
1809 jvParams[fieldName][jss::currency] =
"USD";
1812 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1816 "Invalid field 'accounts', not length-2 array of "
1823 auto tryField = [&](
json::Value badAccount) ->
void {
1827 jvParams[fieldName][jss::accounts][0u] = badAccount;
1828 jvParams[fieldName][jss::accounts][1u] = gw.
human();
1829 jvParams[fieldName][jss::currency] =
"USD";
1832 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1842 jvParams[fieldName][jss::accounts][0u] = alice.
human();
1843 jvParams[fieldName][jss::accounts][1u] = badAccount;
1844 jvParams[fieldName][jss::currency] =
"USD";
1847 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1856 for (
auto const& value : badValues)
1867 jvParams[fieldName][jss::accounts][0u] = alice.
human();
1868 jvParams[fieldName][jss::accounts][1u] = alice.
human();
1869 jvParams[fieldName][jss::currency] =
"USD";
1872 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1873 checkErrorValue(jrr,
"malformedRequest",
"Cannot have a trustline to self.");
1910 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1919 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1920 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Ticket);
1921 BEAST_EXPECT(jrr[jss::node][sfTicketSequence.jsonName] == tkt1);
1927 jvParams[jss::ticket][jss::account] = env.
master.
human();
1928 jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 1;
1931 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1939 jvParams[jss::ticket][jss::account] = env.
master.
human();
1940 jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 2;
1943 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1952 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
1953 checkErrorValue(jrr,
"unexpectedLedgerType",
"Unexpected ledger type.");
1962 {.fieldName = jss::account, .malformedErrorMsg =
"malformedAddress"},
1963 {.fieldName = jss::ticket_seq, .malformedErrorMsg =
"malformedRequest"},
1983 jv[jss::TransactionType] = jss::DIDSet;
1984 jv[jss::Account] = account.human();
1990 env(didCreate(alice));
1998 jvParams[jss::did] = alice.
human();
2001 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2002 BEAST_EXPECT(jrr[jss::node][sfDIDDocument.jsonName] ==
strHex(
std::string{
"data"}));
2011 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2025 testcase(
"Invalid Oracle Ledger Entry");
2033 env, {.owner = owner, .fee =
static_cast<int>(env.
current()->fees().base.drops())});
2041 {.fieldName = jss::account, .malformedErrorMsg =
"malformedAccount"},
2042 {.fieldName = jss::oracle_document_id,
2043 .malformedErrorMsg =
"malformedDocumentID"},
2056 auto const baseFee =
static_cast<int>(env.
current()->fees().base.drops());
2059 for (
int i = 0; i < 10; ++i)
2064 Oracle const oracle(env, {.owner = owner, .documentID = i, .fee = baseFee});
2068 Oracle const oracle1(env, {.owner = owner, .documentID = i + 10, .fee = baseFee});
2070 oracles.
push_back(oracle1.documentID());
2072 for (
int i = 0; i < accounts.
size(); ++i)
2074 auto const jv = [&]() {
2083 BEAST_EXPECT(jv[jss::node][jss::Owner] ==
to_string(accounts[i]));
2102 MPTTester mptAlice(env, alice, {.holders = {bob}});
2107 .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade |
2108 tfMPTCanTransfer | tfMPTCanClawback});
2109 mptAlice.authorize({.account = bob, .holderCount = 1});
2113 std::string const badMptID =
"00000193B9DDCAF401B5B3B26875986043F82CD0D13B4315";
2117 jvParams[jss::mpt_issuance] =
strHex(mptAlice.issuanceID());
2120 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2121 BEAST_EXPECT(jrr[jss::node][sfMPTokenMetadata.jsonName] ==
strHex(
std::string{
"123"}));
2122 BEAST_EXPECT(jrr[jss::node][jss::mpt_issuance_id] ==
strHex(mptAlice.issuanceID()));
2127 jvParams[jss::mpt_issuance] = badMptID;
2130 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2137 jvParams[jss::mptoken][jss::account] = bob.
human();
2138 jvParams[jss::mptoken][jss::mpt_issuance_id] =
strHex(mptAlice.issuanceID());
2141 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2143 jrr[jss::node][sfMPTokenIssuanceID.jsonName] ==
strHex(mptAlice.issuanceID()));
2149 jvParams[jss::mptoken][jss::account] = bob.
human();
2150 jvParams[jss::mptoken][jss::mpt_issuance_id] = badMptID;
2153 env.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2172 Account const issuer{
"issuer"};
2176 env.
fund(
XRP(5000), issuer, alice, bob);
2179 auto const seq = env.
seq(alice);
2180 env(
pdomain::setTx(alice, {{.issuer = alice, .credType =
"first credential"}}));
2183 if (!BEAST_EXPECT(objects.size() == 1))
2189 params[jss::ledger_index] = jss::validated;
2190 params[jss::permissioned_domain][jss::account] = alice.
human();
2191 params[jss::permissioned_domain][jss::seq] = seq;
2192 auto jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2195 !jv[jss::result].
isMember(jss::error) && jv[jss::result].
isMember(jss::node) &&
2196 jv[jss::result][jss::node].
isMember(sfLedgerEntryType.jsonName) &&
2197 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::PermissionedDomain);
2203 params[jss::ledger_index] = jss::validated;
2204 params[jss::permissioned_domain] = pdIdx;
2205 jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2208 !jv[jss::result].
isMember(jss::error) && jv[jss::result].
isMember(jss::node) &&
2209 jv[jss::result][jss::node].
isMember(sfLedgerEntryType.jsonName) &&
2210 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::PermissionedDomain);
2216 params[jss::ledger_index] = jss::validated;
2217 params[jss::permissioned_domain] =
2218 "12F1F1F1F180D67377B2FAB292A31C922470326268D2B9B74CD1E582645B9A"
2220 auto const jrr = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2221 checkErrorValue(jrr[jss::result],
"entryNotFound",
"Entry not found.");
2227 jss::permissioned_domain,
2229 {.fieldName = jss::account, .malformedErrorMsg =
"malformedAddress"},
2230 {.fieldName = jss::seq, .malformedErrorMsg =
"malformedRequest"},
2261 auto checkResult = [&](
bool good,
2268 jv.isObject() && jv.isMember(jss::result) &&
2269 !jv[jss::result].isMember(jss::error) &&
2270 jv[jss::result].isMember(jss::node) &&
2271 jv[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) &&
2272 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == expectedType,
2278 jv.isObject() && jv.isMember(jss::result) &&
2279 jv[jss::result].isMember(jss::error) &&
2280 !jv[jss::result].isMember(jss::node) &&
2281 jv[jss::result][jss::error] == expectedError.value_or(
"entryNotFound"),
2298 Keylet const& expectedKey,
2300 testcase << expectedType.cStr() << (good ?
"" :
" not") <<
" found";
2302 auto const hexKey =
strHex(expectedKey.key);
2308 params[jss::ledger_index] = jss::validated;
2310 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2311 checkResult(
false, jv, expectedType,
"malformedRequest");
2312 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2318 params[jss::ledger_index] = jss::validated;
2319 params[field] =
"arbitrary string";
2320 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2321 checkResult(
false, jv, expectedType,
"malformedRequest");
2322 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2328 params[jss::ledger_index] = jss::validated;
2329 params[field] =
false;
2330 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2331 checkResult(
false, jv, expectedType,
"invalidParams");
2332 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2340 params[jss::ledger_index] = jss::validated;
2341 params[field] = badKey;
2342 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2343 checkResult(
false, jv, expectedType,
"entryNotFound");
2344 BEAST_EXPECTS(jv[jss::result][jss::index] == badKey,
to_string(jv));
2350 params[jss::ledger_index] = jss::validated;
2351 params[jss::index] = field;
2352 params[jss::api_version] = 2;
2353 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2354 checkResult(
false, jv, expectedType,
"malformedRequest");
2355 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2363 params[jss::ledger_index] = jss::validated;
2364 params[field] =
true;
2365 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2367 std::string const pdIdx = jv[jss::result][jss::index].asString();
2368 BEAST_EXPECTS(hexKey == pdIdx,
to_string(jv));
2369 checkResult(good, jv, expectedType);
2378 params[jss::ledger_index] = jss::validated;
2379 params[field] = hexKey;
2380 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2381 checkResult(good, jv, expectedType);
2382 BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey);
2389 params[jss::ledger_index] = jss::validated;
2390 params[jss::index] = field;
2391 params[jss::api_version] = 2;
2392 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2393 checkResult(
false, jv, expectedType,
"malformedRequest");
2394 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2400 params[jss::ledger_index] = jss::validated;
2401 params[jss::index] = field;
2402 params[jss::api_version] = 3;
2403 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2405 BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey);
2406 checkResult(good, jv, expectedType);
2412 params[jss::ledger_index] = jss::validated;
2413 params[jss::index] = pdIdx;
2414 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2416 BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey);
2417 checkResult(good, jv, expectedType);
2454 auto checkResult = [&](
bool good,
2461 jv.isObject() && jv.isMember(jss::result) &&
2462 !jv[jss::result].isMember(jss::error) &&
2463 jv[jss::result].isMember(jss::node) &&
2464 jv[jss::result][jss::node].isMember(sfLedgerEntryType.jsonName) &&
2465 jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == jss::LedgerHashes,
2468 jv[jss::result].isMember(jss::node) &&
2469 jv[jss::result][jss::node].isMember(
"Hashes") &&
2470 jv[jss::result][jss::node][
"Hashes"].
size() == expectedCount,
2476 jv.isObject() && jv.isMember(jss::result) &&
2477 jv[jss::result].isMember(jss::error) &&
2478 !jv[jss::result].isMember(jss::node) &&
2479 jv[jss::result][jss::error] == expectedError.value_or(
"entryNotFound"),
2495 [&](
json::Value ledger,
Keylet const& expectedKey,
bool good,
int expectedCount = 0) {
2497 <<
" \"hashes\":" <<
to_string(ledger) << (good ?
"" :
" not") <<
" found";
2499 auto const hexKey =
strHex(expectedKey.key);
2505 params[jss::ledger_index] = jss::validated;
2507 auto jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2508 checkResult(
false, jv, 0,
"malformedRequest");
2509 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2515 params[jss::ledger_index] = jss::validated;
2516 params[jss::hashes] =
"arbitrary string";
2517 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2518 checkResult(
false, jv, 0,
"malformedRequest");
2519 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2525 params[jss::ledger_index] = jss::validated;
2526 params[jss::hashes] =
"10";
2527 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2528 checkResult(
false, jv, 0,
"malformedRequest");
2529 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2535 params[jss::ledger_index] = jss::validated;
2536 params[jss::hashes] =
false;
2537 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2538 checkResult(
false, jv, 0,
"invalidParams");
2539 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2545 params[jss::ledger_index] = jss::validated;
2546 params[jss::hashes] = -1;
2547 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2548 checkResult(
false, jv, 0,
"internal");
2549 BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
2556 params[jss::ledger_index] = jss::validated;
2557 params[jss::hashes] = badKey;
2558 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2559 checkResult(
false, jv, 0,
"entryNotFound");
2560 BEAST_EXPECT(jv[jss::result][jss::index] == badKey);
2567 params[jss::ledger_index] = jss::validated;
2568 params[jss::hashes] = ledger;
2569 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2570 checkResult(good, jv, expectedCount);
2572 std::string const pdIdx = jv[jss::result][jss::index].asString();
2573 BEAST_EXPECTS(hexKey == pdIdx,
strHex(pdIdx));
2579 params[jss::ledger_index] = jss::validated;
2580 params[jss::hashes] = hexKey;
2581 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2582 checkResult(good, jv, expectedCount);
2585 hexKey == jv[jss::result][jss::index].asString(),
2586 strHex(jv[jss::result][jss::index].asString()));
2592 params[jss::ledger_index] = jss::validated;
2593 params[jss::index] = hexKey;
2594 auto const jv = env.
rpc(
"json",
"ledger_entry",
to_string(params));
2595 checkResult(good, jv, expectedCount);
2598 hexKey == jv[jss::result][jss::index].asString(),
2599 strHex(jv[jss::result][jss::index].asString()));
2611 for (
auto i = env.
current()->seq(); i <= 250; ++i)
2622 for (
auto i = env.
current()->seq(); i <= 260; ++i)
2651 BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check);
2652 BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] ==
"100000000");
2697 if (BEAST_EXPECT(jv.
isMember(jss::status)))
2698 BEAST_EXPECT(jv[jss::status] ==
"error");
2699 if (BEAST_EXPECT(jv.
isMember(jss::error)))
2700 BEAST_EXPECT(jv[jss::error] == err);
2706 else if (BEAST_EXPECT(jv.
isMember(jss::error_message)))
2708 BEAST_EXPECT(jv[jss::error_message] == msg);
2729 jvParams[jss::bridge_account] =
mcDoor.human();
2730 jvParams[jss::bridge] =
jvb;
2732 mcEnv.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2734 BEAST_EXPECT(jrr.
isMember(jss::node));
2735 auto r = jrr[jss::node];
2737 BEAST_EXPECT(r.isMember(jss::Account));
2738 BEAST_EXPECT(r[jss::Account] ==
mcDoor.human());
2740 BEAST_EXPECT(r.isMember(jss::Flags));
2742 BEAST_EXPECT(r.isMember(sfLedgerEntryType.jsonName));
2743 BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::Bridge);
2746 BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName));
2747 BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 0);
2750 BEAST_EXPECT(r.isMember(sfXChainAccountClaimCount.jsonName));
2751 BEAST_EXPECT(r[sfXChainAccountClaimCount.jsonName].asInt() == 0);
2753 BEAST_EXPECT(r.isMember(jss::index));
2754 bridgeIndex = r[jss::index].asString();
2760 jvParams[jss::index] = bridgeIndex;
2762 mcEnv.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2764 BEAST_EXPECT(jrr.
isMember(jss::node));
2765 BEAST_EXPECT(jrr[jss::node] == mcBridge);
2772 jvParams[jss::bridge] =
jvb;
2775 mcEnv.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2789 jvParams[jss::bridge_account] =
mcDoor.human();
2790 jvParams[jss::bridge] =
jvb;
2792 mcEnv.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2794 BEAST_EXPECT(jrr.
isMember(jss::node));
2795 auto r = jrr[jss::node];
2798 BEAST_EXPECT(r.isMember(sfXChainClaimID.jsonName));
2799 BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2);
2806 testcase(
"ledger_entry: xchain_claim_id");
2823 jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] = 1;
2825 scEnv.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2827 BEAST_EXPECT(jrr.
isMember(jss::node));
2828 auto r = jrr[jss::node];
2830 BEAST_EXPECT(r.isMember(jss::Account));
2831 BEAST_EXPECT(r[jss::Account] ==
scAlice.human());
2832 BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID);
2833 BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 1);
2834 BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0);
2841 jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] = 2;
2843 scEnv.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2845 BEAST_EXPECT(jrr.
isMember(jss::node));
2846 auto r = jrr[jss::node];
2848 BEAST_EXPECT(r.isMember(jss::Account));
2849 BEAST_EXPECT(r[jss::Account] ==
scBob.human());
2850 BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID);
2851 BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2);
2852 BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0);
2859 testcase(
"ledger_entry: xchain_create_account_claim_id");
2870 auto const amt =
XRP(1000);
2876 static constexpr size_t kNumAttest = 3;
2889 for (
size_t i = 0; i < kNumAttest; ++i)
2891 scEnv(attestations[i]);
2898 jvParams[jss::xchain_owned_create_account_claim_id] =
jvXRPBridgeRPC;
2899 jvParams[jss::xchain_owned_create_account_claim_id]
2900 [jss::xchain_owned_create_account_claim_id] = 1;
2902 scEnv.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
2904 BEAST_EXPECT(jrr.
isMember(jss::node));
2905 auto r = jrr[jss::node];
2907 BEAST_EXPECT(r.isMember(jss::Account));
2910 BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName));
2911 BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 1);
2913 BEAST_EXPECT(r.isMember(sfXChainCreateAccountAttestations.jsonName));
2914 auto attest = r[sfXChainCreateAccountAttestations.jsonName];
2915 BEAST_EXPECT(attest.isArray());
2916 BEAST_EXPECT(attest.size() == 3);
2920 for (
size_t i = 0; i < kNumAttest; ++i)
2924 a[i].isMember(jss::Amount) && a[i][jss::Amount].asInt() == 1000 *
kDropPerXrp);
2926 a[i].isMember(jss::Destination) && a[i][jss::Destination] ==
scCarol.human());
2928 a[i].isMember(sfAttestationSignerAccount.jsonName) &&
2930 return a[i][sfAttestationSignerAccount.jsonName] == s.account.human();
2933 a[i].isMember(sfAttestationRewardAccount.jsonName) &&
2935 return a[i][sfAttestationRewardAccount.jsonName] == account.human();
2938 a[i].isMember(sfWasLockingChainSend.jsonName) &&
2939 a[i][sfWasLockingChainSend.jsonName] == 1);
2941 a[i].isMember(sfSignatureReward.jsonName) &&
2950 scEnv(attestations[i]);
2956 jvParams[jss::xchain_owned_create_account_claim_id] =
jvXRPBridgeRPC;
2957 jvParams[jss::xchain_owned_create_account_claim_id]
2958 [jss::xchain_owned_create_account_claim_id] = 1;
2960 scEnv.
rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
A generic endpoint for log messages.
void fail(String const &reason, char const *file, int line)
Record a failure.
TestcaseT testcase
Memberspace for declaring test cases.
Lightweight wrapper to tag static string.
constexpr char const * cStr() const
Value removeMember(char const *key)
Remove and return the named member.
bool isNull() const
isNull() tests to see if this field is null.
std::string toStyledString() 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 asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
void clear()
Remove all object members and array elements.
static BaseUInt fromVoid(void const *data)
std::chrono::time_point< NetClock > time_point
std::chrono::duration< rep, period > duration
bool modify(modify_type const &f)
Modify the open ledger.
Writable ledger view that accumulates state and tx changes.
void rawInsert(SLE::ref sle) override
Unconditionally insert a state item.
void pushBack(STObject const &object)
static STObject makeInnerObject(SField const &name)
virtual OpenLedger & getOpenLedger()=0
static Account const kMaster
The master account that holds all XRP in genesis.
void testCreateAccountClaimID()
void run() override
Runs the suite.
void checkErrorValue(json::Value const &jv, std::string const &err, std::string const &msg)
void runLedgerEntryTest(test::jtx::Env &env, json::StaticString const &parentField, std::source_location const location=std::source_location::current())
void testOracleLedgerEntry()
void testMalformedField(test::jtx::Env &env, json::Value correctRequest, json::StaticString const fieldName, FieldType const typeID, std::string const &expectedError, bool required=true, std::source_location const location=std::source_location::current())
void checkErrorValue(json::Value const &jv, std::string const &err, std::string const &msg, std::source_location const location=std::source_location::current())
void run() override
Runs the suite.
static std::vector< json::Value > getBadValues(FieldType fieldType)
void testDepositPreauth()
void testMalformedSubfield(test::jtx::Env &env, json::Value correctRequest, json::StaticString parentFieldName, json::StaticString fieldName, FieldType typeID, std::string const &expectedError, bool required=true, std::source_location const location=std::source_location::current())
void testFixed()
Test the ledger entry types that don't take parameters.
void testPermissionedDomain()
void testDepositPreauthCred()
void runLedgerEntryTest(test::jtx::Env &env, json::StaticString const &parentField, std::vector< Subfield > const &subfields, std::source_location const location=std::source_location::current())
void testInvalidOracleLedgerEntry()
static json::Value getCorrectValue(json::StaticString fieldName)
Convenience class to test AMM functionality.
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
PublicKey const & pk() const
Return the public key.
AccountID id() const
Returns the Account ID.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
SLE::const_pointer le(Account const &account) const
Return an account root.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
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 trust(STAmount const &amount, Account const &account)
Establish trust lines.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
NetClock::time_point now()
Returns the current network time.
Test helper for creating, mutating, and asserting MPT and confidential MPT ledger state.
void create(MPTCreate const &arg=MPTCreate{})
Oracle class facilitates unit-testing of the Price Oracle feature.
static json::Value ledgerEntry(Env &env, std::optional< std::variant< AccountID, std::string > > const &account, std::optional< AnyValue > const &documentID, std::optional< std::string > const &index=std::nullopt)
Sets the optional Destination field on an NFTokenOffer.
@ Array
array value (ordered list)
@ Object
object value (collection of name/value pairs).
std::string missingFieldMessage(std::string const &name)
std::string expectedFieldMessage(std::string const &name, std::string const &type)
Keylet computation functions.
Keylet const & skip() noexcept
The index of the "short" skip list.
Keylet const & negativeUNL() noexcept
The (fixed) index of the object containing the ledger negativeUNL.
Keylet const & feeSettings() noexcept
The (fixed) index of the object containing the ledger fees.
Keylet payChannel(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Keylet const & amendments() noexcept
The index of the amendment table.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Keylet nftokenPageMax(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Keylet nftokenOffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
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 authCredentials(jtx::Account const &account, std::vector< AuthorizeCredentials > const &auth)
json::Value auth(Account const &account, Account const &auth)
Preauthorize for deposit.
std::map< uint256, json::Value > getObjects(Account const &account, Env &env, bool withType)
json::Value setTx(AccountID const &account, Credentials const &credentials, std::optional< uint256 > domain)
json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
json::Value mint(jtx::Account const &account, std::uint32_t nfTokenTaxon)
Mint an NFToken.
json::Value createOffer(jtx::Account const &account, uint256 const &nftokenID, STAmount const &amount)
Create an NFTokenOffer.
uint256 getNextID(jtx::Env const &env, jtx::Account const &issuer, std::uint32_t nfTokenTaxon, std::uint16_t flags, std::uint16_t xferFee)
Get the next NFTokenID that will be issued.
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
json::Value sidechainXchainAccountCreate(Account const &acc, json::Value const &bridge, Account const &dst, AnyAmount const &amt, AnyAmount const &reward)
XrpT const XRP
Converts to XRP Issue or STAmount.
require_t required(Args const &... args)
Compose many condition functors into one.
FeatureBitset testableAmendments()
constexpr std::size_t kUtXchainDefaultNumSigners
json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
json::Value xchainCreateClaimId(Account const &acc, json::Value const &bridge, STAmount const &reward, Account const &otherChainSource)
JValueVec createAccountAttestations(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)
json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
FieldType getFieldType(json::StaticString fieldName)
static uint256 ledgerHash(LedgerHeader const &info)
std::vector< std::pair< json::StaticString, FieldType > > gMappings
std::string getTypeName(FieldType typeID)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string strHex(FwdIt begin, FwdIt end)
uint256 getTicketIndex(AccountID const &account, std::uint32_t uSequence)
std::string to_string(BaseUInt< Bits, Tag > const &a)
json::Value toJson(Asset const &asset)
Asset getAsset(T const &amt)
void forAllApiVersions(Fn const &fn, Args &&... args)
constexpr std::size_t kMaxCredentialsArraySize
The maximum number of credentials can be passed in array.
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
A pair of SHAMap key and LedgerEntryType.
json::StaticString fieldName
std::string malformedErrorMsg
Asset const & raw() const
A signer in a SignerList.
void createBridgeObjects(Env &mcEnv, Env &scEnv)
std::vector< Account > const payee
FeatureBitset const features
std::vector< Signer > const signers
static constexpr int kDropPerXrp
json::Value const jvXRPBridgeRPC