22#include <xrpld/app/tx/detail/ApplyContext.h>
23#include <xrpld/app/tx/detail/NFTokenUtils.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/jss.h>
37 params[jss::account] = acct.
human();
38 params[jss::type] =
"state";
40 return nfts[jss::result][jss::account_nfts].
size();
49 using namespace test::jtx;
62 auto internalTaxon = [
this, &env](
66 auto const le = env.
le(acct);
68 return le->at(~sfMintedNFTokens).value_or(0u);
74 if (env.
current()->rules().enabled(fixNFTokenRemint))
75 tokenSeq += env.
le(acct)
76 ->at(~sfFirstNFTokenSequence)
77 .value_or(env.
seq(acct));
90 std::uint32_t const intTaxon = (i / 16) + (i & 0b10000 ? 2 : 0);
91 uint32_t
const extTaxon = internalTaxon(owner, intTaxon);
106 params[jss::account] = owner.
human();
107 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
110 resp[jss::result][jss::account_objects];
116 acctObjs[i].isMember(sfNFTokens.jsonName) &&
117 acctObjs[i][sfNFTokens.jsonName].
isArray()))
119 BEAST_EXPECT(acctObjs[i][sfNFTokens.jsonName].
size() == 32);
125 BEAST_EXPECT(pageCount == 3);
133 testcase(
"LedgerStateFix error cases");
135 using namespace test::jtx;
143 env.fund(
XRP(1000), alice);
145 auto const linkFixFee =
drops(env.current()->fees().increment);
152 env.fund(
XRP(1000), alice);
161 tx[sfAccountTxnID.jsonName] =
162 "00000000000000000000000000000000"
163 "00000000000000000000000000000000";
170 auto const linkFixFee =
drops(env.current()->fees().increment);
185 tx[sfLedgerFixType.jsonName] = 0;
188 tx[sfLedgerFixType.jsonName] = 200;
203 testcase(
"NFTokenPageLinkFix error cases");
205 using namespace test::jtx;
210 env.fund(
XRP(1000), alice);
217 auto const linkFixFee =
drops(env.current()->fees().increment);
255 using namespace test::jtx;
263 env.fund(
XRP(1000), alice, bob, carol, daria);
272 BEAST_EXPECT(
nftCount(env, alice) == 96);
276 uint256 const aliceMiddleNFTokenPageIndex = [&env, &alice]() {
278 return lastNFTokenPage->at(sfPreviousPageMin);
282 for (
int i = 0; i < 32; ++i)
288 for (
int i = 0; i < 32; ++i)
295 BEAST_EXPECT(
nftCount(env, alice) == 32);
306 if (!BEAST_EXPECT(aliceMiddleNFTokenPage))
310 !aliceMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin));
312 !aliceMiddleNFTokenPage->isFieldPresent(sfNextPageMin));
322 BEAST_EXPECT(
nftCount(env, bob) == 96);
326 uint256 const bobMiddleNFTokenPageIndex = [&env, &bob]() {
328 return lastNFTokenPage->at(sfPreviousPageMin);
332 for (
int i = 0; i < 32; ++i)
338 BEAST_EXPECT(
nftCount(env, bob) == 64);
351 if (!BEAST_EXPECT(bobMiddleNFTokenPage))
355 bobMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin));
356 BEAST_EXPECT(!bobMiddleNFTokenPage->isFieldPresent(sfNextPageMin));
366 BEAST_EXPECT(
nftCount(env, carol) == 96);
370 uint256 const carolMiddleNFTokenPageIndex = [&env, &carol]() {
372 return lastNFTokenPage->at(sfPreviousPageMin);
378 for (
int i = 0; i < 32; ++i)
392 BEAST_EXPECT(
nftCount(env, carol) == 64);
404 if (!BEAST_EXPECT(carolMiddleNFTokenPage))
407 BEAST_EXPECT(carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin));
408 BEAST_EXPECT(!carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin));
414 for (
uint256 const& nft : dariaNFTs)
429 BEAST_EXPECT(
nftCount(env, carol) == 64);
436 if (!BEAST_EXPECT(carolMiddleNFTokenPage))
440 carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin));
442 !carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin));
449 !carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin));
450 BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin));
457 auto const linkFixFee =
drops(env.current()->fees().increment);
464 for (
int i = 0; i < 15; ++i)
467 env.enableFeature(fixNFTokenPageLinks);
483 if (!BEAST_EXPECT(aliceMiddleNFTokenPage))
487 !aliceMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin));
489 !aliceMiddleNFTokenPage->isFieldPresent(sfNextPageMin));
504 if (!BEAST_EXPECT(aliceLastNFTokenPage))
508 !aliceLastNFTokenPage->isFieldPresent(sfPreviousPageMin));
509 BEAST_EXPECT(!aliceLastNFTokenPage->isFieldPresent(sfNextPageMin));
516 BEAST_EXPECT(
nftCount(env, alice) == 32);
532 if (!BEAST_EXPECT(bobMiddleNFTokenPage))
536 bobMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin));
537 BEAST_EXPECT(!bobMiddleNFTokenPage->isFieldPresent(sfNextPageMin));
548 auto const bobLastNFTokenPage = env.le(lastPageKeylet);
549 if (!BEAST_EXPECT(bobLastNFTokenPage))
552 BEAST_EXPECT(bobLastNFTokenPage->isFieldPresent(sfPreviousPageMin));
554 bobLastNFTokenPage->at(sfPreviousPageMin) !=
555 bobMiddleNFTokenPageIndex);
556 BEAST_EXPECT(!bobLastNFTokenPage->isFieldPresent(sfNextPageMin));
560 bobLastNFTokenPage->at(sfPreviousPageMin)));
561 if (!BEAST_EXPECT(bobNewFirstNFTokenPage))
565 bobNewFirstNFTokenPage->isFieldPresent(sfNextPageMin) &&
566 bobNewFirstNFTokenPage->at(sfNextPageMin) ==
569 !bobNewFirstNFTokenPage->isFieldPresent(sfPreviousPageMin));
576 BEAST_EXPECT(
nftCount(env, bob) == 64);
589 if (!BEAST_EXPECT(carolMiddleNFTokenPage))
593 carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin));
595 !carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin));
602 !carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin));
603 BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin));
615 if (!BEAST_EXPECT(carolMiddleNFTokenPage))
619 carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin));
621 carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin) &&
622 carolMiddleNFTokenPage->at(sfNextPageMin) ==
626 auto carolLastNFTokenPage = env.le(lastPageKeylet);
627 if (!BEAST_EXPECT(carolLastNFTokenPage))
631 carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin) &&
632 carolLastNFTokenPage->at(sfPreviousPageMin) ==
633 carolMiddleNFTokenPageIndex);
634 BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin));
639 carolMiddleNFTokenPage->at(sfPreviousPageMin)));
640 if (!BEAST_EXPECT(carolFirstNFTokenPage))
644 carolFirstNFTokenPage->isFieldPresent(sfNextPageMin) &&
645 carolFirstNFTokenPage->at(sfNextPageMin) ==
646 carolMiddleNFTokenPageIndex);
648 !carolFirstNFTokenPage->isFieldPresent(sfPreviousPageMin));
652 BEAST_EXPECT(
nftCount(env, carol) == 96);
666BEAST_DEFINE_TESTSUITE(FixNFTokenPageLinks, tx,
ripple);
UInt size() const
Number of values in array or object.
Value removeMember(char const *key)
Remove and return the named member.
testcase_t testcase
Memberspace for declaring test cases.
void testFixNFTokenPageLinks()
std::vector< uint256 > genPackedTokens(test::jtx::Env &env, test::jtx::Account const &owner)
void run() override
Runs the suite.
void testTokenPageLinkErrors()
static std::uint32_t nftCount(test::jtx::Env &env, test::jtx::Account const &acct)
void testLedgerStateFixErrors()
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
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.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Set a ticket sequence on a JTx.
Sets the optional Owner on an NFTokenOffer.
Keylet nftpage(Keylet const &k, uint256 const &token)
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Taxon cipheredTaxon(std::uint32_t tokenSeq, Taxon taxon)
Taxon toTaxon(std::uint32_t i)
Json::Value nftPageLinks(jtx::Account const &acct, jtx::Account const &owner)
Repair the links in an NFToken directory.
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
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 createOffer(jtx::Account const &account, uint256 const &nftokenID, STAmount const &amount)
Create an NFTokenOffer.
Json::Value acceptSellOffer(jtx::Account const &account, uint256 const &offerIndex)
Accept an NFToken sell offer.
Json::Value acceptBuyOffer(jtx::Account const &account, uint256 const &offerIndex)
Accept an NFToken buy offer.
Json::Value mint(jtx::Account const &account, std::uint32_t nfTokenTaxon)
Mint an NFToken.
Json::Value burn(jtx::Account const &account, uint256 const &nftokenID)
Burn an NFToken.
std::uint32_t ownerCount(Env const &env, Account const &account)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t const tfSellNFToken
constexpr std::uint32_t tfPassive
@ tefINVALID_LEDGER_FIX_TYPE
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t const tfTransferable