rippled
Loading...
Searching...
No Matches
NFTokenDir_test.cpp
1#include <test/jtx.h>
2
3#include <xrpld/app/tx/detail/NFTokenUtils.h>
4
5#include <xrpl/protocol/Feature.h>
6#include <xrpl/protocol/jss.h>
7#include <xrpl/protocol/nftPageMask.h>
8
9#include <initializer_list>
10
11namespace xrpl {
12
14{
15 // printNFTPages is a helper function that may be used for debugging.
16 //
17 // It uses the ledger RPC command to show the NFT pages in the ledger.
18 // This parameter controls how noisy the output is.
19 enum Volume : bool {
20 quiet = false,
21 noisy = true,
22 };
23
24 void
26 {
27 Json::Value jvParams;
28 jvParams[jss::ledger_index] = "current";
29 jvParams[jss::binary] = false;
30 {
31 Json::Value jrr = env.rpc("json", "ledger_data", to_string(jvParams));
32
33 // Iterate the state and print all NFTokenPages.
34 if (!jrr.isMember(jss::result) || !jrr[jss::result].isMember(jss::state))
35 {
36 std::cout << "No ledger state found!" << std::endl;
37 return;
38 }
39 Json::Value& state = jrr[jss::result][jss::state];
40 if (!state.isArray())
41 {
42 std::cout << "Ledger state is not array!" << std::endl;
43 return;
44 }
45 for (Json::UInt i = 0; i < state.size(); ++i)
46 {
47 if (state[i].isMember(sfNFTokens.jsonName) && state[i][sfNFTokens.jsonName].isArray())
48 {
49 std::uint32_t tokenCount = state[i][sfNFTokens.jsonName].size();
50 std::cout << tokenCount << " NFtokens in page " << state[i][jss::index].asString() << std::endl;
51
52 if (vol == noisy)
53 {
54 std::cout << state[i].toStyledString() << std::endl;
55 }
56 else
57 {
58 if (tokenCount > 0)
59 std::cout << "first: " << state[i][sfNFTokens.jsonName][0u].toStyledString() << std::endl;
60 if (tokenCount > 1)
61 std::cout << "last: " << state[i][sfNFTokens.jsonName][tokenCount - 1].toStyledString()
62 << std::endl;
63 }
64 }
65 }
66 }
67 }
68
69 void
71 {
72 // It should be possible to store many consecutive NFTs.
73 testcase("Sequential NFTs");
74
75 using namespace test::jtx;
76 Env env{*this, features};
77
78 // A single minter tends not to mint numerically sequential NFTokens
79 // because the taxon cipher mixes things up. We can override the
80 // cipher, however, and mint many sequential NFTokens with no gaps
81 // between them.
82 //
83 // Here we'll simply mint 100 sequential NFTs. Then we'll create
84 // offers for them to verify that the ledger can find them.
85
86 Account const issuer{"issuer"};
87 Account const buyer{"buyer"};
88 env.fund(XRP(10000), buyer, issuer);
89 env.close();
90
91 // Mint 100 sequential NFTs. Tweak the taxon so zero is always stored.
92 // That's what makes them sequential.
93 constexpr std::size_t nftCount = 100;
95 nftIDs.reserve(nftCount);
96 for (int i = 0; i < nftCount; ++i)
97 {
98 std::uint32_t taxon = toUInt32(nft::cipheredTaxon(i, nft::toTaxon(0)));
99 nftIDs.emplace_back(token::getNextID(env, issuer, taxon, tfTransferable));
100 env(token::mint(issuer, taxon), txflags(tfTransferable));
101 env.close();
102 }
103
104 // Create an offer for each of the NFTs. This verifies that the ledger
105 // can find all of the minted NFTs.
107 for (uint256 const& nftID : nftIDs)
108 {
109 offers.emplace_back(keylet::nftoffer(issuer, env.seq(issuer)).key);
110 env(token::createOffer(issuer, nftID, XRP(0)), txflags((tfSellNFToken)));
111 env.close();
112 }
113
114 // Buyer accepts all of the offers in reverse order.
115 std::reverse(offers.begin(), offers.end());
116 for (uint256 const& offer : offers)
117 {
118 env(token::acceptSellOffer(buyer, offer));
119 env.close();
120 }
121 }
122
123 void
125 {
126 // All NFT IDs with the same low 96 bits must stay on the same NFT page.
127 testcase("Lopsided splits");
128
129 using namespace test::jtx;
130
131 // When a single NFT page exceeds 32 entries, the code is inclined
132 // to split that page into two equal pieces. That's fine, but
133 // the code also needs to keep NFTs with identical low 96-bits on
134 // the same page.
135 //
136 // Here we synthesize cases where there are several NFTs with
137 // identical 96-low-bits in the middle of a page. When that page
138 // is split because it overflows, we need to see that the NFTs
139 // with identical 96-low-bits are all kept on the same page.
140
141 // Lambda that exercises the lopsided splits.
142 auto exerciseLopsided = [this, &features](std::initializer_list<std::string_view const> seeds) {
143 Env env{*this, features};
144
145 // Eventually all of the NFTokens will be owned by buyer.
146 Account const buyer{"buyer"};
147 env.fund(XRP(10000), buyer);
148 env.close();
149
150 // Create accounts for all of the seeds and fund those accounts.
151 std::vector<Account> accounts;
152 accounts.reserve(seeds.size());
153 for (std::string_view seed : seeds)
154 {
155 Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed));
156 env.fund(XRP(10000), account);
157
158 // Do not close the ledger inside the loop. If accounts are
159 // initialized at different ledgers, they will have
160 // different account sequences. That would cause the
161 // accounts to have different NFTokenID sequence numbers.
162 }
163 env.close();
164
165 // All of the accounts create one NFT and and offer that NFT to
166 // buyer.
169 offers.reserve(accounts.size());
170 for (Account const& account : accounts)
171 {
172 // Mint the NFT.
173 uint256 const& nftID = nftIDs.emplace_back(token::getNextID(env, account, 0, tfTransferable));
174 env(token::mint(account, 0), txflags(tfTransferable));
175 env.close();
176
177 // Create an offer to give the NFT to buyer for free.
178 offers.emplace_back(keylet::nftoffer(account, env.seq(account)).key);
179 env(token::createOffer(account, nftID, XRP(0)), token::destination(buyer), txflags((tfSellNFToken)));
180 }
181 env.close();
182
183 // buyer accepts all of the offers.
184 for (uint256 const& offer : offers)
185 {
186 env(token::acceptSellOffer(buyer, offer));
187 env.close();
188 }
189
190 // This can be a good time to look at the NFT pages.
191 // printNFTPages(env, noisy);
192
193 // Verify that all NFTs are owned by buyer and findable in the
194 // ledger by having buyer create sell offers for all of their
195 // NFTs. Attempting to sell an offer that the ledger can't find
196 // generates a non-tesSUCCESS error code.
197 for (uint256 const& nftID : nftIDs)
198 {
199 uint256 const offerID = keylet::nftoffer(buyer, env.seq(buyer)).key;
200 env(token::createOffer(buyer, nftID, XRP(100)), txflags(tfSellNFToken));
201 env.close();
202
203 env(token::cancelOffer(buyer, {offerID}));
204 }
205
206 // Verify that all the NFTs are owned by buyer.
207 Json::Value buyerNFTs = [&env, &buyer]() {
208 Json::Value params;
209 params[jss::account] = buyer.human();
210 params[jss::type] = "state";
211 return env.rpc("json", "account_nfts", to_string(params));
212 }();
213
214 BEAST_EXPECT(buyerNFTs[jss::result][jss::account_nfts].size() == nftIDs.size());
215 for (Json::Value const& ownedNFT : buyerNFTs[jss::result][jss::account_nfts])
216 {
217 uint256 ownedID;
218 BEAST_EXPECT(ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString()));
219 auto const foundIter = std::find(nftIDs.begin(), nftIDs.end(), ownedID);
220
221 // Assuming we find the NFT, erase it so we know it's been
222 // found and can't be found again.
223 if (BEAST_EXPECT(foundIter != nftIDs.end()))
224 nftIDs.erase(foundIter);
225 }
226
227 // All NFTs should now be accounted for, so nftIDs should be
228 // empty.
229 BEAST_EXPECT(nftIDs.empty());
230 };
231
232 // These seeds cause a lopsided split where the new NFT is added
233 // to the upper page.
234 static std::initializer_list<std::string_view const> const splitAndAddToHi{
235 "sp6JS7f14BuwFY8Mw5p3b8jjQBBTK", // 0. 0x1d2932ea
236 "sp6JS7f14BuwFY8Mw6F7X3EiGKazu", // 1. 0x1d2932ea
237 "sp6JS7f14BuwFY8Mw6FxjntJJfKXq", // 2. 0x1d2932ea
238 "sp6JS7f14BuwFY8Mw6eSF1ydEozJg", // 3. 0x1d2932ea
239 "sp6JS7f14BuwFY8Mw6koPB91um2ej", // 4. 0x1d2932ea
240 "sp6JS7f14BuwFY8Mw6m6D64iwquSe", // 5. 0x1d2932ea
241
242 "sp6JS7f14BuwFY8Mw5rC43sN4adC2", // 6. 0x208dbc24
243 "sp6JS7f14BuwFY8Mw65L9DDQqgebz", // 7. 0x208dbc24
244 "sp6JS7f14BuwFY8Mw65nKvU8pPQNn", // 8. 0x208dbc24
245 "sp6JS7f14BuwFY8Mw6bxZLyTrdipw", // 9. 0x208dbc24
246 "sp6JS7f14BuwFY8Mw6d5abucntSoX", // 10. 0x208dbc24
247 "sp6JS7f14BuwFY8Mw6qXK5awrRRP8", // 11. 0x208dbc24
248
249 // These eight need to be kept together by the implementation.
250 "sp6JS7f14BuwFY8Mw66EBtMxoMcCa", // 12. 0x309b67ed
251 "sp6JS7f14BuwFY8Mw66dGfE9jVfGv", // 13. 0x309b67ed
252 "sp6JS7f14BuwFY8Mw6APdZa7PH566", // 14. 0x309b67ed
253 "sp6JS7f14BuwFY8Mw6C3QX5CZyET5", // 15. 0x309b67ed
254 "sp6JS7f14BuwFY8Mw6CSysFf8GvaR", // 16. 0x309b67ed
255 "sp6JS7f14BuwFY8Mw6c7QSDmoAeRV", // 17. 0x309b67ed
256 "sp6JS7f14BuwFY8Mw6mvonveaZhW7", // 18. 0x309b67ed
257 "sp6JS7f14BuwFY8Mw6vtHHG7dYcXi", // 19. 0x309b67ed
258
259 "sp6JS7f14BuwFY8Mw66yppUNxESaw", // 20. 0x40d4b96f
260 "sp6JS7f14BuwFY8Mw6ATYQvobXiDT", // 21. 0x40d4b96f
261 "sp6JS7f14BuwFY8Mw6bis8D1Wa9Uy", // 22. 0x40d4b96f
262 "sp6JS7f14BuwFY8Mw6cTiGCWA8Wfa", // 23. 0x40d4b96f
263 "sp6JS7f14BuwFY8Mw6eAy2fpXmyYf", // 24. 0x40d4b96f
264 "sp6JS7f14BuwFY8Mw6icn58TRs8YG", // 25. 0x40d4b96f
265
266 "sp6JS7f14BuwFY8Mw68tj2eQEWoJt", // 26. 0x503b6ba9
267 "sp6JS7f14BuwFY8Mw6AjnAinNnMHT", // 27. 0x503b6ba9
268 "sp6JS7f14BuwFY8Mw6CKDUwB4LrhL", // 28. 0x503b6ba9
269 "sp6JS7f14BuwFY8Mw6d2yPszEFA6J", // 29. 0x503b6ba9
270 "sp6JS7f14BuwFY8Mw6jcBQBH3PfnB", // 30. 0x503b6ba9
271 "sp6JS7f14BuwFY8Mw6qxx19KSnN1w", // 31. 0x503b6ba9
272
273 // Adding this NFT splits the page. It is added to the upper
274 // page.
275 "sp6JS7f14BuwFY8Mw6ut1hFrqWoY5", // 32. 0x503b6ba9
276 };
277
278 // These seeds cause a lopsided split where the new NFT is added
279 // to the lower page.
280 static std::initializer_list<std::string_view const> const splitAndAddToLo{
281 "sp6JS7f14BuwFY8Mw5p3b8jjQBBTK", // 0. 0x1d2932ea
282 "sp6JS7f14BuwFY8Mw6F7X3EiGKazu", // 1. 0x1d2932ea
283 "sp6JS7f14BuwFY8Mw6FxjntJJfKXq", // 2. 0x1d2932ea
284 "sp6JS7f14BuwFY8Mw6eSF1ydEozJg", // 3. 0x1d2932ea
285 "sp6JS7f14BuwFY8Mw6koPB91um2ej", // 4. 0x1d2932ea
286 "sp6JS7f14BuwFY8Mw6m6D64iwquSe", // 5. 0x1d2932ea
287
288 "sp6JS7f14BuwFY8Mw5rC43sN4adC2", // 6. 0x208dbc24
289 "sp6JS7f14BuwFY8Mw65L9DDQqgebz", // 7. 0x208dbc24
290 "sp6JS7f14BuwFY8Mw65nKvU8pPQNn", // 8. 0x208dbc24
291 "sp6JS7f14BuwFY8Mw6bxZLyTrdipw", // 9. 0x208dbc24
292 "sp6JS7f14BuwFY8Mw6d5abucntSoX", // 10. 0x208dbc24
293 "sp6JS7f14BuwFY8Mw6qXK5awrRRP8", // 11. 0x208dbc24
294
295 // These eight need to be kept together by the implementation.
296 "sp6JS7f14BuwFY8Mw66EBtMxoMcCa", // 12. 0x309b67ed
297 "sp6JS7f14BuwFY8Mw66dGfE9jVfGv", // 13. 0x309b67ed
298 "sp6JS7f14BuwFY8Mw6APdZa7PH566", // 14. 0x309b67ed
299 "sp6JS7f14BuwFY8Mw6C3QX5CZyET5", // 15. 0x309b67ed
300 "sp6JS7f14BuwFY8Mw6CSysFf8GvaR", // 16. 0x309b67ed
301 "sp6JS7f14BuwFY8Mw6c7QSDmoAeRV", // 17. 0x309b67ed
302 "sp6JS7f14BuwFY8Mw6mvonveaZhW7", // 18. 0x309b67ed
303 "sp6JS7f14BuwFY8Mw6vtHHG7dYcXi", // 19. 0x309b67ed
304
305 "sp6JS7f14BuwFY8Mw66yppUNxESaw", // 20. 0x40d4b96f
306 "sp6JS7f14BuwFY8Mw6ATYQvobXiDT", // 21. 0x40d4b96f
307 "sp6JS7f14BuwFY8Mw6bis8D1Wa9Uy", // 22. 0x40d4b96f
308 "sp6JS7f14BuwFY8Mw6cTiGCWA8Wfa", // 23. 0x40d4b96f
309 "sp6JS7f14BuwFY8Mw6eAy2fpXmyYf", // 24. 0x40d4b96f
310 "sp6JS7f14BuwFY8Mw6icn58TRs8YG", // 25. 0x40d4b96f
311
312 "sp6JS7f14BuwFY8Mw68tj2eQEWoJt", // 26. 0x503b6ba9
313 "sp6JS7f14BuwFY8Mw6AjnAinNnMHT", // 27. 0x503b6ba9
314 "sp6JS7f14BuwFY8Mw6CKDUwB4LrhL", // 28. 0x503b6ba9
315 "sp6JS7f14BuwFY8Mw6d2yPszEFA6J", // 29. 0x503b6ba9
316 "sp6JS7f14BuwFY8Mw6jcBQBH3PfnB", // 30. 0x503b6ba9
317 "sp6JS7f14BuwFY8Mw6qxx19KSnN1w", // 31. 0x503b6ba9
318
319 // Adding this NFT splits the page. It is added to the lower
320 // page.
321 "sp6JS7f14BuwFY8Mw6xCigaMwC6Dp", // 32. 0x309b67ed
322 };
323
324 // Run the test cases.
325 exerciseLopsided(splitAndAddToHi);
326 exerciseLopsided(splitAndAddToLo);
327 }
328
329 void
331 {
332 testcase("NFTokenDir");
333
334 using namespace test::jtx;
335
336 // When a single NFT page exceeds 32 entries, the code is inclined
337 // to split that page into two equal pieces. The new page is lower
338 // than the original. There was an off-by-one in the selection of
339 // the index for the new page. This test recreates the problem.
340
341 // Lambda that exercises the split.
342 auto exercise = [this, &features](std::initializer_list<std::string_view const> seeds) {
343 Env env{*this, envconfig(), features, nullptr, beast::severities::kDisabled};
344
345 // Eventually all of the NFTokens will be owned by buyer.
346 Account const buyer{"buyer"};
347 env.fund(XRP(10000), buyer);
348 env.close();
349
350 // Create accounts for all of the seeds and fund those accounts.
351 std::vector<Account> accounts;
352 accounts.reserve(seeds.size());
353 for (std::string_view seed : seeds)
354 {
355 Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed));
356 env.fund(XRP(10000), account);
357
358 // Do not close the ledger inside the loop. If accounts are
359 // initialized at different ledgers, they will have
360 // different account sequences. That would cause the
361 // accounts to have different NFTokenID sequence numbers.
362 }
363 env.close();
364
365 // All of the accounts create one NFT and and offer that NFT to
366 // buyer.
369 offers.reserve(accounts.size());
370 for (Account const& account : accounts)
371 {
372 // Mint the NFT.
373 uint256 const& nftID = nftIDs.emplace_back(token::getNextID(env, account, 0, tfTransferable));
374 env(token::mint(account, 0), txflags(tfTransferable));
375 env.close();
376
377 // Create an offer to give the NFT to buyer for free.
378 offers.emplace_back(keylet::nftoffer(account, env.seq(account)).key);
379 env(token::createOffer(account, nftID, XRP(0)), token::destination(buyer), txflags((tfSellNFToken)));
380 }
381 env.close();
382
383 // buyer accepts all of the but the last. The last offer
384 // causes the page to split.
385 for (std::size_t i = 0; i < offers.size() - 1; ++i)
386 {
387 env(token::acceptSellOffer(buyer, offers[i]));
388 env.close();
389 }
390
391 env(token::acceptSellOffer(buyer, offers.back()));
392 env.close();
393
394 // This can be a good time to look at the NFT pages.
395 // printNFTPages(env, noisy);
396
397 // Verify that all NFTs are owned by buyer and findable in the
398 // ledger by having buyer create sell offers for all of their
399 // NFTs. Attempting to sell an offer that the ledger can't find
400 // generates a non-tesSUCCESS error code.
401 for (uint256 const& nftID : nftIDs)
402 {
403 uint256 const offerID = keylet::nftoffer(buyer, env.seq(buyer)).key;
404 env(token::createOffer(buyer, nftID, XRP(100)), txflags(tfSellNFToken));
405 env.close();
406
407 env(token::cancelOffer(buyer, {offerID}));
408 }
409
410 // Verify that all the NFTs are owned by buyer.
411 Json::Value buyerNFTs = [&env, &buyer]() {
412 Json::Value params;
413 params[jss::account] = buyer.human();
414 params[jss::type] = "state";
415 return env.rpc("json", "account_nfts", to_string(params));
416 }();
417
418 BEAST_EXPECT(buyerNFTs[jss::result][jss::account_nfts].size() == nftIDs.size());
419 for (Json::Value const& ownedNFT : buyerNFTs[jss::result][jss::account_nfts])
420 {
421 uint256 ownedID;
422 BEAST_EXPECT(ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString()));
423 auto const foundIter = std::find(nftIDs.begin(), nftIDs.end(), ownedID);
424
425 // Assuming we find the NFT, erase it so we know it's been
426 // found and can't be found again.
427 if (BEAST_EXPECT(foundIter != nftIDs.end()))
428 nftIDs.erase(foundIter);
429 }
430
431 // All NFTs should now be accounted for, so nftIDs should be
432 // empty.
433 BEAST_EXPECT(nftIDs.empty());
434 };
435
436 // These seeds fill the last 17 entries of the initial page with
437 // equivalent NFTs. The split should keep these together.
438 static std::initializer_list<std::string_view const> const seventeenHi{
439 // These 16 need to be kept together by the implementation.
440 "sp6JS7f14BuwFY8Mw5EYu5z86hKDL", // 0. 0x399187e9
441 "sp6JS7f14BuwFY8Mw5PUAMwc5ygd7", // 1. 0x399187e9
442 "sp6JS7f14BuwFY8Mw5R3xUBcLSeTs", // 2. 0x399187e9
443 "sp6JS7f14BuwFY8Mw5W6oS5sdC3oF", // 3. 0x399187e9
444 "sp6JS7f14BuwFY8Mw5pYc3D9iuLcw", // 4. 0x399187e9
445 "sp6JS7f14BuwFY8Mw5pfGVnhcdp3b", // 5. 0x399187e9
446 "sp6JS7f14BuwFY8Mw6jS6RdEqXqrN", // 6. 0x399187e9
447 "sp6JS7f14BuwFY8Mw6krt6AKbvRXW", // 7. 0x399187e9
448 "sp6JS7f14BuwFY8Mw6mnVBQq7cAN2", // 8. 0x399187e9
449 "sp6JS7f14BuwFY8Mw8ECJxPjmkufQ", // 9. 0x399187e9
450 "sp6JS7f14BuwFY8Mw8asgzcceGWYm", // 10. 0x399187e9
451 "sp6JS7f14BuwFY8MwF6J3FXnPCgL8", // 11. 0x399187e9
452 "sp6JS7f14BuwFY8MwFEud2w5czv5q", // 12. 0x399187e9
453 "sp6JS7f14BuwFY8MwFNxKVqJnx8P5", // 13. 0x399187e9
454 "sp6JS7f14BuwFY8MwFnTCXg3eRidL", // 14. 0x399187e9
455 "sp6JS7f14BuwFY8Mwj47hv1vrDge6", // 15. 0x399187e9
456
457 // These 17 need to be kept together by the implementation.
458 "sp6JS7f14BuwFY8MwjJCwYr9zSfAv", // 16. 0xabb11898
459 "sp6JS7f14BuwFY8MwjYa5yLkgCLuT", // 17. 0xabb11898
460 "sp6JS7f14BuwFY8MwjenxuJ3TH2Bc", // 18. 0xabb11898
461 "sp6JS7f14BuwFY8MwjriN7Ui11NzB", // 19. 0xabb11898
462 "sp6JS7f14BuwFY8Mwk3AuoJNSEo34", // 20. 0xabb11898
463 "sp6JS7f14BuwFY8MwkT36hnRv8hTo", // 21. 0xabb11898
464 "sp6JS7f14BuwFY8MwkTQixEXfi1Cr", // 22. 0xabb11898
465 "sp6JS7f14BuwFY8MwkYJaZM1yTJBF", // 23. 0xabb11898
466 "sp6JS7f14BuwFY8Mwkc4k1uo85qp2", // 24. 0xabb11898
467 "sp6JS7f14BuwFY8Mwkf7cFhF1uuxx", // 25. 0xabb11898
468 "sp6JS7f14BuwFY8MwmCK2un99wb4e", // 26. 0xabb11898
469 "sp6JS7f14BuwFY8MwmETztNHYu2Bx", // 27. 0xabb11898
470 "sp6JS7f14BuwFY8MwmJws9UwRASfR", // 28. 0xabb11898
471 "sp6JS7f14BuwFY8MwoH5PQkGK8tEb", // 29. 0xabb11898
472 "sp6JS7f14BuwFY8MwoVXtP2yCzjJV", // 30. 0xabb11898
473 "sp6JS7f14BuwFY8MwobxRXA9vsTeX", // 31. 0xabb11898
474 "sp6JS7f14BuwFY8Mwos3pc5Gb3ihU", // 32. 0xabb11898
475 };
476
477 // These seeds fill the first entries of the initial page with
478 // equivalent NFTs. The split should keep these together.
479 static std::initializer_list<std::string_view const> const seventeenLo{
480 // These 17 need to be kept together by the implementation.
481 "sp6JS7f14BuwFY8Mw5EYu5z86hKDL", // 0. 0x399187e9
482 "sp6JS7f14BuwFY8Mw5PUAMwc5ygd7", // 1. 0x399187e9
483 "sp6JS7f14BuwFY8Mw5R3xUBcLSeTs", // 2. 0x399187e9
484 "sp6JS7f14BuwFY8Mw5W6oS5sdC3oF", // 3. 0x399187e9
485 "sp6JS7f14BuwFY8Mw5pYc3D9iuLcw", // 4. 0x399187e9
486 "sp6JS7f14BuwFY8Mw5pfGVnhcdp3b", // 5. 0x399187e9
487 "sp6JS7f14BuwFY8Mw6jS6RdEqXqrN", // 6. 0x399187e9
488 "sp6JS7f14BuwFY8Mw6krt6AKbvRXW", // 7. 0x399187e9
489 "sp6JS7f14BuwFY8Mw6mnVBQq7cAN2", // 8. 0x399187e9
490 "sp6JS7f14BuwFY8Mw8ECJxPjmkufQ", // 9. 0x399187e9
491 "sp6JS7f14BuwFY8Mw8asgzcceGWYm", // 10. 0x399187e9
492 "sp6JS7f14BuwFY8MwF6J3FXnPCgL8", // 11. 0x399187e9
493 "sp6JS7f14BuwFY8MwFEud2w5czv5q", // 12. 0x399187e9
494 "sp6JS7f14BuwFY8MwFNxKVqJnx8P5", // 13. 0x399187e9
495 "sp6JS7f14BuwFY8MwFnTCXg3eRidL", // 14. 0x399187e9
496 "sp6JS7f14BuwFY8Mwj47hv1vrDge6", // 15. 0x399187e9
497 "sp6JS7f14BuwFY8Mwj6TYekeeyukh", // 16. 0x399187e9
498
499 // These 16 need to be kept together by the implementation.
500 "sp6JS7f14BuwFY8MwjYa5yLkgCLuT", // 17. 0xabb11898
501 "sp6JS7f14BuwFY8MwjenxuJ3TH2Bc", // 18. 0xabb11898
502 "sp6JS7f14BuwFY8MwjriN7Ui11NzB", // 19. 0xabb11898
503 "sp6JS7f14BuwFY8Mwk3AuoJNSEo34", // 20. 0xabb11898
504 "sp6JS7f14BuwFY8MwkT36hnRv8hTo", // 21. 0xabb11898
505 "sp6JS7f14BuwFY8MwkTQixEXfi1Cr", // 22. 0xabb11898
506 "sp6JS7f14BuwFY8MwkYJaZM1yTJBF", // 23. 0xabb11898
507 "sp6JS7f14BuwFY8Mwkc4k1uo85qp2", // 24. 0xabb11898
508 "sp6JS7f14BuwFY8Mwkf7cFhF1uuxx", // 25. 0xabb11898
509 "sp6JS7f14BuwFY8MwmCK2un99wb4e", // 26. 0xabb11898
510 "sp6JS7f14BuwFY8MwmETztNHYu2Bx", // 27. 0xabb11898
511 "sp6JS7f14BuwFY8MwmJws9UwRASfR", // 28. 0xabb11898
512 "sp6JS7f14BuwFY8MwoH5PQkGK8tEb", // 29. 0xabb11898
513 "sp6JS7f14BuwFY8MwoVXtP2yCzjJV", // 30. 0xabb11898
514 "sp6JS7f14BuwFY8MwobxRXA9vsTeX", // 31. 0xabb11898
515 "sp6JS7f14BuwFY8Mwos3pc5Gb3ihU", // 32. 0xabb11898
516 };
517
518 // Run the test cases.
519 exercise(seventeenHi);
520 exercise(seventeenLo);
521 }
522
523 void
525 {
526 // Exercise the case where 33 NFTs with identical sort
527 // characteristics are owned by the same account.
528 testcase("NFToken too many same");
529
530 using namespace test::jtx;
531
532 Env env{*this, features};
533
534 // Eventually all of the NFTokens will be owned by buyer.
535 Account const buyer{"buyer"};
536 env.fund(XRP(10000), buyer);
537 env.close();
538
539 // Here are 33 seeds that produce identical low 32-bits in their
540 // corresponding AccountIDs.
542 "sp6JS7f14BuwFY8Mw5FnqmbciPvH6", // 0. 0x9a8ebed3
543 "sp6JS7f14BuwFY8Mw5MBGbyMSsXLp", // 1. 0x9a8ebed3
544 "sp6JS7f14BuwFY8Mw5S4PnDyBdKKm", // 2. 0x9a8ebed3
545 "sp6JS7f14BuwFY8Mw6kcXpM2enE35", // 3. 0x9a8ebed3
546 "sp6JS7f14BuwFY8Mw6tuuSMMwyJ44", // 4. 0x9a8ebed3
547 "sp6JS7f14BuwFY8Mw8E8JWLQ1P8pt", // 5. 0x9a8ebed3
548 "sp6JS7f14BuwFY8Mw8WwdgWkCHhEx", // 6. 0x9a8ebed3
549 "sp6JS7f14BuwFY8Mw8XDUYvU6oGhQ", // 7. 0x9a8ebed3
550 "sp6JS7f14BuwFY8Mw8ceVGL4M1zLQ", // 8. 0x9a8ebed3
551 "sp6JS7f14BuwFY8Mw8fdSwLCZWDFd", // 9. 0x9a8ebed3
552 "sp6JS7f14BuwFY8Mw8zuF6Fg65i1E", // 10. 0x9a8ebed3
553 "sp6JS7f14BuwFY8MwF2k7bihVfqes", // 11. 0x9a8ebed3
554 "sp6JS7f14BuwFY8MwF6X24WXGn557", // 12. 0x9a8ebed3
555 "sp6JS7f14BuwFY8MwFMpn7strjekg", // 13. 0x9a8ebed3
556 "sp6JS7f14BuwFY8MwFSdy9sYVrwJs", // 14. 0x9a8ebed3
557 "sp6JS7f14BuwFY8MwFdMcLy9UkrXn", // 15. 0x9a8ebed3
558 "sp6JS7f14BuwFY8MwFdbwFm1AAboa", // 16. 0x9a8ebed3
559 "sp6JS7f14BuwFY8MwFdr5AhKThVtU", // 17. 0x9a8ebed3
560 "sp6JS7f14BuwFY8MwjFc3Q9YatvAw", // 18. 0x9a8ebed3
561 "sp6JS7f14BuwFY8MwjRXcNs1ozEXn", // 19. 0x9a8ebed3
562 "sp6JS7f14BuwFY8MwkQGUKL7v1FBt", // 20. 0x9a8ebed3
563 "sp6JS7f14BuwFY8Mwkamsoxx1wECt", // 21. 0x9a8ebed3
564 "sp6JS7f14BuwFY8Mwm3hus1dG6U8y", // 22. 0x9a8ebed3
565 "sp6JS7f14BuwFY8Mwm589M8vMRpXF", // 23. 0x9a8ebed3
566 "sp6JS7f14BuwFY8MwmJTRJ4Fqz1A3", // 24. 0x9a8ebed3
567 "sp6JS7f14BuwFY8MwmRfy8fer4QbL", // 25. 0x9a8ebed3
568 "sp6JS7f14BuwFY8MwmkkFx1HtgWRx", // 26. 0x9a8ebed3
569 "sp6JS7f14BuwFY8MwmwP9JFdKa4PS", // 27. 0x9a8ebed3
570 "sp6JS7f14BuwFY8MwoXWJLB3ciHfo", // 28. 0x9a8ebed3
571 "sp6JS7f14BuwFY8MwoYc1gTtT2mWL", // 29. 0x9a8ebed3
572 "sp6JS7f14BuwFY8MwogXtHH7FNVoo", // 30. 0x9a8ebed3
573 "sp6JS7f14BuwFY8MwoqYoA9P8gf3r", // 31. 0x9a8ebed3
574 "sp6JS7f14BuwFY8MwoujwMJofGnsA", // 32. 0x9a8ebed3
575 };
576
577 // Create accounts for all of the seeds and fund those accounts.
578 std::vector<Account> accounts;
579 accounts.reserve(seeds.size());
580 for (std::string_view seed : seeds)
581 {
582 Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed));
583 env.fund(XRP(10000), account);
584
585 // Do not close the ledger inside the loop. If accounts are
586 // initialized at different ledgers, they will have different
587 // account sequences. That would cause the accounts to have
588 // different NFTokenID sequence numbers.
589 }
590 env.close();
591
592 // All of the accounts create one NFT and and offer that NFT to buyer.
595 offers.reserve(accounts.size());
596 for (Account const& account : accounts)
597 {
598 // Mint the NFT.
599 uint256 const& nftID = nftIDs.emplace_back(token::getNextID(env, account, 0, tfTransferable));
600 env(token::mint(account, 0), txflags(tfTransferable));
601 env.close();
602
603 // Create an offer to give the NFT to buyer for free.
604 offers.emplace_back(keylet::nftoffer(account, env.seq(account)).key);
605 env(token::createOffer(account, nftID, XRP(0)), token::destination(buyer), txflags((tfSellNFToken)));
606 }
607 env.close();
608
609 // Verify that the low 96 bits of all generated NFTs is identical.
610 uint256 const expectLowBits = nftIDs.front() & nft::pageMask;
611 for (uint256 const& nftID : nftIDs)
612 {
613 BEAST_EXPECT(expectLowBits == (nftID & nft::pageMask));
614 }
615
616 // Remove one NFT and offer from the vectors. This offer is the one
617 // that will overflow the page.
618 nftIDs.pop_back();
619 uint256 const offerForPageOverflow = offers.back();
620 offers.pop_back();
621
622 // buyer accepts all of the offers but one.
623 for (uint256 const& offer : offers)
624 {
625 env(token::acceptSellOffer(buyer, offer));
626 env.close();
627 }
628
629 // buyer accepts the last offer which causes a page overflow.
630 env(token::acceptSellOffer(buyer, offerForPageOverflow), ter(tecNO_SUITABLE_NFTOKEN_PAGE));
631
632 // Verify that all expected NFTs are owned by buyer and findable in
633 // the ledger by having buyer create sell offers for all of their NFTs.
634 // Attempting to sell an offer that the ledger can't find generates
635 // a non-tesSUCCESS error code.
636 for (uint256 const& nftID : nftIDs)
637 {
638 uint256 const offerID = keylet::nftoffer(buyer, env.seq(buyer)).key;
639 env(token::createOffer(buyer, nftID, XRP(100)), txflags(tfSellNFToken));
640 env.close();
641
642 env(token::cancelOffer(buyer, {offerID}));
643 }
644
645 // Verify that all the NFTs are owned by buyer.
646 Json::Value buyerNFTs = [&env, &buyer]() {
647 Json::Value params;
648 params[jss::account] = buyer.human();
649 params[jss::type] = "state";
650 return env.rpc("json", "account_nfts", to_string(params));
651 }();
652
653 BEAST_EXPECT(buyerNFTs[jss::result][jss::account_nfts].size() == nftIDs.size());
654 for (Json::Value const& ownedNFT : buyerNFTs[jss::result][jss::account_nfts])
655 {
656 uint256 ownedID;
657 BEAST_EXPECT(ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString()));
658 auto const foundIter = std::find(nftIDs.begin(), nftIDs.end(), ownedID);
659
660 // Assuming we find the NFT, erase it so we know it's been found
661 // and can't be found again.
662 if (BEAST_EXPECT(foundIter != nftIDs.end()))
663 nftIDs.erase(foundIter);
664 }
665
666 // All NFTs should now be accounted for, so nftIDs should be empty.
667 BEAST_EXPECT(nftIDs.empty());
668
669 TER const expect = tesSUCCESS;
670 env(token::mint(buyer, 0), txflags(tfTransferable), ter(expect));
671 env.close();
672 }
673
674 void
676 {
677 // We'll make a worst case scenario for NFT packing:
678 //
679 // 1. 33 accounts with identical low-32 bits mint 7 consecutive NFTs.
680 // 2. The taxon is manipulated to always be stored as zero.
681 // 3. A single account buys all 7x32 of the 33 NFTs.
682 //
683 // All of the NFTs should be acquired by the buyer.
684 //
685 // Lastly, none of the remaining NFTs should be acquirable by the
686 // buyer. They would cause page overflow.
687
688 testcase("NFToken consecutive packing");
689
690 using namespace test::jtx;
691
692 Env env{*this, features};
693
694 // Eventually all of the NFTokens will be owned by buyer.
695 Account const buyer{"buyer"};
696 env.fund(XRP(10000), buyer);
697 env.close();
698
699 // Here are 33 seeds that produce identical low 32-bits in their
700 // corresponding AccountIDs.
702 "sp6JS7f14BuwFY8Mw56vZeiBuhePx", // 0. 0x115d0525
703 "sp6JS7f14BuwFY8Mw5BodF9tGuTUe", // 1. 0x115d0525
704 "sp6JS7f14BuwFY8Mw5EnhC1cg84J7", // 2. 0x115d0525
705 "sp6JS7f14BuwFY8Mw5P913Cunr2BK", // 3. 0x115d0525
706 "sp6JS7f14BuwFY8Mw5Pru7eLo1XzT", // 4. 0x115d0525
707 "sp6JS7f14BuwFY8Mw61SLUC8UX2m8", // 5. 0x115d0525
708 "sp6JS7f14BuwFY8Mw6AsBF9TpeMpq", // 6. 0x115d0525
709 "sp6JS7f14BuwFY8Mw84XqrBZkU2vE", // 7. 0x115d0525
710 "sp6JS7f14BuwFY8Mw89oSU6dBk3KB", // 8. 0x115d0525
711 "sp6JS7f14BuwFY8Mw89qUKCyDmyzj", // 9. 0x115d0525
712 "sp6JS7f14BuwFY8Mw8GfqQ9VRZ8tm", // 10. 0x115d0525
713 "sp6JS7f14BuwFY8Mw8LtW3VqrqMks", // 11. 0x115d0525
714 "sp6JS7f14BuwFY8Mw8ZrAkJc2sHew", // 12. 0x115d0525
715 "sp6JS7f14BuwFY8Mw8jpkYSNrD3ah", // 13. 0x115d0525
716 "sp6JS7f14BuwFY8MwF2mshd786m3V", // 14. 0x115d0525
717 "sp6JS7f14BuwFY8MwFHfXq9x5NbPY", // 15. 0x115d0525
718 "sp6JS7f14BuwFY8MwFrjWq5LAB8NT", // 16. 0x115d0525
719 "sp6JS7f14BuwFY8Mwj4asgSh6hQZd", // 17. 0x115d0525
720 "sp6JS7f14BuwFY8Mwj7ipFfqBSRrE", // 18. 0x115d0525
721 "sp6JS7f14BuwFY8MwjHqtcvGav8uW", // 19. 0x115d0525
722 "sp6JS7f14BuwFY8MwjLp4sk5fmzki", // 20. 0x115d0525
723 "sp6JS7f14BuwFY8MwjioHuYb3Ytkx", // 21. 0x115d0525
724 "sp6JS7f14BuwFY8MwkRjHPXWi7fGN", // 22. 0x115d0525
725 "sp6JS7f14BuwFY8MwkdVdPV3LjNN1", // 23. 0x115d0525
726 "sp6JS7f14BuwFY8MwkxUtVY5AXZFk", // 24. 0x115d0525
727 "sp6JS7f14BuwFY8Mwm4jQzdfTbY9F", // 25. 0x115d0525
728 "sp6JS7f14BuwFY8MwmCucYAqNp4iF", // 26. 0x115d0525
729 "sp6JS7f14BuwFY8Mwo2bgdFtxBzpF", // 27. 0x115d0525
730 "sp6JS7f14BuwFY8MwoGwD7v4U6qBh", // 28. 0x115d0525
731 "sp6JS7f14BuwFY8MwoUczqFADMoXi", // 29. 0x115d0525
732 "sp6JS7f14BuwFY8MwoY1xZeGd3gAr", // 30. 0x115d0525
733 "sp6JS7f14BuwFY8MwomVCbfkv4kYZ", // 31. 0x115d0525
734 "sp6JS7f14BuwFY8MwoqbrPSr4z13F", // 32. 0x115d0525
735 };
736
737 // Create accounts for all of the seeds and fund those accounts.
738 std::vector<Account> accounts;
739 accounts.reserve(seeds.size());
740 for (std::string_view seed : seeds)
741 {
742 Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed));
743 env.fund(XRP(10000), account);
744
745 // Do not close the ledger inside the loop. If accounts are
746 // initialized at different ledgers, they will have different
747 // account sequences. That would cause the accounts to have
748 // different NFTokenID sequence numbers.
749 }
750 env.close();
751
752 // All of the accounts create seven consecutive NFTs and and offer
753 // those NFTs to buyer.
754 std::array<std::vector<uint256>, 7> nftIDsByPage;
755 for (auto& vec : nftIDsByPage)
756 vec.reserve(accounts.size());
758 for (auto& vec : offers)
759 vec.reserve(accounts.size());
760 for (std::size_t i = 0; i < nftIDsByPage.size(); ++i)
761 {
762 for (Account const& account : accounts)
763 {
764 // Mint the NFT. Tweak the taxon so zero is always stored.
765 std::uint32_t taxon = toUInt32(nft::cipheredTaxon(i, nft::toTaxon(0)));
766
767 uint256 const& nftID =
768 nftIDsByPage[i].emplace_back(token::getNextID(env, account, taxon, tfTransferable));
769 env(token::mint(account, taxon), txflags(tfTransferable));
770 env.close();
771
772 // Create an offer to give the NFT to buyer for free.
773 offers[i].emplace_back(keylet::nftoffer(account, env.seq(account)).key);
774 env(token::createOffer(account, nftID, XRP(0)), token::destination(buyer), txflags((tfSellNFToken)));
775 }
776 }
777 env.close();
778
779 // Verify that the low 96 bits of all generated NFTs of the same
780 // sequence is identical.
781 for (auto const& vec : nftIDsByPage)
782 {
783 uint256 const expectLowBits = vec.front() & nft::pageMask;
784 for (uint256 const& nftID : vec)
785 {
786 BEAST_EXPECT(expectLowBits == (nftID & nft::pageMask));
787 }
788 }
789
790 // Remove one NFT and offer from each of the vectors. These offers
791 // are the ones that will overflow the page.
792 std::vector<uint256> overflowNFTs;
793 overflowNFTs.reserve(nftIDsByPage.size());
794 std::vector<uint256> overflowOffers;
795 overflowOffers.reserve(nftIDsByPage.size());
796
797 for (std::size_t i = 0; i < nftIDsByPage.size(); ++i)
798 {
799 overflowNFTs.push_back(nftIDsByPage[i].back());
800 nftIDsByPage[i].pop_back();
801 BEAST_EXPECT(nftIDsByPage[i].size() == seeds.size() - 1);
802
803 overflowOffers.push_back(offers[i].back());
804 offers[i].pop_back();
805 BEAST_EXPECT(offers[i].size() == seeds.size() - 1);
806 }
807
808 // buyer accepts all of the offers that won't cause an overflow.
809 // Fill the center and outsides first to exercise different boundary
810 // cases.
811 for (int i : std::initializer_list<int>{3, 6, 0, 1, 2, 5, 4})
812 {
813 for (uint256 const& offer : offers[i])
814 {
815 env(token::acceptSellOffer(buyer, offer));
816 env.close();
817 }
818 }
819
820 // buyer accepts the seven offers that would cause page overflows if
821 // the transaction succeeded.
822 for (uint256 const& offer : overflowOffers)
823 {
824 env(token::acceptSellOffer(buyer, offer), ter(tecNO_SUITABLE_NFTOKEN_PAGE));
825 env.close();
826 }
827
828 // Verify that all expected NFTs are owned by buyer and findable in
829 // the ledger by having buyer create sell offers for all of their NFTs.
830 // Attempting to sell an offer that the ledger can't find generates
831 // a non-tesSUCCESS error code.
832 for (auto const& vec : nftIDsByPage)
833 {
834 for (uint256 const& nftID : vec)
835 {
836 env(token::createOffer(buyer, nftID, XRP(100)), txflags(tfSellNFToken));
837 env.close();
838 }
839 }
840
841 // See what the account_objects command does with "nft_offer".
842 {
843 Json::Value ownedNftOffers(Json::arrayValue);
844 std::string marker;
845 do
846 {
847 Json::Value buyerOffers = [&env, &buyer, &marker]() {
848 Json::Value params;
849 params[jss::account] = buyer.human();
850 params[jss::type] = jss::nft_offer;
851
852 if (!marker.empty())
853 params[jss::marker] = marker;
854 return env.rpc("json", "account_objects", to_string(params));
855 }();
856
857 marker.clear();
858 if (buyerOffers.isMember(jss::result))
859 {
860 Json::Value& result = buyerOffers[jss::result];
861
862 if (result.isMember(jss::marker))
863 marker = result[jss::marker].asString();
864
865 if (result.isMember(jss::account_objects))
866 {
867 Json::Value& someOffers = result[jss::account_objects];
868 for (std::size_t i = 0; i < someOffers.size(); ++i)
869 ownedNftOffers.append(someOffers[i]);
870 }
871 }
872 } while (!marker.empty());
873
874 // Verify there are as many offers are there are NFTs.
875 {
876 std::size_t totalOwnedNFTs = 0;
877 for (auto const& vec : nftIDsByPage)
878 totalOwnedNFTs += vec.size();
879 BEAST_EXPECT(ownedNftOffers.size() == totalOwnedNFTs);
880 }
881
882 // Cancel all the offers.
883 {
884 std::vector<uint256> cancelOffers;
885 cancelOffers.reserve(ownedNftOffers.size());
886
887 for (auto const& offer : ownedNftOffers)
888 {
889 if (offer.isMember(jss::index))
890 {
891 uint256 offerIndex;
892 if (offerIndex.parseHex(offer[jss::index].asString()))
893 cancelOffers.push_back(offerIndex);
894 }
895 }
896 env(token::cancelOffer(buyer, cancelOffers));
897 env.close();
898 }
899
900 // account_objects should no longer return any "nft_offer"s.
901 Json::Value remainingOffers = [&env, &buyer]() {
902 Json::Value params;
903 params[jss::account] = buyer.human();
904 params[jss::type] = jss::nft_offer;
905
906 return env.rpc("json", "account_objects", to_string(params));
907 }();
908 BEAST_EXPECT(
909 remainingOffers.isMember(jss::result) && remainingOffers[jss::result].isMember(jss::account_objects) &&
910 remainingOffers[jss::result][jss::account_objects].size() == 0);
911 }
912
913 // Verify that the ledger reports all of the NFTs owned by buyer.
914 // Use the account_nfts rpc call to get the values.
915 Json::Value ownedNFTs(Json::arrayValue);
916 std::string marker;
917 do
918 {
919 Json::Value buyerNFTs = [&env, &buyer, &marker]() {
920 Json::Value params;
921 params[jss::account] = buyer.human();
922 params[jss::type] = "state";
923
924 if (!marker.empty())
925 params[jss::marker] = marker;
926 return env.rpc("json", "account_nfts", to_string(params));
927 }();
928
929 marker.clear();
930 if (buyerNFTs.isMember(jss::result))
931 {
932 Json::Value& result = buyerNFTs[jss::result];
933
934 if (result.isMember(jss::marker))
935 marker = result[jss::marker].asString();
936
937 if (result.isMember(jss::account_nfts))
938 {
939 Json::Value& someNFTs = result[jss::account_nfts];
940 for (std::size_t i = 0; i < someNFTs.size(); ++i)
941 ownedNFTs.append(someNFTs[i]);
942 }
943 }
944 } while (!marker.empty());
945
946 // Copy all of the nftIDs into a set to make validation easier.
947 std::set<uint256> allNftIDs;
948 for (auto& vec : nftIDsByPage)
949 allNftIDs.insert(vec.begin(), vec.end());
950
951 BEAST_EXPECT(ownedNFTs.size() == allNftIDs.size());
952
953 for (Json::Value const& ownedNFT : ownedNFTs)
954 {
955 if (ownedNFT.isMember(sfNFTokenID.jsonName))
956 {
957 uint256 ownedID;
958 BEAST_EXPECT(ownedID.parseHex(ownedNFT[sfNFTokenID.jsonName].asString()));
959 auto const foundIter = allNftIDs.find(ownedID);
960
961 // Assuming we find the NFT, erase it so we know it's been found
962 // and can't be found again.
963 if (BEAST_EXPECT(foundIter != allNftIDs.end()))
964 allNftIDs.erase(foundIter);
965 }
966 }
967
968 // All NFTs should now be accounted for, so allNftIDs should be empty.
969 BEAST_EXPECT(allNftIDs.empty());
970 }
971
972 void
974 {
975 testConsecutiveNFTs(features);
976 testLopsidedSplits(features);
977 testNFTokenDir(features);
978 testTooManyEquivalent(features);
979 testConsecutivePacking(features);
980 }
981
982public:
983 void
984 run() override
985 {
986 using namespace test::jtx;
987 FeatureBitset const all{testable_amendments()};
988
990 }
991};
992
993BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDir, app, xrpl, 1);
994
995} // namespace xrpl
996
997// Seed that produces an account with the low-32 bits == 0xFFFFFFFF in
998// case it is needed for future testing:
999//
1000// sp6JS7f14BuwFY8MwFe95Vpi9Znjs
1001//
1002
1003// Sets of related accounts.
1004//
1005// Identifying the seeds of accounts that generate account IDs with the
1006// same low 32 bits takes a while. However several sets of accounts with
1007// that relationship have been located. In case these sets of accounts are
1008// needed for future testing scenarios they are recorded below.
1009#if 0
101034 account seeds that produce account IDs with low 32-bits 0x399187e9:
1011 sp6JS7f14BuwFY8Mw5EYu5z86hKDL
1012 sp6JS7f14BuwFY8Mw5PUAMwc5ygd7
1013 sp6JS7f14BuwFY8Mw5R3xUBcLSeTs
1014 sp6JS7f14BuwFY8Mw5W6oS5sdC3oF
1015 sp6JS7f14BuwFY8Mw5pYc3D9iuLcw
1016 sp6JS7f14BuwFY8Mw5pfGVnhcdp3b
1017 sp6JS7f14BuwFY8Mw6jS6RdEqXqrN
1018 sp6JS7f14BuwFY8Mw6krt6AKbvRXW
1019 sp6JS7f14BuwFY8Mw6mnVBQq7cAN2
1020 sp6JS7f14BuwFY8Mw8ECJxPjmkufQ
1021 sp6JS7f14BuwFY8Mw8asgzcceGWYm
1022 sp6JS7f14BuwFY8MwF6J3FXnPCgL8
1023 sp6JS7f14BuwFY8MwFEud2w5czv5q
1024 sp6JS7f14BuwFY8MwFNxKVqJnx8P5
1025 sp6JS7f14BuwFY8MwFnTCXg3eRidL
1026 sp6JS7f14BuwFY8Mwj47hv1vrDge6
1027 sp6JS7f14BuwFY8Mwj6TYekeeyukh
1028 sp6JS7f14BuwFY8MwjFjsRDerz7jb
1029 sp6JS7f14BuwFY8Mwjrj9mHTLBrcX
1030 sp6JS7f14BuwFY8MwkKcJi3zMzAea
1031 sp6JS7f14BuwFY8MwkYTDdnYRm9z4
1032 sp6JS7f14BuwFY8Mwkq8ei4D8uPNd
1033 sp6JS7f14BuwFY8Mwm2pFruxbnJRd
1034 sp6JS7f14BuwFY8MwmJV2ZnAjpC2g
1035 sp6JS7f14BuwFY8MwmTFMPHQHfVYF
1036 sp6JS7f14BuwFY8MwmkG2jXEgqiud
1037 sp6JS7f14BuwFY8Mwms3xEh5tMDTw
1038 sp6JS7f14BuwFY8MwmtipW4D8giZ9
1039 sp6JS7f14BuwFY8MwoRQBZm4KUUeE
1040 sp6JS7f14BuwFY8MwoVey94QpXcrc
1041 sp6JS7f14BuwFY8MwoZiuUoUTo3VG
1042 sp6JS7f14BuwFY8MwonFFDLT4bHAZ
1043 sp6JS7f14BuwFY8MwooGphD4hefBQ
1044 sp6JS7f14BuwFY8MwoxDp3dmX6q5N
1045
104634 account seeds that produce account IDs with low 32-bits 0x473f2c9a:
1047 sp6JS7f14BuwFY8Mw53ktgqmv5Bmz
1048 sp6JS7f14BuwFY8Mw5KPb2Kz7APFX
1049 sp6JS7f14BuwFY8Mw5Xx4A6HRTPEE
1050 sp6JS7f14BuwFY8Mw5y6qZFNAo358
1051 sp6JS7f14BuwFY8Mw6kdaBg1QrZfn
1052 sp6JS7f14BuwFY8Mw8QmTfLMAZ5K1
1053 sp6JS7f14BuwFY8Mw8cbRRVcCEELr
1054 sp6JS7f14BuwFY8Mw8gQvJebmxvDG
1055 sp6JS7f14BuwFY8Mw8qPQurwu3P7Y
1056 sp6JS7f14BuwFY8MwFS4PEVKmuPy5
1057 sp6JS7f14BuwFY8MwFUQM1rAsQ8tS
1058 sp6JS7f14BuwFY8MwjJBZCkuwsRnM
1059 sp6JS7f14BuwFY8MwjTdS8vZhX5E9
1060 sp6JS7f14BuwFY8MwjhSmWCbNhd25
1061 sp6JS7f14BuwFY8MwjwkpqwZsDBw9
1062 sp6JS7f14BuwFY8MwjyET4p6eqd5J
1063 sp6JS7f14BuwFY8MwkMNAe4JhnG7E
1064 sp6JS7f14BuwFY8MwkRRpnT93UWWS
1065 sp6JS7f14BuwFY8MwkY9CvB22RvUe
1066 sp6JS7f14BuwFY8Mwkhw9VxXqmTr7
1067 sp6JS7f14BuwFY8MwkmgaTat7eFa7
1068 sp6JS7f14BuwFY8Mwkq5SxGGv1oLH
1069 sp6JS7f14BuwFY8MwmCBM5p5bTg6y
1070 sp6JS7f14BuwFY8MwmmmXaVah64dB
1071 sp6JS7f14BuwFY8Mwo7R7Cn614v9V
1072 sp6JS7f14BuwFY8MwoCAG1na7GR2M
1073 sp6JS7f14BuwFY8MwoDuPvJS4gG7C
1074 sp6JS7f14BuwFY8MwoMMowSyPQLfy
1075 sp6JS7f14BuwFY8MwoRqDiwTNsTBm
1076 sp6JS7f14BuwFY8MwoWbBWtjpB7pg
1077 sp6JS7f14BuwFY8Mwoi1AEeELGecF
1078 sp6JS7f14BuwFY8MwopGP6Lo5byuj
1079 sp6JS7f14BuwFY8MwoufkXGHp2VW8
1080 sp6JS7f14BuwFY8MwowGeagFQY32k
1081
108234 account seeds that produce account IDs with low 32-bits 0x4d59f0d1:
1083 sp6JS7f14BuwFY8Mw5CsNgH64zxK7
1084 sp6JS7f14BuwFY8Mw5Dg4wi2E344h
1085 sp6JS7f14BuwFY8Mw5ErV949Zh2PX
1086 sp6JS7f14BuwFY8Mw5p4nsQvEUE1s
1087 sp6JS7f14BuwFY8Mw8LGnkbaP68Gn
1088 sp6JS7f14BuwFY8Mw8aq6RCBc3iHo
1089 sp6JS7f14BuwFY8Mw8bkWaGoKYT6e
1090 sp6JS7f14BuwFY8Mw8qrCuXnzAXVj
1091 sp6JS7f14BuwFY8MwFDKcPAHPHJTm
1092 sp6JS7f14BuwFY8MwFUXJs4unfgNu
1093 sp6JS7f14BuwFY8MwFj9Yv5LjshD9
1094 sp6JS7f14BuwFY8Mwj3H73nmq5UaC
1095 sp6JS7f14BuwFY8MwjHSYShis1Yhk
1096 sp6JS7f14BuwFY8MwjpfE1HVo8UP1
1097 sp6JS7f14BuwFY8Mwk6JE1SXUuiNc
1098 sp6JS7f14BuwFY8MwkASgxEjEnFmU
1099 sp6JS7f14BuwFY8MwkGNY8kg7R6RK
1100 sp6JS7f14BuwFY8MwkHinNZ8SYBQu
1101 sp6JS7f14BuwFY8MwkXLCW1hbhGya
1102 sp6JS7f14BuwFY8MwkZ7mWrYK9YtU
1103 sp6JS7f14BuwFY8MwkdFSqNB5DbKL
1104 sp6JS7f14BuwFY8Mwm3jdBaCAx8H6
1105 sp6JS7f14BuwFY8Mwm3rk5hEwDRtY
1106 sp6JS7f14BuwFY8Mwm77a2ULuwxu4
1107 sp6JS7f14BuwFY8MwmJpY7braKLaN
1108 sp6JS7f14BuwFY8MwmKHQjG4XiZ6g
1109 sp6JS7f14BuwFY8Mwmmv8Y3wyUDzs
1110 sp6JS7f14BuwFY8MwmucFe1WgqtwG
1111 sp6JS7f14BuwFY8Mwo1EjdU1bznZR
1112 sp6JS7f14BuwFY8MwoJiqankkU5uR
1113 sp6JS7f14BuwFY8MwoLnvQ6zdqbKw
1114 sp6JS7f14BuwFY8MwoUGeJ319eu48
1115 sp6JS7f14BuwFY8MwoYf135tQjHP4
1116 sp6JS7f14BuwFY8MwogeF6M6SAyid
1117
111834 account seeds that produce account IDs with low 32-bits 0xabb11898:
1119 sp6JS7f14BuwFY8Mw5DgiYaNVSb1G
1120 sp6JS7f14BuwFY8Mw5k6e94TMvuox
1121 sp6JS7f14BuwFY8Mw5tTSN7KzYxiT
1122 sp6JS7f14BuwFY8Mw61XV6m33utif
1123 sp6JS7f14BuwFY8Mw87jKfrjiENCb
1124 sp6JS7f14BuwFY8Mw8AFtxxFiRtJG
1125 sp6JS7f14BuwFY8Mw8cosAVExzbeE
1126 sp6JS7f14BuwFY8Mw8fmkQ63zE8WQ
1127 sp6JS7f14BuwFY8Mw8iYSsxNbDN6D
1128 sp6JS7f14BuwFY8Mw8wTZdGRJyyM1
1129 sp6JS7f14BuwFY8Mw8z7xEh3qBGr7
1130 sp6JS7f14BuwFY8MwFL5gpKQWZj7g
1131 sp6JS7f14BuwFY8MwFPeZchXQnRZ5
1132 sp6JS7f14BuwFY8MwFSPxWSJVoU29
1133 sp6JS7f14BuwFY8MwFYyVkqX8kvRm
1134 sp6JS7f14BuwFY8MwFcbVikUEwJvk
1135 sp6JS7f14BuwFY8MwjF7NcZk1NctK
1136 sp6JS7f14BuwFY8MwjJCwYr9zSfAv
1137 sp6JS7f14BuwFY8MwjYa5yLkgCLuT
1138 sp6JS7f14BuwFY8MwjenxuJ3TH2Bc
1139 sp6JS7f14BuwFY8MwjriN7Ui11NzB
1140 sp6JS7f14BuwFY8Mwk3AuoJNSEo34
1141 sp6JS7f14BuwFY8MwkT36hnRv8hTo
1142 sp6JS7f14BuwFY8MwkTQixEXfi1Cr
1143 sp6JS7f14BuwFY8MwkYJaZM1yTJBF
1144 sp6JS7f14BuwFY8Mwkc4k1uo85qp2
1145 sp6JS7f14BuwFY8Mwkf7cFhF1uuxx
1146 sp6JS7f14BuwFY8MwmCK2un99wb4e
1147 sp6JS7f14BuwFY8MwmETztNHYu2Bx
1148 sp6JS7f14BuwFY8MwmJws9UwRASfR
1149 sp6JS7f14BuwFY8MwoH5PQkGK8tEb
1150 sp6JS7f14BuwFY8MwoVXtP2yCzjJV
1151 sp6JS7f14BuwFY8MwobxRXA9vsTeX
1152 sp6JS7f14BuwFY8Mwos3pc5Gb3ihU
1153
115434 account seeds that produce account IDs with low 32-bits 0xce627322:
1155 sp6JS7f14BuwFY8Mw5Ck6i83pGNh3
1156 sp6JS7f14BuwFY8Mw5FKuwTxjAdH1
1157 sp6JS7f14BuwFY8Mw5FVKkEn6TkLH
1158 sp6JS7f14BuwFY8Mw5NbQwLwHDd5v
1159 sp6JS7f14BuwFY8Mw5X1dbz3msZaZ
1160 sp6JS7f14BuwFY8Mw6qv6qaXNeP74
1161 sp6JS7f14BuwFY8Mw81SXagUeutCw
1162 sp6JS7f14BuwFY8Mw84Ph7Qa8kwwk
1163 sp6JS7f14BuwFY8Mw8Hp4gFyU3Qko
1164 sp6JS7f14BuwFY8Mw8Kt8bAKredSx
1165 sp6JS7f14BuwFY8Mw8XHK3VKRQ7v7
1166 sp6JS7f14BuwFY8Mw8eGyWxZGHY6v
1167 sp6JS7f14BuwFY8Mw8iU5CLyHVcD2
1168 sp6JS7f14BuwFY8Mw8u3Zr26Ar914
1169 sp6JS7f14BuwFY8MwF2Kcdxtjzjv8
1170 sp6JS7f14BuwFY8MwFLmPWb6rbxNg
1171 sp6JS7f14BuwFY8MwFUu8s7UVuxuJ
1172 sp6JS7f14BuwFY8MwFYBaatwHxAJ8
1173 sp6JS7f14BuwFY8Mwjg6hFkeHwoqG
1174 sp6JS7f14BuwFY8MwjjycJojy2ufk
1175 sp6JS7f14BuwFY8MwkEWoxcSKGPXv
1176 sp6JS7f14BuwFY8MwkMe7wLkEUsQT
1177 sp6JS7f14BuwFY8MwkvyKLaPUc4FS
1178 sp6JS7f14BuwFY8Mwm8doqXPKZmVQ
1179 sp6JS7f14BuwFY8Mwm9r3No8yQ8Tx
1180 sp6JS7f14BuwFY8Mwm9w6dks68W9B
1181 sp6JS7f14BuwFY8MwmMPrv9sCdbpS
1182 sp6JS7f14BuwFY8MwmPAvs3fcQNja
1183 sp6JS7f14BuwFY8MwmS5jasapfcnJ
1184 sp6JS7f14BuwFY8MwmU2L3qJEhnuA
1185 sp6JS7f14BuwFY8MwoAQYmiBnW7fM
1186 sp6JS7f14BuwFY8MwoBkkkXrPmkKF
1187 sp6JS7f14BuwFY8MwonfmxPo6tkvC
1188 sp6JS7f14BuwFY8MwouZFwhiNcYq6
1189
119034 account seeds that produce account IDs with low 32-bits 0xe29643e8:
1191 sp6JS7f14BuwFY8Mw5EfAavcXAh2k
1192 sp6JS7f14BuwFY8Mw5LhFjLkFSCVF
1193 sp6JS7f14BuwFY8Mw5bRfEv5HgdBh
1194 sp6JS7f14BuwFY8Mw5d6sPcKzypKN
1195 sp6JS7f14BuwFY8Mw5rcqDtk1fACP
1196 sp6JS7f14BuwFY8Mw5xkxRq1Notzv
1197 sp6JS7f14BuwFY8Mw66fbkdw5WYmt
1198 sp6JS7f14BuwFY8Mw6diEG8sZ7Fx7
1199 sp6JS7f14BuwFY8Mw6v2r1QhG7xc1
1200 sp6JS7f14BuwFY8Mw6zP6DHCTx2Fd
1201 sp6JS7f14BuwFY8Mw8B3n39JKuFkk
1202 sp6JS7f14BuwFY8Mw8FmBvqYw7uqn
1203 sp6JS7f14BuwFY8Mw8KEaftb1eRwu
1204 sp6JS7f14BuwFY8Mw8WJ1qKkegj9N
1205 sp6JS7f14BuwFY8Mw8r8cAZEkq2BS
1206 sp6JS7f14BuwFY8MwFKPxxwF65gZh
1207 sp6JS7f14BuwFY8MwFKhaF8APcN5H
1208 sp6JS7f14BuwFY8MwFN2buJn4BgYC
1209 sp6JS7f14BuwFY8MwFUTe175MjP3x
1210 sp6JS7f14BuwFY8MwFZhmRDb53NNb
1211 sp6JS7f14BuwFY8MwFa2Azn5nU2WS
1212 sp6JS7f14BuwFY8MwjNNt91hwgkn7
1213 sp6JS7f14BuwFY8MwjdiYt6ChACe7
1214 sp6JS7f14BuwFY8Mwk5qFVQ48Mmr9
1215 sp6JS7f14BuwFY8MwkGvCj7pNf1zG
1216 sp6JS7f14BuwFY8MwkY9UcN2D2Fzs
1217 sp6JS7f14BuwFY8MwkpGvSk9G9RyT
1218 sp6JS7f14BuwFY8MwmGQ7nJf1eEzV
1219 sp6JS7f14BuwFY8MwmQLjGsYdyAmV
1220 sp6JS7f14BuwFY8MwmZ8usztKvikT
1221 sp6JS7f14BuwFY8MwobyMLC2hQdFR
1222 sp6JS7f14BuwFY8MwoiRtwUecZeJ5
1223 sp6JS7f14BuwFY8MwojHjKsUzj1KJ
1224 sp6JS7f14BuwFY8Mwop29anGAjidU
1225
122633 account seeds that produce account IDs with low 32-bits 0x115d0525:
1227 sp6JS7f14BuwFY8Mw56vZeiBuhePx
1228 sp6JS7f14BuwFY8Mw5BodF9tGuTUe
1229 sp6JS7f14BuwFY8Mw5EnhC1cg84J7
1230 sp6JS7f14BuwFY8Mw5P913Cunr2BK
1231 sp6JS7f14BuwFY8Mw5Pru7eLo1XzT
1232 sp6JS7f14BuwFY8Mw61SLUC8UX2m8
1233 sp6JS7f14BuwFY8Mw6AsBF9TpeMpq
1234 sp6JS7f14BuwFY8Mw84XqrBZkU2vE
1235 sp6JS7f14BuwFY8Mw89oSU6dBk3KB
1236 sp6JS7f14BuwFY8Mw89qUKCyDmyzj
1237 sp6JS7f14BuwFY8Mw8GfqQ9VRZ8tm
1238 sp6JS7f14BuwFY8Mw8LtW3VqrqMks
1239 sp6JS7f14BuwFY8Mw8ZrAkJc2sHew
1240 sp6JS7f14BuwFY8Mw8jpkYSNrD3ah
1241 sp6JS7f14BuwFY8MwF2mshd786m3V
1242 sp6JS7f14BuwFY8MwFHfXq9x5NbPY
1243 sp6JS7f14BuwFY8MwFrjWq5LAB8NT
1244 sp6JS7f14BuwFY8Mwj4asgSh6hQZd
1245 sp6JS7f14BuwFY8Mwj7ipFfqBSRrE
1246 sp6JS7f14BuwFY8MwjHqtcvGav8uW
1247 sp6JS7f14BuwFY8MwjLp4sk5fmzki
1248 sp6JS7f14BuwFY8MwjioHuYb3Ytkx
1249 sp6JS7f14BuwFY8MwkRjHPXWi7fGN
1250 sp6JS7f14BuwFY8MwkdVdPV3LjNN1
1251 sp6JS7f14BuwFY8MwkxUtVY5AXZFk
1252 sp6JS7f14BuwFY8Mwm4jQzdfTbY9F
1253 sp6JS7f14BuwFY8MwmCucYAqNp4iF
1254 sp6JS7f14BuwFY8Mwo2bgdFtxBzpF
1255 sp6JS7f14BuwFY8MwoGwD7v4U6qBh
1256 sp6JS7f14BuwFY8MwoUczqFADMoXi
1257 sp6JS7f14BuwFY8MwoY1xZeGd3gAr
1258 sp6JS7f14BuwFY8MwomVCbfkv4kYZ
1259 sp6JS7f14BuwFY8MwoqbrPSr4z13F
1260
126133 account seeds that produce account IDs with low 32-bits 0x304033aa:
1262 sp6JS7f14BuwFY8Mw5DaUP9agF5e1
1263 sp6JS7f14BuwFY8Mw5ohbtmPN4yGN
1264 sp6JS7f14BuwFY8Mw5rRsA5fcoTAQ
1265 sp6JS7f14BuwFY8Mw6zpYHMY3m6KT
1266 sp6JS7f14BuwFY8Mw86BzQq4sTnoW
1267 sp6JS7f14BuwFY8Mw8CCpnfvmGdV7
1268 sp6JS7f14BuwFY8Mw8DRjUDaBcFco
1269 sp6JS7f14BuwFY8Mw8cL7GPo3zZN7
1270 sp6JS7f14BuwFY8Mw8y6aeYVtH6qt
1271 sp6JS7f14BuwFY8MwFZR3PtVTCdUH
1272 sp6JS7f14BuwFY8MwFcdcdbgz7m3s
1273 sp6JS7f14BuwFY8MwjdnJDiUxEBRR
1274 sp6JS7f14BuwFY8MwjhxWgSntqrFe
1275 sp6JS7f14BuwFY8MwjrSHEhZ8CUM1
1276 sp6JS7f14BuwFY8MwjzkEeSTc9ZYf
1277 sp6JS7f14BuwFY8MwkBZSk9JhaeCB
1278 sp6JS7f14BuwFY8MwkGfwNY4i2iiU
1279 sp6JS7f14BuwFY8MwknjtZd2oU2Ff
1280 sp6JS7f14BuwFY8Mwkszsqd3ok9NE
1281 sp6JS7f14BuwFY8Mwm58A81MAMvgZ
1282 sp6JS7f14BuwFY8MwmiPTWysuDJCH
1283 sp6JS7f14BuwFY8MwmxhiNeLfD76r
1284 sp6JS7f14BuwFY8Mwo7SPdkwpGrFH
1285 sp6JS7f14BuwFY8MwoANq4F1Sj3qH
1286 sp6JS7f14BuwFY8MwoVjcHufAkd6L
1287 sp6JS7f14BuwFY8MwoVxHBXdaxzhm
1288 sp6JS7f14BuwFY8MwoZ2oTjBNfLpm
1289 sp6JS7f14BuwFY8Mwoc9swzyotFVD
1290 sp6JS7f14BuwFY8MwogMqVRwVEcQ9
1291 sp6JS7f14BuwFY8MwohMm7WxwnFqH
1292 sp6JS7f14BuwFY8MwopUcpZHuF8BH
1293 sp6JS7f14BuwFY8Mwor6rW6SS7tiB
1294 sp6JS7f14BuwFY8MwoxyaqYz4Ngsb
1295
129633 account seeds that produce account IDs with low 32-bits 0x42d4e09c:
1297 sp6JS7f14BuwFY8Mw58NSZH9EaUxQ
1298 sp6JS7f14BuwFY8Mw5JByk1pgPpL7
1299 sp6JS7f14BuwFY8Mw5YrJJuXnkHVB
1300 sp6JS7f14BuwFY8Mw5kZe2ZzNSnKR
1301 sp6JS7f14BuwFY8Mw6eXHTsbwi1U7
1302 sp6JS7f14BuwFY8Mw6gqN7HHDDKSh
1303 sp6JS7f14BuwFY8Mw6zw8L1sSSR53
1304 sp6JS7f14BuwFY8Mw8E4WqSKKbksy
1305 sp6JS7f14BuwFY8MwF3V9gemqJtND
1306 sp6JS7f14BuwFY8Mwj4j46LHWZuY6
1307 sp6JS7f14BuwFY8MwjF5i8vh4Ezjy
1308 sp6JS7f14BuwFY8MwjJZpEKgMpUAt
1309 sp6JS7f14BuwFY8MwjWL7LfnzNUuh
1310 sp6JS7f14BuwFY8Mwk7Y1csGuqAhX
1311 sp6JS7f14BuwFY8MwkB1HVH17hN5W
1312 sp6JS7f14BuwFY8MwkBntH7BZZupu
1313 sp6JS7f14BuwFY8MwkEy4rMbNHG9P
1314 sp6JS7f14BuwFY8MwkKz4LYesZeiN
1315 sp6JS7f14BuwFY8MwkUrXyo9gMDPM
1316 sp6JS7f14BuwFY8MwkV2hySsxej1G
1317 sp6JS7f14BuwFY8MwkozhTVN12F9C
1318 sp6JS7f14BuwFY8MwkpkzGB3sFJw5
1319 sp6JS7f14BuwFY8Mwks3zDZLGrhdn
1320 sp6JS7f14BuwFY8MwktG1KCS7L2wW
1321 sp6JS7f14BuwFY8Mwm1jVFsafwcYx
1322 sp6JS7f14BuwFY8Mwm8hmrU6g5Wd6
1323 sp6JS7f14BuwFY8MwmFvstfRF7e2f
1324 sp6JS7f14BuwFY8MwmeRohi6m5fs8
1325 sp6JS7f14BuwFY8MwmmU96RHUaRZL
1326 sp6JS7f14BuwFY8MwoDFzteYqaUh4
1327 sp6JS7f14BuwFY8MwoPkTf5tDykPF
1328 sp6JS7f14BuwFY8MwoSbMaDtiMoDN
1329 sp6JS7f14BuwFY8MwoVL1vY1CysjR
1330
133133 account seeds that produce account IDs with low 32-bits 0x9a8ebed3:
1332 sp6JS7f14BuwFY8Mw5FnqmbciPvH6
1333 sp6JS7f14BuwFY8Mw5MBGbyMSsXLp
1334 sp6JS7f14BuwFY8Mw5S4PnDyBdKKm
1335 sp6JS7f14BuwFY8Mw6kcXpM2enE35
1336 sp6JS7f14BuwFY8Mw6tuuSMMwyJ44
1337 sp6JS7f14BuwFY8Mw8E8JWLQ1P8pt
1338 sp6JS7f14BuwFY8Mw8WwdgWkCHhEx
1339 sp6JS7f14BuwFY8Mw8XDUYvU6oGhQ
1340 sp6JS7f14BuwFY8Mw8ceVGL4M1zLQ
1341 sp6JS7f14BuwFY8Mw8fdSwLCZWDFd
1342 sp6JS7f14BuwFY8Mw8zuF6Fg65i1E
1343 sp6JS7f14BuwFY8MwF2k7bihVfqes
1344 sp6JS7f14BuwFY8MwF6X24WXGn557
1345 sp6JS7f14BuwFY8MwFMpn7strjekg
1346 sp6JS7f14BuwFY8MwFSdy9sYVrwJs
1347 sp6JS7f14BuwFY8MwFdMcLy9UkrXn
1348 sp6JS7f14BuwFY8MwFdbwFm1AAboa
1349 sp6JS7f14BuwFY8MwFdr5AhKThVtU
1350 sp6JS7f14BuwFY8MwjFc3Q9YatvAw
1351 sp6JS7f14BuwFY8MwjRXcNs1ozEXn
1352 sp6JS7f14BuwFY8MwkQGUKL7v1FBt
1353 sp6JS7f14BuwFY8Mwkamsoxx1wECt
1354 sp6JS7f14BuwFY8Mwm3hus1dG6U8y
1355 sp6JS7f14BuwFY8Mwm589M8vMRpXF
1356 sp6JS7f14BuwFY8MwmJTRJ4Fqz1A3
1357 sp6JS7f14BuwFY8MwmRfy8fer4QbL
1358 sp6JS7f14BuwFY8MwmkkFx1HtgWRx
1359 sp6JS7f14BuwFY8MwmwP9JFdKa4PS
1360 sp6JS7f14BuwFY8MwoXWJLB3ciHfo
1361 sp6JS7f14BuwFY8MwoYc1gTtT2mWL
1362 sp6JS7f14BuwFY8MwogXtHH7FNVoo
1363 sp6JS7f14BuwFY8MwoqYoA9P8gf3r
1364 sp6JS7f14BuwFY8MwoujwMJofGnsA
1365
136633 account seeds that produce account IDs with low 32-bits 0xa1dcea4a:
1367 sp6JS7f14BuwFY8Mw5Ccov2N36QTy
1368 sp6JS7f14BuwFY8Mw5CuSemVb5p7w
1369 sp6JS7f14BuwFY8Mw5Ep8wpsTfpSz
1370 sp6JS7f14BuwFY8Mw5WtutJc2H45M
1371 sp6JS7f14BuwFY8Mw6vsDeaSKeUJZ
1372 sp6JS7f14BuwFY8Mw83t5BPWUAzzF
1373 sp6JS7f14BuwFY8Mw8FYGnK35mgkV
1374 sp6JS7f14BuwFY8Mw8huo1x5pfKKJ
1375 sp6JS7f14BuwFY8Mw8mPStxfMDrZa
1376 sp6JS7f14BuwFY8Mw8yC3A7aQJytK
1377 sp6JS7f14BuwFY8MwFCWCDmo9o3t8
1378 sp6JS7f14BuwFY8MwFjapa4gKxPhR
1379 sp6JS7f14BuwFY8Mwj8CWtG29uw71
1380 sp6JS7f14BuwFY8MwjHyU5KpEMLVT
1381 sp6JS7f14BuwFY8MwjMZSN7LZuWD8
1382 sp6JS7f14BuwFY8Mwja2TXJNBhKHU
1383 sp6JS7f14BuwFY8Mwjf3xNTopHKTF
1384 sp6JS7f14BuwFY8Mwjn5RAhedPeuM
1385 sp6JS7f14BuwFY8MwkJdr4d6QoE8K
1386 sp6JS7f14BuwFY8MwkmBryo3SUoLm
1387 sp6JS7f14BuwFY8MwkrPdsc4tR8yw
1388 sp6JS7f14BuwFY8Mwkttjcw2a65Fi
1389 sp6JS7f14BuwFY8Mwm19n3rSaNx5S
1390 sp6JS7f14BuwFY8Mwm3ryr4Xp2aQX
1391 sp6JS7f14BuwFY8MwmBnDmgnJLB6B
1392 sp6JS7f14BuwFY8MwmHgPjzrYjthq
1393 sp6JS7f14BuwFY8MwmeV55DAnWKdd
1394 sp6JS7f14BuwFY8Mwo49hK6BGrauT
1395 sp6JS7f14BuwFY8Mwo56vfKY9aoWu
1396 sp6JS7f14BuwFY8MwoU7tTTXLQTrh
1397 sp6JS7f14BuwFY8MwoXpogSF2KaZB
1398 sp6JS7f14BuwFY8MwoY9JYQAR16pc
1399 sp6JS7f14BuwFY8MwoozLzKNAEXKM
1400
140133 account seeds that produce account IDs with low 32-bits 0xbd2116db:
1402 sp6JS7f14BuwFY8Mw5GrpkmPuA3Bw
1403 sp6JS7f14BuwFY8Mw5r1sLoQJZDc6
1404 sp6JS7f14BuwFY8Mw68zzRmezLdd6
1405 sp6JS7f14BuwFY8Mw6jDSyaiF1mRp
1406 sp6JS7f14BuwFY8Mw813wU9u5D6Uh
1407 sp6JS7f14BuwFY8Mw8BBvpf2JFGoJ
1408 sp6JS7f14BuwFY8Mw8F7zXxAiT263
1409 sp6JS7f14BuwFY8Mw8XG7WuVGHP2N
1410 sp6JS7f14BuwFY8Mw8eyWrcz91cz6
1411 sp6JS7f14BuwFY8Mw8yNVKFVYyk9u
1412 sp6JS7f14BuwFY8MwF2oA6ePqvZWP
1413 sp6JS7f14BuwFY8MwF9VkcSNh3keq
1414 sp6JS7f14BuwFY8MwFYsMWajgEf2j
1415 sp6JS7f14BuwFY8Mwj3Gu43jYoJ4n
1416 sp6JS7f14BuwFY8MwjJ5iRmYDHrW4
1417 sp6JS7f14BuwFY8MwjaUSSga93CiM
1418 sp6JS7f14BuwFY8MwjxgLh2FY4Lvt
1419 sp6JS7f14BuwFY8Mwk9hQdNZUgmTB
1420 sp6JS7f14BuwFY8MwkcMXqtFp1sMx
1421 sp6JS7f14BuwFY8MwkzZCDc56jsUB
1422 sp6JS7f14BuwFY8Mwm5Zz7fP24Qym
1423 sp6JS7f14BuwFY8MwmDWqizXSoJRG
1424 sp6JS7f14BuwFY8MwmKHmkNYdMqqi
1425 sp6JS7f14BuwFY8MwmRfAWHxWpGNK
1426 sp6JS7f14BuwFY8MwmjCdXwyhphZ1
1427 sp6JS7f14BuwFY8MwmmukDAm1w6FL
1428 sp6JS7f14BuwFY8Mwmmz2SzaR9TRH
1429 sp6JS7f14BuwFY8Mwmz2z5mKHXzfn
1430 sp6JS7f14BuwFY8Mwo2xNe5629r5k
1431 sp6JS7f14BuwFY8MwoKy8tZxZrfJw
1432 sp6JS7f14BuwFY8MwoLyQ9aMsq8Dm
1433 sp6JS7f14BuwFY8MwoqqYkewuyZck
1434 sp6JS7f14BuwFY8MwouvvhREVp6Pp
1435
143633 account seeds that produce account IDs with low 32-bits 0xd80df065:
1437 sp6JS7f14BuwFY8Mw5B7ERyhAfgHA
1438 sp6JS7f14BuwFY8Mw5VuW3cF7bm2v
1439 sp6JS7f14BuwFY8Mw5py3t1j7YbFT
1440 sp6JS7f14BuwFY8Mw5qc84SzB6RHr
1441 sp6JS7f14BuwFY8Mw5vGHW1G1hAy8
1442 sp6JS7f14BuwFY8Mw6gVa8TYukws6
1443 sp6JS7f14BuwFY8Mw8K9w1RoUAv1w
1444 sp6JS7f14BuwFY8Mw8KvKtB7787CA
1445 sp6JS7f14BuwFY8Mw8Y7WhRbuFzRq
1446 sp6JS7f14BuwFY8Mw8cipw7inRmMn
1447 sp6JS7f14BuwFY8MwFM5fAUNLNB13
1448 sp6JS7f14BuwFY8MwFSe1zAsht3X3
1449 sp6JS7f14BuwFY8MwFYNdigqQuHZM
1450 sp6JS7f14BuwFY8MwjWkejj7V4V5Q
1451 sp6JS7f14BuwFY8Mwjd2JGpsjvynq
1452 sp6JS7f14BuwFY8Mwjg1xkducn751
1453 sp6JS7f14BuwFY8Mwjsp6LnaJvL1W
1454 sp6JS7f14BuwFY8MwjvSbLc9593yH
1455 sp6JS7f14BuwFY8Mwjw2h5wx7U6vZ
1456 sp6JS7f14BuwFY8MwjxKUjtRsmPLH
1457 sp6JS7f14BuwFY8Mwk1Yy8ginDfqv
1458 sp6JS7f14BuwFY8Mwk2HrWhWwZP12
1459 sp6JS7f14BuwFY8Mwk4SsqiexvpWs
1460 sp6JS7f14BuwFY8Mwk66zCs5ACpE6
1461 sp6JS7f14BuwFY8MwkCwx6vY97Nwh
1462 sp6JS7f14BuwFY8MwknrbjnhTTWU8
1463 sp6JS7f14BuwFY8MwkokDy2ShRzQx
1464 sp6JS7f14BuwFY8Mwm3BxnRPNxsuu
1465 sp6JS7f14BuwFY8MwmY9EWdQQsFVr
1466 sp6JS7f14BuwFY8MwmYTWjrDhmk8S
1467 sp6JS7f14BuwFY8Mwo9skXt9Y5BVS
1468 sp6JS7f14BuwFY8MwoZYKZybJ1Crp
1469 sp6JS7f14BuwFY8MwoyXqkhySfSmF
1470
147133 account seeds that produce account IDs with low 32-bits 0xe2e44294:
1472 sp6JS7f14BuwFY8Mw53dmvTgNtBwi
1473 sp6JS7f14BuwFY8Mw5Wrxsqn6WrXW
1474 sp6JS7f14BuwFY8Mw5fGDT31RCXgC
1475 sp6JS7f14BuwFY8Mw5nKRkubwrLWM
1476 sp6JS7f14BuwFY8Mw5nXMajwKjriB
1477 sp6JS7f14BuwFY8Mw5xZybggrC9NG
1478 sp6JS7f14BuwFY8Mw5xea8f6dBMV5
1479 sp6JS7f14BuwFY8Mw5zDGofAHy5Lb
1480 sp6JS7f14BuwFY8Mw6eado41rQNVG
1481 sp6JS7f14BuwFY8Mw6yqKXQsQJPuU
1482 sp6JS7f14BuwFY8Mw83MSN4FDzSGH
1483 sp6JS7f14BuwFY8Mw8B3pUbzQqHe2
1484 sp6JS7f14BuwFY8Mw8WwRLnhBRvfk
1485 sp6JS7f14BuwFY8Mw8hDBpKbpJwJX
1486 sp6JS7f14BuwFY8Mw8jggRSZACe7M
1487 sp6JS7f14BuwFY8Mw8mJRpU3qWbwC
1488 sp6JS7f14BuwFY8MwFDnVozykN21u
1489 sp6JS7f14BuwFY8MwFGGRGY9fctgv
1490 sp6JS7f14BuwFY8MwjKznfChH9DQb
1491 sp6JS7f14BuwFY8MwjbC5GvngRCk6
1492 sp6JS7f14BuwFY8Mwk3Lb7FPe1629
1493 sp6JS7f14BuwFY8MwkCeS41BwVrBD
1494 sp6JS7f14BuwFY8MwkDnnvRyuWJ7d
1495 sp6JS7f14BuwFY8MwkbkRNnzDEFpf
1496 sp6JS7f14BuwFY8MwkiNhaVhGNk6v
1497 sp6JS7f14BuwFY8Mwm1X4UJXRZx3p
1498 sp6JS7f14BuwFY8Mwm7da9q5vfq7J
1499 sp6JS7f14BuwFY8MwmPLqfBPrHw5H
1500 sp6JS7f14BuwFY8MwmbJpxvVjEwm2
1501 sp6JS7f14BuwFY8MwoAVeA7ka37cD
1502 sp6JS7f14BuwFY8MwoTFFTAwFKmVM
1503 sp6JS7f14BuwFY8MwoYsne51VpDE3
1504 sp6JS7f14BuwFY8MwohLVnU1VTk5h
1505
1506#endif // 0
T begin(T... args)
Represents a JSON value.
Definition json_value.h:130
bool isArray() 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
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.
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:147
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:221
void testLopsidedSplits(FeatureBitset features)
void run() override
Runs the suite.
void printNFTPages(test::jtx::Env &env, Volume vol)
void testWithFeats(FeatureBitset features)
void testNFTokenDir(FeatureBitset features)
void testConsecutivePacking(FeatureBitset features)
void testTooManyEquivalent(FeatureBitset features)
void testConsecutiveNFTs(FeatureBitset features)
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:471
A transaction testing environment.
Definition Env.h:119
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:792
T clear(T... args)
T emplace_back(T... args)
T empty(T... args)
T end(T... args)
T endl(T... args)
T erase(T... args)
T find(T... args)
T front(T... args)
T insert(T... args)
@ arrayValue
array value (ordered list)
Definition json_value.h:25
unsigned int UInt
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Definition Indexes.cpp:375
uint256 constexpr pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))
Taxon toTaxon(std::uint32_t i)
Definition nft.h:22
Taxon cipheredTaxon(std::uint32_t tokenSeq, Taxon taxon)
Definition nft.h:64
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr std::uint32_t const tfTransferable
Definition TxFlags.h:122
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:597
@ tecNO_SUITABLE_NFTOKEN_PAGE
Definition TER.h:302
constexpr std::uint32_t const tfSellNFToken
Definition TxFlags.h:210
@ tesSUCCESS
Definition TER.h:225
T pop_back(T... args)
T push_back(T... args)
T reserve(T... args)
T reverse(T... args)
T size(T... args)
uint256 key
Definition Keylet.h:20