rippled
Loading...
Searching...
No Matches
AccountNFTs.cpp
1#include <xrpld/rpc/Context.h>
2#include <xrpld/rpc/detail/RPCHelpers.h>
3#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
4#include <xrpld/rpc/detail/Tuning.h>
5
6#include <xrpl/ledger/ReadView.h>
7#include <xrpl/protocol/ErrorCodes.h>
8#include <xrpl/protocol/Indexes.h>
9#include <xrpl/protocol/RPCErr.h>
10#include <xrpl/protocol/jss.h>
11#include <xrpl/protocol/nftPageMask.h>
12#include <xrpl/resource/Fees.h>
13#include <xrpl/tx/transactors/nft/NFTokenUtils.h>
14
15namespace xrpl {
16
29{
30 auto const& params = context.params;
31 if (!params.isMember(jss::account))
32 return RPC::missing_field_error(jss::account);
33
34 if (!params[jss::account].isString())
35 return RPC::invalid_field_error(jss::account);
36
37 auto id = parseBase58<AccountID>(params[jss::account].asString());
38 if (!id)
39 {
41 }
42
44 auto result = RPC::lookupLedger(ledger, context);
45 if (ledger == nullptr)
46 return result;
47 auto const accountID{id.value()};
48
49 if (!ledger->exists(keylet::account(accountID)))
51
52 unsigned int limit = 0;
53 if (auto err = readLimitField(limit, RPC::Tuning::accountNFTokens, context))
54 return *err;
55
56 uint256 marker;
57 bool const markerSet = params.isMember(jss::marker);
58
59 if (markerSet)
60 {
61 auto const& m = params[jss::marker];
62 if (!m.isString())
63 return RPC::expected_field_error(jss::marker, "string");
64
65 if (!marker.parseHex(m.asString()))
66 return RPC::invalid_field_error(jss::marker);
67 }
68
69 auto const first = keylet::nftpage(keylet::nftpage_min(accountID), marker);
70 auto const last = keylet::nftpage_max(accountID);
71
72 auto cp = ledger->read(
73 Keylet(ltNFTOKEN_PAGE, ledger->succ(first.key, last.key.next()).value_or(last.key)));
74
75 std::uint32_t cnt = 0;
76 auto& nfts = (result[jss::account_nfts] = Json::arrayValue);
77
78 // Continue iteration from the current page:
79 bool pastMarker = marker.isZero();
80 bool markerFound = false;
81 uint256 const maskedMarker = marker & nft::pageMask;
82 while (cp)
83 {
84 auto arr = cp->getFieldArray(sfNFTokens);
85
86 for (auto const& o : arr)
87 {
88 // Scrolling past the marker gets weird. We need to look at
89 // a couple of conditions.
90 //
91 // 1. If the low 96-bits don't match, then we compare only
92 // against the low 96-bits, since that's what determines
93 // the sort order of the pages.
94 //
95 // 2. However, within one page there can be a number of
96 // NFTokenIDs that all have the same low 96 bits. If we're
97 // in that case then we need to compare against the full
98 // 256 bits.
99 uint256 const nftokenID = o[sfNFTokenID];
100 uint256 const maskedNftokenID = nftokenID & nft::pageMask;
101
102 if (!pastMarker)
103 {
104 if (maskedNftokenID < maskedMarker)
105 continue;
106
107 if (maskedNftokenID == maskedMarker && nftokenID < marker)
108 continue;
109
110 if (nftokenID == marker)
111 {
112 markerFound = true;
113 continue;
114 }
115 }
116
117 if (markerSet && !markerFound)
118 return RPC::invalid_field_error(jss::marker);
119
120 pastMarker = true;
121
122 {
123 Json::Value& obj = nfts.append(o.getJson(JsonOptions::none));
124
125 // Pull out the components of the nft ID.
126 obj[sfFlags.jsonName] = nft::getFlags(nftokenID);
127 obj[sfIssuer.jsonName] = to_string(nft::getIssuer(nftokenID));
128 obj[sfNFTokenTaxon.jsonName] = nft::toUInt32(nft::getTaxon(nftokenID));
129 obj[jss::nft_serial] = nft::getSerial(nftokenID);
130 if (std::uint16_t const xferFee = {nft::getTransferFee(nftokenID)})
131 obj[sfTransferFee.jsonName] = xferFee;
132 }
133
134 if (++cnt == limit)
135 {
136 result[jss::limit] = limit;
137 result[jss::marker] = to_string(o.getFieldH256(sfNFTokenID));
138 return result;
139 }
140 }
141
142 if (auto npm = (*cp)[~sfNextPageMin])
143 {
144 cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm));
145 }
146 else
147 {
148 cp = nullptr;
149 }
150 }
151
152 if (markerSet && !markerFound)
153 return RPC::invalid_field_error(jss::marker);
154
155 result[jss::account] = toBase58(accountID);
157 return result;
158}
159
160} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
Value & append(Value const &value)
Append value to array at the end.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:476
bool isZero() const
Definition base_uint.h:513
@ arrayValue
array value (ordered list)
Definition json_value.h:25
static LimitRange constexpr accountNFTokens
Limits for the account_nftokens command, in pages.
Json::Value invalid_field_error(std::string const &name)
Definition ErrorCodes.h:273
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition ErrorCodes.h:297
Json::Value missing_field_error(std::string const &name)
Definition ErrorCodes.h:231
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext const &context, Json::Value &result)
Looks up a ledger from a request and fills a Json::Value with ledger data.
Charge const feeMediumBurdenRPC
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Definition Indexes.cpp:371
Keylet nftpage(Keylet const &k, uint256 const &token)
Definition Indexes.cpp:379
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Definition Indexes.cpp:363
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
std::uint32_t toUInt32(Taxon t)
Definition nft.h:28
Taxon getTaxon(uint256 const &id)
Definition nft.h:88
uint256 constexpr pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))
AccountID getIssuer(uint256 const &id)
Definition nft.h:100
std::uint16_t getTransferFee(uint256 const &id)
Definition nft.h:48
std::uint32_t getSerial(uint256 const &id)
Definition nft.h:56
std::uint16_t getFlags(uint256 const &id)
Definition nft.h:40
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
Json::Value doAccountNFTs(RPC::JsonContext &context)
General RPC command that can retrieve objects in the account root.
Json::Value rpcError(error_code_i iError)
Definition RPCErr.cpp:12
@ rpcACT_NOT_FOUND
Definition ErrorCodes.h:50
@ rpcACT_MALFORMED
Definition ErrorCodes.h:70
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:19
Resource::Charge & loadType
Definition Context.h:22
Json::Value params
Definition Context.h:43