rippled
Loading...
Searching...
No Matches
AccountObjects.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2014 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/tx/detail/NFTokenUtils.h>
21#include <xrpld/rpc/Context.h>
22#include <xrpld/rpc/detail/RPCHelpers.h>
23#include <xrpld/rpc/detail/Tuning.h>
24
25#include <xrpl/ledger/ReadView.h>
26#include <xrpl/protocol/ErrorCodes.h>
27#include <xrpl/protocol/Indexes.h>
28#include <xrpl/protocol/LedgerFormats.h>
29#include <xrpl/protocol/RPCErr.h>
30#include <xrpl/protocol/jss.h>
31#include <xrpl/protocol/nftPageMask.h>
32#include <xrpl/resource/Fees.h>
33
34#include <string>
35
36namespace ripple {
37
51{
52 auto const& params = context.params;
53 if (!params.isMember(jss::account))
54 return RPC::missing_field_error(jss::account);
55
56 if (!params[jss::account].isString())
57 return RPC::invalid_field_error(jss::account);
58
59 auto id = parseBase58<AccountID>(params[jss::account].asString());
60 if (!id)
61 {
63 }
64
66 auto result = RPC::lookupLedger(ledger, context);
67 if (ledger == nullptr)
68 return result;
69 auto const accountID{id.value()};
70
71 if (!ledger->exists(keylet::account(accountID)))
73
74 unsigned int limit;
75 if (auto err = readLimitField(limit, RPC::Tuning::accountNFTokens, context))
76 return *err;
77
78 uint256 marker;
79 bool const markerSet = params.isMember(jss::marker);
80
81 if (markerSet)
82 {
83 auto const& m = params[jss::marker];
84 if (!m.isString())
85 return RPC::expected_field_error(jss::marker, "string");
86
87 if (!marker.parseHex(m.asString()))
88 return RPC::invalid_field_error(jss::marker);
89 }
90
91 auto const first = keylet::nftpage(keylet::nftpage_min(accountID), marker);
92 auto const last = keylet::nftpage_max(accountID);
93
94 auto cp = ledger->read(Keylet(
95 ltNFTOKEN_PAGE,
96 ledger->succ(first.key, last.key.next()).value_or(last.key)));
97
98 std::uint32_t cnt = 0;
99 auto& nfts = (result[jss::account_nfts] = Json::arrayValue);
100
101 // Continue iteration from the current page:
102 bool pastMarker = marker.isZero();
103 bool markerFound = false;
104 uint256 const maskedMarker = marker & nft::pageMask;
105 while (cp)
106 {
107 auto arr = cp->getFieldArray(sfNFTokens);
108
109 for (auto const& o : arr)
110 {
111 // Scrolling past the marker gets weird. We need to look at
112 // a couple of conditions.
113 //
114 // 1. If the low 96-bits don't match, then we compare only
115 // against the low 96-bits, since that's what determines
116 // the sort order of the pages.
117 //
118 // 2. However, within one page there can be a number of
119 // NFTokenIDs that all have the same low 96 bits. If we're
120 // in that case then we need to compare against the full
121 // 256 bits.
122 uint256 const nftokenID = o[sfNFTokenID];
123 uint256 const maskedNftokenID = nftokenID & nft::pageMask;
124
125 if (!pastMarker)
126 {
127 if (maskedNftokenID < maskedMarker)
128 continue;
129
130 if (maskedNftokenID == maskedMarker && nftokenID < marker)
131 continue;
132
133 if (nftokenID == marker)
134 {
135 markerFound = true;
136 continue;
137 }
138 }
139
140 if (markerSet && !markerFound)
141 return RPC::invalid_field_error(jss::marker);
142
143 pastMarker = true;
144
145 {
146 Json::Value& obj = nfts.append(o.getJson(JsonOptions::none));
147
148 // Pull out the components of the nft ID.
149 obj[sfFlags.jsonName] = nft::getFlags(nftokenID);
150 obj[sfIssuer.jsonName] = to_string(nft::getIssuer(nftokenID));
151 obj[sfNFTokenTaxon.jsonName] =
152 nft::toUInt32(nft::getTaxon(nftokenID));
153 obj[jss::nft_serial] = nft::getSerial(nftokenID);
154 if (std::uint16_t xferFee = {nft::getTransferFee(nftokenID)})
155 obj[sfTransferFee.jsonName] = xferFee;
156 }
157
158 if (++cnt == limit)
159 {
160 result[jss::limit] = limit;
161 result[jss::marker] = to_string(o.getFieldH256(sfNFTokenID));
162 return result;
163 }
164 }
165
166 if (auto npm = (*cp)[~sfNextPageMin])
167 cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm));
168 else
169 cp = nullptr;
170 }
171
172 if (markerSet && !markerFound)
173 return RPC::invalid_field_error(jss::marker);
174
175 result[jss::account] = toBase58(accountID);
177 return result;
178}
179
182{
183 auto const& params = context.params;
184 if (!params.isMember(jss::account))
185 return RPC::missing_field_error(jss::account);
186
187 if (!params[jss::account].isString())
188 return RPC::invalid_field_error(jss::account);
189
191 auto result = RPC::lookupLedger(ledger, context);
192 if (ledger == nullptr)
193 return result;
194
195 auto const id = parseBase58<AccountID>(params[jss::account].asString());
196 if (!id)
197 {
199 return result;
200 }
201 auto const accountID{id.value()};
202
203 if (!ledger->exists(keylet::account(accountID)))
205
207
208 if (params.isMember(jss::deletion_blockers_only) &&
209 params[jss::deletion_blockers_only].asBool())
210 {
211 struct
212 {
214 LedgerEntryType type;
215 } static constexpr deletionBlockers[] = {
216 {jss::check, ltCHECK},
217 {jss::escrow, ltESCROW},
218 {jss::nft_page, ltNFTOKEN_PAGE},
219 {jss::payment_channel, ltPAYCHAN},
220 {jss::state, ltRIPPLE_STATE},
221 {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID},
222 {jss::xchain_owned_create_account_claim_id,
223 ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
224 {jss::bridge, ltBRIDGE},
225 {jss::mpt_issuance, ltMPTOKEN_ISSUANCE},
226 {jss::mptoken, ltMPTOKEN},
227 {jss::permissioned_domain, ltPERMISSIONED_DOMAIN},
228 {jss::vault, ltVAULT},
229 };
230
231 typeFilter.emplace();
232 typeFilter->reserve(std::size(deletionBlockers));
233
234 for (auto [name, type] : deletionBlockers)
235 {
236 if (params.isMember(jss::type) && name != params[jss::type])
237 {
238 continue;
239 }
240
241 typeFilter->push_back(type);
242 }
243 }
244 else
245 {
246 auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params);
247
249 return RPC::invalid_field_error(jss::type);
250
251 if (rpcStatus)
252 {
253 result.clear();
254 rpcStatus.inject(result);
255 return result;
256 }
257 else if (type != ltANY)
258 {
259 typeFilter = std::vector<LedgerEntryType>({type});
260 }
261 }
262
263 unsigned int limit;
264 if (auto err = readLimitField(limit, RPC::Tuning::accountObjects, context))
265 return *err;
266
267 uint256 dirIndex;
268 uint256 entryIndex;
269 if (params.isMember(jss::marker))
270 {
271 auto const& marker = params[jss::marker];
272 if (!marker.isString())
273 return RPC::expected_field_error(jss::marker, "string");
274
275 auto const& markerStr = marker.asString();
276 auto const& idx = markerStr.find(',');
277 if (idx == std::string::npos)
278 return RPC::invalid_field_error(jss::marker);
279
280 if (!dirIndex.parseHex(markerStr.substr(0, idx)))
281 return RPC::invalid_field_error(jss::marker);
282
283 if (!entryIndex.parseHex(markerStr.substr(idx + 1)))
284 return RPC::invalid_field_error(jss::marker);
285 }
286
288 *ledger,
289 accountID,
290 typeFilter,
291 dirIndex,
292 entryIndex,
293 limit,
294 result))
295 return RPC::invalid_field_error(jss::marker);
296
297 result[jss::account] = toBase58(accountID);
299 return result;
300}
301
302} // namespace ripple
Lightweight wrapper to tag static string.
Definition json_value.h:63
Represents a JSON value.
Definition json_value.h:149
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:503
bool isZero() const
Definition base_uint.h:540
T emplace(T... args)
T is_same_v
@ arrayValue
array value (ordered list)
Definition json_value.h:44
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:325
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:233
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:349
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:283
Charge const feeMediumBurdenRPC
Keylet nftpage(Keylet const &k, uint256 const &token)
Definition Indexes.cpp:419
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:184
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Definition Indexes.cpp:403
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Definition Indexes.cpp:411
std::uint16_t getTransferFee(uint256 const &id)
Definition nft.h:68
std::uint16_t getFlags(uint256 const &id)
Definition nft.h:60
std::uint32_t toUInt32(Taxon t)
Definition nft.h:48
Taxon getTaxon(uint256 const &id)
Definition nft.h:108
AccountID getIssuer(uint256 const &id)
Definition nft.h:120
std::uint32_t getSerial(uint256 const &id)
Definition nft.h:76
uint256 constexpr pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
@ rpcACT_NOT_FOUND
Definition ErrorCodes.h:70
@ rpcACT_MALFORMED
Definition ErrorCodes.h:90
Json::Value rpcError(int iError)
Definition RPCErr.cpp:31
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:630
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:39
Resource::Charge & loadType
Definition Context.h:42