rippled
Loading...
Searching...
No Matches
AccountObjects.cpp
1#include <xrpld/app/tx/detail/NFTokenUtils.h>
2#include <xrpld/rpc/Context.h>
3#include <xrpld/rpc/detail/RPCHelpers.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/LedgerFormats.h>
10#include <xrpl/protocol/RPCErr.h>
11#include <xrpl/protocol/jss.h>
12#include <xrpl/protocol/nftPageMask.h>
13#include <xrpl/resource/Fees.h>
14
15#include <string>
16
17namespace ripple {
18
32{
33 auto const& params = context.params;
34 if (!params.isMember(jss::account))
35 return RPC::missing_field_error(jss::account);
36
37 if (!params[jss::account].isString())
38 return RPC::invalid_field_error(jss::account);
39
40 auto id = parseBase58<AccountID>(params[jss::account].asString());
41 if (!id)
42 {
44 }
45
47 auto result = RPC::lookupLedger(ledger, context);
48 if (ledger == nullptr)
49 return result;
50 auto const accountID{id.value()};
51
52 if (!ledger->exists(keylet::account(accountID)))
54
55 unsigned int limit;
56 if (auto err = readLimitField(limit, RPC::Tuning::accountNFTokens, context))
57 return *err;
58
59 uint256 marker;
60 bool const markerSet = params.isMember(jss::marker);
61
62 if (markerSet)
63 {
64 auto const& m = params[jss::marker];
65 if (!m.isString())
66 return RPC::expected_field_error(jss::marker, "string");
67
68 if (!marker.parseHex(m.asString()))
69 return RPC::invalid_field_error(jss::marker);
70 }
71
72 auto const first = keylet::nftpage(keylet::nftpage_min(accountID), marker);
73 auto const last = keylet::nftpage_max(accountID);
74
75 auto cp = ledger->read(Keylet(
76 ltNFTOKEN_PAGE,
77 ledger->succ(first.key, last.key.next()).value_or(last.key)));
78
79 std::uint32_t cnt = 0;
80 auto& nfts = (result[jss::account_nfts] = Json::arrayValue);
81
82 // Continue iteration from the current page:
83 bool pastMarker = marker.isZero();
84 bool markerFound = false;
85 uint256 const maskedMarker = marker & nft::pageMask;
86 while (cp)
87 {
88 auto arr = cp->getFieldArray(sfNFTokens);
89
90 for (auto const& o : arr)
91 {
92 // Scrolling past the marker gets weird. We need to look at
93 // a couple of conditions.
94 //
95 // 1. If the low 96-bits don't match, then we compare only
96 // against the low 96-bits, since that's what determines
97 // the sort order of the pages.
98 //
99 // 2. However, within one page there can be a number of
100 // NFTokenIDs that all have the same low 96 bits. If we're
101 // in that case then we need to compare against the full
102 // 256 bits.
103 uint256 const nftokenID = o[sfNFTokenID];
104 uint256 const maskedNftokenID = nftokenID & nft::pageMask;
105
106 if (!pastMarker)
107 {
108 if (maskedNftokenID < maskedMarker)
109 continue;
110
111 if (maskedNftokenID == maskedMarker && nftokenID < marker)
112 continue;
113
114 if (nftokenID == marker)
115 {
116 markerFound = true;
117 continue;
118 }
119 }
120
121 if (markerSet && !markerFound)
122 return RPC::invalid_field_error(jss::marker);
123
124 pastMarker = true;
125
126 {
127 Json::Value& obj = nfts.append(o.getJson(JsonOptions::none));
128
129 // Pull out the components of the nft ID.
130 obj[sfFlags.jsonName] = nft::getFlags(nftokenID);
131 obj[sfIssuer.jsonName] = to_string(nft::getIssuer(nftokenID));
132 obj[sfNFTokenTaxon.jsonName] =
133 nft::toUInt32(nft::getTaxon(nftokenID));
134 obj[jss::nft_serial] = nft::getSerial(nftokenID);
135 if (std::uint16_t xferFee = {nft::getTransferFee(nftokenID)})
136 obj[sfTransferFee.jsonName] = xferFee;
137 }
138
139 if (++cnt == limit)
140 {
141 result[jss::limit] = limit;
142 result[jss::marker] = to_string(o.getFieldH256(sfNFTokenID));
143 return result;
144 }
145 }
146
147 if (auto npm = (*cp)[~sfNextPageMin])
148 cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm));
149 else
150 cp = nullptr;
151 }
152
153 if (markerSet && !markerFound)
154 return RPC::invalid_field_error(jss::marker);
155
156 result[jss::account] = toBase58(accountID);
158 return result;
159}
160
163{
164 auto const& params = context.params;
165 if (!params.isMember(jss::account))
166 return RPC::missing_field_error(jss::account);
167
168 if (!params[jss::account].isString())
169 return RPC::invalid_field_error(jss::account);
170
172 auto result = RPC::lookupLedger(ledger, context);
173 if (ledger == nullptr)
174 return result;
175
176 auto const id = parseBase58<AccountID>(params[jss::account].asString());
177 if (!id)
178 {
180 return result;
181 }
182 auto const accountID{id.value()};
183
184 if (!ledger->exists(keylet::account(accountID)))
186
188
189 if (params.isMember(jss::deletion_blockers_only) &&
190 params[jss::deletion_blockers_only].asBool())
191 {
192 struct
193 {
195 LedgerEntryType type;
196 } static constexpr deletionBlockers[] = {
197 {jss::check, ltCHECK},
198 {jss::escrow, ltESCROW},
199 {jss::nft_page, ltNFTOKEN_PAGE},
200 {jss::payment_channel, ltPAYCHAN},
201 {jss::state, ltRIPPLE_STATE},
202 {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID},
203 {jss::xchain_owned_create_account_claim_id,
204 ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
205 {jss::bridge, ltBRIDGE},
206 {jss::mpt_issuance, ltMPTOKEN_ISSUANCE},
207 {jss::mptoken, ltMPTOKEN},
208 {jss::permissioned_domain, ltPERMISSIONED_DOMAIN},
209 {jss::vault, ltVAULT},
210 };
211
212 typeFilter.emplace();
213 typeFilter->reserve(std::size(deletionBlockers));
214
215 for (auto [name, type] : deletionBlockers)
216 {
217 if (params.isMember(jss::type) && name != params[jss::type])
218 {
219 continue;
220 }
221
222 typeFilter->push_back(type);
223 }
224 }
225 else
226 {
227 auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params);
228
230 return RPC::invalid_field_error(jss::type);
231
232 if (rpcStatus)
233 {
234 result.clear();
235 rpcStatus.inject(result);
236 return result;
237 }
238 else if (type != ltANY)
239 {
240 typeFilter = std::vector<LedgerEntryType>({type});
241 }
242 }
243
244 unsigned int limit;
245 if (auto err = readLimitField(limit, RPC::Tuning::accountObjects, context))
246 return *err;
247
248 uint256 dirIndex;
249 uint256 entryIndex;
250 if (params.isMember(jss::marker))
251 {
252 auto const& marker = params[jss::marker];
253 if (!marker.isString())
254 return RPC::expected_field_error(jss::marker, "string");
255
256 auto const& markerStr = marker.asString();
257 auto const& idx = markerStr.find(',');
258 if (idx == std::string::npos)
259 return RPC::invalid_field_error(jss::marker);
260
261 if (!dirIndex.parseHex(markerStr.substr(0, idx)))
262 return RPC::invalid_field_error(jss::marker);
263
264 if (!entryIndex.parseHex(markerStr.substr(idx + 1)))
265 return RPC::invalid_field_error(jss::marker);
266 }
267
269 *ledger,
270 accountID,
271 typeFilter,
272 dirIndex,
273 entryIndex,
274 limit,
275 result))
276 return RPC::invalid_field_error(jss::marker);
277
278 result[jss::account] = toBase58(accountID);
280 return result;
281}
282
283} // namespace ripple
Lightweight wrapper to tag static string.
Definition json_value.h:45
Represents a JSON value.
Definition json_value.h:131
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:484
bool isZero() const
Definition base_uint.h:521
T emplace(T... args)
T is_same_v
@ arrayValue
array value (ordered list)
Definition json_value.h:26
static LimitRange constexpr accountNFTokens
Limits for the account_nftokens command, in pages.
static LimitRange constexpr accountObjects
Limits for the account_objects command.
Json::Value invalid_field_error(std::string const &name)
Definition ErrorCodes.h:306
bool isAccountObjectsValidType(LedgerEntryType const &type)
Check if the type is a valid filtering type for account_objects method.
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition ErrorCodes.h:214
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
bool getAccountObjects(ReadView const &ledger, AccountID const &account, std::optional< std::vector< LedgerEntryType > > const &typeFilter, uint256 dirIndex, uint256 entryIndex, std::uint32_t const limit, Json::Value &jvResult)
Gathers all objects for an account in a ledger.
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition ErrorCodes.h:330
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext &context, Json::Value &result)
Look up a ledger from a request and fill a Json::Result with the data representing a ledger.
Json::Value missing_field_error(std::string const &name)
Definition ErrorCodes.h:264
Charge const feeMediumBurdenRPC
Keylet nftpage(Keylet const &k, uint256 const &token)
Definition Indexes.cpp:400
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Definition Indexes.cpp:384
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Definition Indexes.cpp:392
std::uint16_t getTransferFee(uint256 const &id)
Definition nft.h:49
std::uint16_t getFlags(uint256 const &id)
Definition nft.h:41
std::uint32_t toUInt32(Taxon t)
Definition nft.h:29
Taxon getTaxon(uint256 const &id)
Definition nft.h:89
AccountID getIssuer(uint256 const &id)
Definition nft.h:101
std::uint32_t getSerial(uint256 const &id)
Definition nft.h:57
uint256 constexpr pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
@ rpcACT_NOT_FOUND
Definition ErrorCodes.h:51
@ rpcACT_MALFORMED
Definition ErrorCodes.h:71
Json::Value rpcError(int iError)
Definition RPCErr.cpp:12
Json::Value doAccountObjects(RPC::JsonContext &context)
Json::Value doAccountNFTs(RPC::JsonContext &context)
General RPC command that can retrieve objects in the account root.
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
LedgerEntryType
Identifiers for on-ledger objects.
@ ltANY
A special type, matching any ledger entry type.
T size(T... args)
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:20
Resource::Charge & loadType
Definition Context.h:23