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/ledger/ReadView.h>
22#include <xrpld/rpc/Context.h>
23#include <xrpld/rpc/detail/RPCHelpers.h>
24#include <xrpld/rpc/detail/Tuning.h>
25#include <xrpl/protocol/ErrorCodes.h>
26#include <xrpl/protocol/Indexes.h>
27#include <xrpl/protocol/LedgerFormats.h>
28#include <xrpl/protocol/RPCErr.h>
29#include <xrpl/protocol/jss.h>
30#include <xrpl/protocol/nftPageMask.h>
31#include <xrpl/resource/Fees.h>
32
33#include <string>
34
35namespace ripple {
36
50{
51 auto const& params = context.params;
52 if (!params.isMember(jss::account))
53 return RPC::missing_field_error(jss::account);
54
55 if (!params[jss::account].isString())
56 return RPC::invalid_field_error(jss::account);
57
58 auto id = parseBase58<AccountID>(params[jss::account].asString());
59 if (!id)
60 {
62 }
63
65 auto result = RPC::lookupLedger(ledger, context);
66 if (ledger == nullptr)
67 return result;
68 auto const accountID{id.value()};
69
70 if (!ledger->exists(keylet::account(accountID)))
72
73 unsigned int limit;
74 if (auto err = readLimitField(limit, RPC::Tuning::accountNFTokens, context))
75 return *err;
76
77 uint256 marker;
78 bool const markerSet = params.isMember(jss::marker);
79
80 if (markerSet)
81 {
82 auto const& m = params[jss::marker];
83 if (!m.isString())
84 return RPC::expected_field_error(jss::marker, "string");
85
86 if (!marker.parseHex(m.asString()))
87 return RPC::invalid_field_error(jss::marker);
88 }
89
90 auto const first = keylet::nftpage(keylet::nftpage_min(accountID), marker);
91 auto const last = keylet::nftpage_max(accountID);
92
93 auto cp = ledger->read(Keylet(
94 ltNFTOKEN_PAGE,
95 ledger->succ(first.key, last.key.next()).value_or(last.key)));
96
97 std::uint32_t cnt = 0;
98 auto& nfts = (result[jss::account_nfts] = Json::arrayValue);
99
100 // Continue iteration from the current page:
101 bool pastMarker = marker.isZero();
102 bool markerFound = false;
103 uint256 const maskedMarker = marker & nft::pageMask;
104 while (cp)
105 {
106 auto arr = cp->getFieldArray(sfNFTokens);
107
108 for (auto const& o : arr)
109 {
110 // Scrolling past the marker gets weird. We need to look at
111 // a couple of conditions.
112 //
113 // 1. If the low 96-bits don't match, then we compare only
114 // against the low 96-bits, since that's what determines
115 // the sort order of the pages.
116 //
117 // 2. However, within one page there can be a number of
118 // NFTokenIDs that all have the same low 96 bits. If we're
119 // in that case then we need to compare against the full
120 // 256 bits.
121 uint256 const nftokenID = o[sfNFTokenID];
122 uint256 const maskedNftokenID = nftokenID & nft::pageMask;
123
124 if (!pastMarker)
125 {
126 if (maskedNftokenID < maskedMarker)
127 continue;
128
129 if (maskedNftokenID == maskedMarker && nftokenID < marker)
130 continue;
131
132 if (nftokenID == marker)
133 {
134 markerFound = true;
135 continue;
136 }
137 }
138
139 if (markerSet && !markerFound)
140 return RPC::invalid_field_error(jss::marker);
141
142 pastMarker = true;
143
144 {
145 Json::Value& obj = nfts.append(o.getJson(JsonOptions::none));
146
147 // Pull out the components of the nft ID.
148 obj[sfFlags.jsonName] = nft::getFlags(nftokenID);
149 obj[sfIssuer.jsonName] = to_string(nft::getIssuer(nftokenID));
150 obj[sfNFTokenTaxon.jsonName] =
151 nft::toUInt32(nft::getTaxon(nftokenID));
152 obj[jss::nft_serial] = nft::getSerial(nftokenID);
153 if (std::uint16_t xferFee = {nft::getTransferFee(nftokenID)})
154 obj[sfTransferFee.jsonName] = xferFee;
155 }
156
157 if (++cnt == limit)
158 {
159 result[jss::limit] = limit;
160 result[jss::marker] = to_string(o.getFieldH256(sfNFTokenID));
161 return result;
162 }
163 }
164
165 if (auto npm = (*cp)[~sfNextPageMin])
166 cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm));
167 else
168 cp = nullptr;
169 }
170
171 if (markerSet && !markerFound)
172 return RPC::invalid_field_error(jss::marker);
173
174 result[jss::account] = toBase58(accountID);
176 return result;
177}
178
181{
182 auto const& params = context.params;
183 if (!params.isMember(jss::account))
184 return RPC::missing_field_error(jss::account);
185
186 if (!params[jss::account].isString())
187 return RPC::invalid_field_error(jss::account);
188
190 auto result = RPC::lookupLedger(ledger, context);
191 if (ledger == nullptr)
192 return result;
193
194 auto const id = parseBase58<AccountID>(params[jss::account].asString());
195 if (!id)
196 {
198 return result;
199 }
200 auto const accountID{id.value()};
201
202 if (!ledger->exists(keylet::account(accountID)))
204
206
207 if (params.isMember(jss::deletion_blockers_only) &&
208 params[jss::deletion_blockers_only].asBool())
209 {
210 struct
211 {
213 LedgerEntryType type;
214 } static constexpr deletionBlockers[] = {
215 {jss::check, ltCHECK},
216 {jss::escrow, ltESCROW},
217 {jss::nft_page, ltNFTOKEN_PAGE},
218 {jss::payment_channel, ltPAYCHAN},
219 {jss::state, ltRIPPLE_STATE},
220 {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID},
221 {jss::xchain_owned_create_account_claim_id,
222 ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
223 {jss::bridge, ltBRIDGE},
224 {jss::mpt_issuance, ltMPTOKEN_ISSUANCE},
225 {jss::mptoken, ltMPTOKEN},
226 {jss::permissioned_domain, ltPERMISSIONED_DOMAIN}};
227
228 typeFilter.emplace();
229 typeFilter->reserve(std::size(deletionBlockers));
230
231 for (auto [name, type] : deletionBlockers)
232 {
233 if (params.isMember(jss::type) && name != params[jss::type])
234 {
235 continue;
236 }
237
238 typeFilter->push_back(type);
239 }
240 }
241 else
242 {
243 auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params);
244
246 return RPC::invalid_field_error(jss::type);
247
248 if (rpcStatus)
249 {
250 result.clear();
251 rpcStatus.inject(result);
252 return result;
253 }
254 else if (type != ltANY)
255 {
256 typeFilter = std::vector<LedgerEntryType>({type});
257 }
258 }
259
260 unsigned int limit;
261 if (auto err = readLimitField(limit, RPC::Tuning::accountObjects, context))
262 return *err;
263
264 uint256 dirIndex;
265 uint256 entryIndex;
266 if (params.isMember(jss::marker))
267 {
268 auto const& marker = params[jss::marker];
269 if (!marker.isString())
270 return RPC::expected_field_error(jss::marker, "string");
271
272 auto const& markerStr = marker.asString();
273 auto const& idx = markerStr.find(',');
274 if (idx == std::string::npos)
275 return RPC::invalid_field_error(jss::marker);
276
277 if (!dirIndex.parseHex(markerStr.substr(0, idx)))
278 return RPC::invalid_field_error(jss::marker);
279
280 if (!entryIndex.parseHex(markerStr.substr(idx + 1)))
281 return RPC::invalid_field_error(jss::marker);
282 }
283
285 *ledger,
286 accountID,
287 typeFilter,
288 dirIndex,
289 entryIndex,
290 limit,
291 result))
292 return RPC::invalid_field_error(jss::marker);
293
294 result[jss::account] = toBase58(accountID);
296 return result;
297}
298
299} // namespace ripple
Lightweight wrapper to tag static string.
Definition: json_value.h:62
Represents a JSON value.
Definition: json_value.h:148
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:897
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)
@ arrayValue
array value (ordered list)
Definition: json_value.h:43
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:315
bool isAccountObjectsValidType(LedgerEntryType const &type)
Check if the type is a valid filtering type for account_objects method.
Definition: RPCHelpers.cpp:985
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition: ErrorCodes.h:223
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:930
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.
Definition: RPCHelpers.cpp:152
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:339
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.
Definition: RPCHelpers.cpp:621
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:273
Charge const feeMediumBurdenRPC
Keylet nftpage(Keylet const &k, uint256 const &token)
Definition: Indexes.cpp:410
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:175
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Definition: Indexes.cpp:394
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Definition: Indexes.cpp:402
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:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
@ 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.
Definition: LedgerFormats.h:54
@ ltANY
A special type, matching any ledger entry type.
Definition: LedgerFormats.h:78
T size(T... args)
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:39
Resource::Charge & loadType
Definition: Context.h:41
Json::Value params
Definition: Context.h:62