Merge remote-tracking branch 'upstream/develop' into sponsor

This commit is contained in:
tequ
2026-01-29 11:22:42 +09:00
1026 changed files with 27864 additions and 68510 deletions

View File

@@ -110,20 +110,16 @@ public:
{
Json::Value params;
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Missing field 'account'.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Missing field 'account'.");
}
// test account non-string
{
auto testInvalidAccountParam = [&](auto const& param) {
Json::Value params;
params[jss::account] = param;
auto jrr = env.rpc(
"json", "account_objects", to_string(params))[jss::result];
auto jrr = env.rpc("json", "account_objects", to_string(params))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'account'.");
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'.");
};
testInvalidAccountParam(1);
@@ -136,19 +132,16 @@ public:
// test error on malformed account string.
{
Json::Value params;
params[jss::account] =
"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
params[jss::account] = "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] == "Account malformed.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Account malformed.");
}
// test error on account that's not in the ledger.
{
Json::Value params;
params[jss::account] = Account{"bogie"}.human();
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] == "Account not found.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Account not found.");
}
Account const bob{"bob"};
// test error on large ledger_index.
@@ -157,8 +150,7 @@ public:
params[jss::account] = bob.human();
params[jss::ledger_index] = 10;
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] == "ledgerNotFound");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "ledgerNotFound");
}
env.fund(XRP(1000), bob);
@@ -168,9 +160,7 @@ public:
params[jss::account] = bob.human();
params[jss::type] = 10;
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'type', not string.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'type', not string.");
}
// test error on type param not a valid type
{
@@ -178,9 +168,7 @@ public:
params[jss::account] = bob.human();
params[jss::type] = "expedited";
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'type'.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'type'.");
}
// test error on limit -ve
{
@@ -188,9 +176,7 @@ public:
params[jss::account] = bob.human();
params[jss::limit] = -1;
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'limit', not unsigned integer.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'limit', not unsigned integer.");
}
// test errors on marker
{
@@ -210,39 +196,27 @@ public:
std::string mark = to_string(resume_marker);
params[jss::marker] = 10;
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker', not string.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker', not string.");
params[jss::marker] = "This is a string with no comma";
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
params[jss::marker] = "This string has a comma, but is not hex";
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 64);
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 65);
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 65) + "not hex";
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
// Should this be an error?
// A hex digit is absent from the end of marker.
@@ -323,8 +297,7 @@ public:
params[jss::limit] = 1;
for (int i = 0; i < 4; ++i)
{
auto resp =
env.rpc("json", "account_objects", to_string(params));
auto resp = env.rpc("json", "account_objects", to_string(params));
auto& aobjs = resp[jss::result][jss::account_objects];
BEAST_EXPECT(aobjs.size() == 1);
auto& aobj = aobjs[0U];
@@ -405,8 +378,7 @@ public:
BEAST_EXPECT(!resp.isMember(jss::marker));
Json::Value& aobjs = resp[jss::result][jss::account_objects];
BEAST_EXPECT(aobjs.size() == 1);
BEAST_EXPECT(
aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
BEAST_EXPECT(aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
BEAST_EXPECT(aobjs[0u][sfNFTokens.jsonName].size() == 1);
}
// test stepped one-at-a-time with limit=1, resume from prev marker
@@ -415,8 +387,7 @@ public:
params[jss::account] = bob.human();
params[jss::limit] = 1;
Json::Value resp =
env.rpc("json", "account_objects", to_string(params));
Json::Value resp = env.rpc("json", "account_objects", to_string(params));
Json::Value& aobjs = resp[jss::result][jss::account_objects];
BEAST_EXPECT(aobjs.size() == 1);
auto& aobj = aobjs[0U];
@@ -456,8 +427,7 @@ public:
BEAST_EXPECT(!resp.isMember(jss::marker));
Json::Value& aobjs = resp[jss::result][jss::account_objects];
BEAST_EXPECT(aobjs.size() == 1);
BEAST_EXPECT(
aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
BEAST_EXPECT(aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
BEAST_EXPECT(aobjs[0u][sfNFTokens.jsonName].size() == 1);
}
// test stepped one-at-a-time with limit=1, resume from prev marker
@@ -467,8 +437,7 @@ public:
params[jss::limit] = 1;
for (int i = 0; i < 5; ++i)
{
Json::Value resp =
env.rpc("json", "account_objects", to_string(params));
Json::Value resp = env.rpc("json", "account_objects", to_string(params));
Json::Value& aobjs = resp[jss::result][jss::account_objects];
BEAST_EXPECT(aobjs.size() == 1);
auto& aobj = aobjs[0U];
@@ -522,8 +491,7 @@ public:
params[jss::limit] = 1;
for (int i = 0; i < 6; ++i)
{
Json::Value resp =
env.rpc("json", "account_objects", to_string(params));
Json::Value resp = env.rpc("json", "account_objects", to_string(params));
Json::Value& aobjs = resp[jss::result][jss::account_objects];
BEAST_EXPECT(aobjs.size() == 1);
auto& aobj = aobjs[0U];
@@ -558,8 +526,7 @@ public:
Account const gw{"gateway"};
auto const USD = gw["USD"];
auto const features = testable_amendments() | featureXChainBridge |
featurePermissionedDomains;
auto const features = testable_amendments() | featureXChainBridge | featurePermissionedDomains;
Env env(*this, features);
// Make a lambda we can use to get "account_objects" easily.
@@ -589,8 +556,7 @@ public:
// Make a lambda that checks if the response has error for invalid type
auto acctObjsTypeIsInvalid = [](Json::Value const& resp) {
return resp[jss::result].isMember(jss::error) &&
resp[jss::result][jss::error_message] ==
"Invalid field \'type\'.";
resp[jss::result][jss::error_message] == "Invalid field \'type\'.";
};
env.fund(XRP(10000), gw, alice);
@@ -632,8 +598,7 @@ public:
auto const& nftPage = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(nftPage[sfNFTokens.jsonName].size() == 1);
BEAST_EXPECT(
nftPage[sfNFTokens.jsonName][0u][sfNFToken.jsonName]
[sfNFTokenID.jsonName] == to_string(nftID));
nftPage[sfNFTokens.jsonName][0u][sfNFToken.jsonName][sfNFTokenID.jsonName] == to_string(nftID));
}
// Set up a trust line so we can find it.
@@ -648,8 +613,7 @@ public:
auto const& state = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(state[sfBalance.jsonName][jss::value].asInt() == -5);
BEAST_EXPECT(
state[sfHighLimit.jsonName][jss::value].asUInt() == 1000);
BEAST_EXPECT(state[sfHighLimit.jsonName][jss::value].asUInt() == 1000);
}
// gw writes a check for USD(10) to alice.
env(check::create(gw, alice, USD(10)));
@@ -683,8 +647,7 @@ public:
jvEscrow[jss::Account] = gw.human();
jvEscrow[jss::Destination] = gw.human();
jvEscrow[jss::Amount] = XRP(100).value().getJson(JsonOptions::none);
jvEscrow[sfFinishAfter.jsonName] =
env.now().time_since_epoch().count() + 1;
jvEscrow[sfFinishAfter.jsonName] = env.now().time_since_epoch().count() + 1;
env(jvEscrow);
env.close();
}
@@ -712,30 +675,22 @@ public:
Json::Value const resp = acctObjs(gw, jss::permissioned_domain);
BEAST_EXPECT(acctObjsIsSize(resp, 1));
auto const& permissionedDomain =
resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(
permissionedDomain.isMember(jss::Owner) &&
(permissionedDomain[jss::Owner] == gw.human()));
auto const& permissionedDomain = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(permissionedDomain.isMember(jss::Owner) && (permissionedDomain[jss::Owner] == gw.human()));
bool const check1 = BEAST_EXPECT(
permissionedDomain.isMember(jss::AcceptedCredentials) &&
permissionedDomain[jss::AcceptedCredentials].isArray() &&
(permissionedDomain[jss::AcceptedCredentials].size() == 1) &&
(permissionedDomain[jss::AcceptedCredentials][0u].isMember(
jss::Credential)));
(permissionedDomain[jss::AcceptedCredentials][0u].isMember(jss::Credential)));
if (check1)
{
auto const& credential =
permissionedDomain[jss::AcceptedCredentials][0u]
[jss::Credential];
auto const& credential = permissionedDomain[jss::AcceptedCredentials][0u][jss::Credential];
BEAST_EXPECT(
credential.isMember(sfIssuer.jsonName) &&
(credential[sfIssuer.jsonName] == issuer.human()));
credential.isMember(sfIssuer.jsonName) && (credential[sfIssuer.jsonName] == issuer.human()));
BEAST_EXPECT(
credential.isMember(sfCredentialType.jsonName) &&
(credential[sfCredentialType.jsonName] ==
strHex(credentialType1)));
(credential[sfCredentialType.jsonName] == strHex(credentialType1)));
}
}
@@ -753,30 +708,17 @@ public:
return scEnv.rpc("json", "account_objects", to_string(params));
};
Json::Value const resp =
scEnvAcctObjs(Account::master, jss::bridge);
Json::Value const resp = scEnvAcctObjs(Account::master, jss::bridge);
BEAST_EXPECT(acctObjsIsSize(resp, 1));
auto const& acct_bridge =
resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(
acct_bridge[sfAccount.jsonName] == Account::master.human());
BEAST_EXPECT(
acct_bridge[sfLedgerEntryType.getJsonName()] == "Bridge");
BEAST_EXPECT(
acct_bridge[sfXChainClaimID.getJsonName()].asUInt() == 0);
BEAST_EXPECT(
acct_bridge[sfXChainAccountClaimCount.getJsonName()].asUInt() ==
0);
BEAST_EXPECT(
acct_bridge[sfXChainAccountCreateCount.getJsonName()]
.asUInt() == 0);
BEAST_EXPECT(
acct_bridge[sfMinAccountCreateAmount.getJsonName()].asUInt() ==
20000000);
BEAST_EXPECT(
acct_bridge[sfSignatureReward.getJsonName()].asUInt() ==
1000000);
auto const& acct_bridge = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(acct_bridge[sfAccount.jsonName] == Account::master.human());
BEAST_EXPECT(acct_bridge[sfLedgerEntryType.getJsonName()] == "Bridge");
BEAST_EXPECT(acct_bridge[sfXChainClaimID.getJsonName()].asUInt() == 0);
BEAST_EXPECT(acct_bridge[sfXChainAccountClaimCount.getJsonName()].asUInt() == 0);
BEAST_EXPECT(acct_bridge[sfXChainAccountCreateCount.getJsonName()].asUInt() == 0);
BEAST_EXPECT(acct_bridge[sfMinAccountCreateAmount.getJsonName()].asUInt() == 20000000);
BEAST_EXPECT(acct_bridge[sfSignatureReward.getJsonName()].asUInt() == 1000000);
BEAST_EXPECT(acct_bridge[sfXChainBridge.getJsonName()] == x.jvb);
}
{
@@ -786,8 +728,7 @@ public:
Env scEnv(*this, envconfig(), features);
x.createScBridgeObjects(scEnv);
scEnv(
xchain_create_claim_id(x.scAlice, x.jvb, x.reward, x.mcAlice));
scEnv(xchain_create_claim_id(x.scAlice, x.jvb, x.reward, x.mcAlice));
scEnv.close();
scEnv(xchain_create_claim_id(x.scBob, x.jvb, x.reward, x.mcBob));
scEnv.close();
@@ -802,28 +743,21 @@ public:
{
// Find the xchain sequence number for Andrea.
Json::Value const resp =
scEnvAcctObjs(x.scAlice, jss::xchain_owned_claim_id);
Json::Value const resp = scEnvAcctObjs(x.scAlice, jss::xchain_owned_claim_id);
BEAST_EXPECT(acctObjsIsSize(resp, 1));
auto const& xchain_seq =
resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(
xchain_seq[sfAccount.jsonName] == x.scAlice.human());
BEAST_EXPECT(
xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 1);
auto const& xchain_seq = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(xchain_seq[sfAccount.jsonName] == x.scAlice.human());
BEAST_EXPECT(xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 1);
}
{
// and the one for Bob
Json::Value const resp =
scEnvAcctObjs(x.scBob, jss::xchain_owned_claim_id);
Json::Value const resp = scEnvAcctObjs(x.scBob, jss::xchain_owned_claim_id);
BEAST_EXPECT(acctObjsIsSize(resp, 1));
auto const& xchain_seq =
resp[jss::result][jss::account_objects][0u];
auto const& xchain_seq = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(xchain_seq[sfAccount.jsonName] == x.scBob.human());
BEAST_EXPECT(
xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 2);
BEAST_EXPECT(xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 2);
}
}
{
@@ -837,16 +771,7 @@ public:
// account (Account::master) to collect the signatures until a
// quorum is reached
scEnv(test::jtx::create_account_attestation(
x.scAttester,
x.jvb,
x.mcCarol,
amt,
x.reward,
x.payees[0],
true,
1,
x.scuAlice,
x.signers[0]));
x.scAttester, x.jvb, x.mcCarol, amt, x.reward, x.payees[0], true, 1, x.scuAlice, x.signers[0]));
scEnv.close();
auto scEnvAcctObjs = [&](Account const& acct, char const* type) {
@@ -859,19 +784,12 @@ public:
{
// Find the xchain_create_account_claim_id
Json::Value const resp = scEnvAcctObjs(
Account::master, jss::xchain_owned_create_account_claim_id);
Json::Value const resp = scEnvAcctObjs(Account::master, jss::xchain_owned_create_account_claim_id);
BEAST_EXPECT(acctObjsIsSize(resp, 1));
auto const& xchain_create_account_claim_id =
resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(
xchain_create_account_claim_id[sfAccount.jsonName] ==
Account::master.human());
BEAST_EXPECT(
xchain_create_account_claim_id[sfXChainAccountCreateCount
.getJsonName()]
.asUInt() == 1);
auto const& xchain_create_account_claim_id = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(xchain_create_account_claim_id[sfAccount.jsonName] == Account::master.human());
BEAST_EXPECT(xchain_create_account_claim_id[sfXChainAccountCreateCount.getJsonName()].asUInt() == 1);
}
}
@@ -895,8 +813,7 @@ public:
jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
jvPayChan[jss::Account] = gw.human();
jvPayChan[jss::Destination] = alice.human();
jvPayChan[jss::Amount] =
XRP(300).value().getJson(JsonOptions::none);
jvPayChan[jss::Amount] = XRP(300).value().getJson(JsonOptions::none);
jvPayChan[sfSettleDelay.jsonName] = 24 * 60 * 60;
jvPayChan[sfPublicKey.jsonName] = strHex(gw.pk().slice());
env(jvPayChan);
@@ -910,8 +827,7 @@ public:
auto const& payChan = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(payChan[sfAccount.jsonName] == gw.human());
BEAST_EXPECT(payChan[sfAmount.jsonName].asUInt() == 300'000'000);
BEAST_EXPECT(
payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60);
BEAST_EXPECT(payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60);
}
{
@@ -940,11 +856,9 @@ public:
Json::Value const resp = acctObjs(gw, jss::signer_list);
BEAST_EXPECT(acctObjsIsSize(resp, 1));
auto const& signerList =
resp[jss::result][jss::account_objects][0u];
auto const& signerList = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(signerList[sfSignerQuorum.jsonName] == 6);
auto const& entry = signerList[sfSignerEntries.jsonName][0u]
[sfSignerEntry.jsonName];
auto const& entry = signerList[sfSignerEntries.jsonName][0u][sfSignerEntry.jsonName];
BEAST_EXPECT(entry[sfAccount.jsonName] == alice.human());
BEAST_EXPECT(entry[sfSignerWeight.jsonName].asUInt() == 7);
}
@@ -967,12 +881,7 @@ public:
{
// Create a sponsorship
env(sponsor::set(
alice,
tfSponsorshipSetRequireSignForFee,
200,
XRP(100),
drops(10)),
env(sponsor::set(alice, tfSponsorshipSetRequireSignForFee, 200, XRP(100), drops(10)),
sponsor::sponseeAcc(gw));
env.close();
@@ -982,18 +891,13 @@ public:
Json::Value const resp = acctObjs(acct, jss::sponsorship);
BEAST_EXPECT(acctObjsIsSize(resp, 1));
auto const& sponsorship =
resp[jss::result][jss::account_objects][0u];
auto const& sponsorship = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(sponsorship[sfOwner.jsonName] == alice.human());
BEAST_EXPECT(sponsorship[sfSponsee.jsonName] == gw.human());
BEAST_EXPECT(
sponsorship[sfFlags.jsonName].asUInt() ==
tfSponsorshipSetRequireSignForFee);
BEAST_EXPECT(
sponsorship[sfReserveCount.jsonName].asUInt() == 200);
BEAST_EXPECT(
sponsorship[sfFeeAmount.jsonName].asUInt() == 100000000);
BEAST_EXPECT(sponsorship[sfFlags.jsonName].asUInt() == tfSponsorshipSetRequireSignForFee);
BEAST_EXPECT(sponsorship[sfReserveCount.jsonName].asUInt() == 200);
BEAST_EXPECT(sponsorship[sfFeeAmount.jsonName].asUInt() == 100000000);
BEAST_EXPECT(sponsorship[sfMaxFee.jsonName].asUInt() == 10);
}
}
@@ -1018,8 +922,7 @@ public:
return v;
}();
std::uint32_t const expectedAccountObjects{
static_cast<std::uint32_t>(std::size(expectedLedgerTypes))};
std::uint32_t const expectedAccountObjects{static_cast<std::uint32_t>(std::size(expectedLedgerTypes))};
if (BEAST_EXPECT(acctObjsIsSize(resp, expectedAccountObjects)))
{
@@ -1028,8 +931,7 @@ public:
gotLedgerTypes.reserve(expectedAccountObjects);
for (std::uint32_t i = 0; i < expectedAccountObjects; ++i)
{
gotLedgerTypes.push_back(
aobjs[i]["LedgerEntryType"].asString());
gotLedgerTypes.push_back(aobjs[i]["LedgerEntryType"].asString());
}
std::sort(gotLedgerTypes.begin(), gotLedgerTypes.end());
BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
@@ -1052,19 +954,15 @@ public:
}
{
// Make a lambda to get the types
auto getTypes = [&](Json::Value const& resp,
std::vector<std::string>& typesOut) {
auto getTypes = [&](Json::Value const& resp, std::vector<std::string>& typesOut) {
auto const objs = resp[jss::result][jss::account_objects];
for (auto const& obj : resp[jss::result][jss::account_objects])
typesOut.push_back(
obj[sfLedgerEntryType.fieldName].asString());
typesOut.push_back(obj[sfLedgerEntryType.fieldName].asString());
std::sort(typesOut.begin(), typesOut.end());
};
// Make a lambda we can use to check the number of fetched
// account objects and their ledger type
auto expectObjects =
[&](Json::Value const& resp,
std::vector<std::string> const& types) -> bool {
auto expectObjects = [&](Json::Value const& resp, std::vector<std::string> const& types) -> bool {
if (!acctObjsIsSize(resp, types.size()))
return false;
std::vector<std::string> typesOut;
@@ -1078,36 +976,24 @@ public:
auto const lines = getAccountLines(env, amm.ammAccount());
BEAST_EXPECT(lines[jss::lines].size() == 3);
// request AMM only, doesn't depend on the limit
BEAST_EXPECT(
acctObjsIsSize(acctObjs(amm.ammAccount(), jss::amm), 1));
BEAST_EXPECT(acctObjsIsSize(acctObjs(amm.ammAccount(), jss::amm), 1));
// request first two objects
auto resp = acctObjs(amm.ammAccount(), std::nullopt, 2);
std::vector<std::string> typesOut;
getTypes(resp, typesOut);
// request next two objects
resp = acctObjs(
amm.ammAccount(),
std::nullopt,
10,
resp[jss::result][jss::marker].asString());
resp = acctObjs(amm.ammAccount(), std::nullopt, 10, resp[jss::result][jss::marker].asString());
getTypes(resp, typesOut);
BEAST_EXPECT(
(typesOut ==
std::vector<std::string>{
jss::AMM.c_str(),
jss::RippleState.c_str(),
jss::RippleState.c_str(),
jss::RippleState.c_str()}));
jss::AMM.c_str(), jss::RippleState.c_str(), jss::RippleState.c_str(), jss::RippleState.c_str()}));
// filter by state: there are three trustlines
resp = acctObjs(amm.ammAccount(), jss::state, 10);
BEAST_EXPECT(expectObjects(
resp,
{jss::RippleState.c_str(),
jss::RippleState.c_str(),
jss::RippleState.c_str()}));
// AMM account doesn't own offers
BEAST_EXPECT(
acctObjsIsSize(acctObjs(amm.ammAccount(), jss::offer), 0));
expectObjects(resp, {jss::RippleState.c_str(), jss::RippleState.c_str(), jss::RippleState.c_str()}));
// AMM account doesn't own offers
BEAST_EXPECT(acctObjsIsSize(acctObjs(amm.ammAccount(), jss::offer), 0));
// gw account doesn't own AMM object
BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0));
}
@@ -1160,8 +1046,7 @@ public:
Json::Value params;
params[jss::account] = bob.human();
params[jss::ledger_index] = "validated";
Json::Value const resp =
env.rpc("json", "account_nfts", to_string(params));
Json::Value const resp = env.rpc("json", "account_nfts", to_string(params));
Json::Value const& nfts = resp[jss::result][jss::account_nfts];
for (Json::Value const& nft : nfts)
tokenIDs.push_back(nft["NFTokenID"]);
@@ -1170,23 +1055,20 @@ public:
// this lambda function is used to check if the account_nfts method
// returns the correct token information. lastIndex is used to query the
// last marker.
auto compareNFTs = [&tokenIDs, &env, &bob](
unsigned const limit, unsigned const lastIndex) {
auto compareNFTs = [&tokenIDs, &env, &bob](unsigned const limit, unsigned const lastIndex) {
Json::Value params;
params[jss::account] = bob.human();
params[jss::limit] = limit;
params[jss::marker] = tokenIDs[lastIndex];
params[jss::ledger_index] = "validated";
Json::Value const resp =
env.rpc("json", "account_nfts", to_string(params));
Json::Value const resp = env.rpc("json", "account_nfts", to_string(params));
if (resp[jss::result].isMember(jss::error))
return false;
Json::Value const& nfts = resp[jss::result][jss::account_nfts];
unsigned const nftsCount = tokenIDs.size() - lastIndex - 1 < limit
? tokenIDs.size() - lastIndex - 1
: limit;
unsigned const nftsCount =
tokenIDs.size() - lastIndex - 1 < limit ? tokenIDs.size() - lastIndex - 1 : limit;
if (nfts.size() != nftsCount)
return false;
@@ -1207,26 +1089,22 @@ public:
BEAST_EXPECT(compareNFTs(4, 7));
// lambda that holds common code for invalid cases.
auto testInvalidMarker = [&env, &bob](
auto marker, char const* errorMessage) {
auto testInvalidMarker = [&env, &bob](auto marker, char const* errorMessage) {
Json::Value params;
params[jss::account] = bob.human();
params[jss::limit] = 4;
params[jss::ledger_index] = jss::validated;
params[jss::marker] = marker;
Json::Value const resp =
env.rpc("json", "account_nfts", to_string(params));
Json::Value const resp = env.rpc("json", "account_nfts", to_string(params));
return resp[jss::result][jss::error_message] == errorMessage;
};
// test an invalid marker that is not a string
BEAST_EXPECT(
testInvalidMarker(17, "Invalid field \'marker\', not string."));
BEAST_EXPECT(testInvalidMarker(17, "Invalid field \'marker\', not string."));
// test an invalid marker that has a non-hex character
BEAST_EXPECT(testInvalidMarker(
"00000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B900000000000000000G",
"Invalid field \'marker\'."));
"00000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B900000000000000000G", "Invalid field \'marker\'."));
// this lambda function is used to create some fake marker using given
// taxon and sequence because we want to test some unassociated markers
@@ -1237,20 +1115,17 @@ public:
std::uint16_t flags = 0,
std::uint16_t fee = 0) {
// the marker has the exact same format as an NFTokenID
return to_string(NFTokenMint::createNFTokenID(
flags, fee, issuer, nft::toTaxon(taxon), tokenSeq));
return to_string(NFTokenMint::createNFTokenID(flags, fee, issuer, nft::toTaxon(taxon), tokenSeq));
};
// test an unassociated marker which does not exist in the NFTokenIDs
BEAST_EXPECT(testInvalidMarker(
createFakeNFTMarker(bob.id(), 0x000000000, 0x00000000),
"Invalid field \'marker\'."));
BEAST_EXPECT(
testInvalidMarker(createFakeNFTMarker(bob.id(), 0x000000000, 0x00000000), "Invalid field \'marker\'."));
// test an unassociated marker which exceeds the maximum value of the
// existing NFTokenID
BEAST_EXPECT(testInvalidMarker(
createFakeNFTMarker(bob.id(), 0xFFFFFFFF, 0xFFFFFFFF),
"Invalid field \'marker\'."));
BEAST_EXPECT(
testInvalidMarker(createFakeNFTMarker(bob.id(), 0xFFFFFFFF, 0xFFFFFFFF), "Invalid field \'marker\'."));
}
void
@@ -1266,11 +1141,9 @@ public:
auto testInvalidAccountParam = [&](auto const& param) {
Json::Value params;
params[jss::account] = param;
auto jrr = env.rpc(
"json", "account_nfts", to_string(params))[jss::result];
auto jrr = env.rpc("json", "account_nfts", to_string(params))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'account'.");
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'.");
};
testInvalidAccountParam(1);
@@ -1341,10 +1214,8 @@ public:
params[jss::limit] = limit;
params[jss::ledger_index] = jss::validated;
params[jss::marker] = marker;
Json::Value const resp =
env.rpc("json", "account_objects", to_string(params));
return resp[jss::result][jss::error_message] ==
"Invalid field \'marker\'.";
Json::Value const resp = env.rpc("json", "account_objects", to_string(params));
return resp[jss::result][jss::error_message] == "Invalid field \'marker\'.";
};
auto const markerStr = marker.asString();
@@ -1430,8 +1301,7 @@ public:
auto resp = env.rpc("json", "account_objects", to_string(params));
auto& accountObjects = resp[jss::result][jss::account_objects];
BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
BEAST_EXPECT(
accountObjects.size() == accountObjectSize - limit * 2);
BEAST_EXPECT(accountObjects.size() == accountObjectSize - limit * 2);
BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
}