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
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
229 typeFilter.emplace();
230 typeFilter->reserve(std::size(deletionBlockers));
231
232 for (auto [name, type] : deletionBlockers)
233 {
234 if (params.isMember(jss::type) && name != params[jss::type])
235 {
236 continue;
237 }
238
239 typeFilter->push_back(type);
240 }
241 }
242 else
243 {
244 auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params);
245
247 return RPC::invalid_field_error(jss::type);
248
249 if (rpcStatus)
250 {
251 result.clear();
252 rpcStatus.inject(result);
253 return result;
254 }
255 else if (type != ltANY)
256 {
257 typeFilter = std::vector<LedgerEntryType>({type});
258 }
259 }
260
261 unsigned int limit;
262 if (auto err = readLimitField(limit, RPC::Tuning::accountObjects, context))
263 return *err;
264
265 uint256 dirIndex;
266 uint256 entryIndex;
267 if (params.isMember(jss::marker))
268 {
269 auto const& marker = params[jss::marker];
270 if (!marker.isString())
271 return RPC::expected_field_error(jss::marker, "string");
272
273 auto const& markerStr = marker.asString();
274 auto const& idx = markerStr.find(',');
275 if (idx == std::string::npos)
276 return RPC::invalid_field_error(jss::marker);
277
278 if (!dirIndex.parseHex(markerStr.substr(0, idx)))
279 return RPC::invalid_field_error(jss::marker);
280
281 if (!entryIndex.parseHex(markerStr.substr(idx + 1)))
282 return RPC::invalid_field_error(jss::marker);
283 }
284
286 *ledger,
287 accountID,
288 typeFilter,
289 dirIndex,
290 entryIndex,
291 limit,
292 result))
293 return RPC::invalid_field_error(jss::marker);
294
295 result[jss::account] = toBase58(accountID);
297 return result;
298}
299
300} // 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:986
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:931
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:153
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:622
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:42
Json::Value params
Definition: Context.h:63