rippled
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 <ripple/app/main/Application.h>
21 #include <ripple/app/tx/impl/details/NFTokenUtils.h>
22 #include <ripple/ledger/ReadView.h>
23 #include <ripple/net/RPCErr.h>
24 #include <ripple/protocol/ErrorCodes.h>
25 #include <ripple/protocol/Indexes.h>
26 #include <ripple/protocol/LedgerFormats.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/protocol/nftPageMask.h>
29 #include <ripple/resource/Fees.h>
30 #include <ripple/rpc/Context.h>
31 #include <ripple/rpc/impl/RPCHelpers.h>
32 #include <ripple/rpc/impl/Tuning.h>
33 
34 #include <sstream>
35 #include <string>
36 
37 namespace ripple {
38 
52 {
53  auto const& params = context.params;
54  if (!params.isMember(jss::account))
55  return RPC::missing_field_error(jss::account);
56 
58  auto result = RPC::lookupLedger(ledger, context);
59  if (ledger == nullptr)
60  return result;
61 
62  auto id = parseBase58<AccountID>(params[jss::account].asString());
63  if (!id)
64  {
66  return result;
67  }
68  auto const accountID{id.value()};
69 
70  if (!ledger->exists(keylet::account(accountID)))
71  return rpcError(rpcACT_NOT_FOUND);
72 
73  unsigned int limit;
74  if (auto err = readLimitField(limit, RPC::Tuning::accountNFTokens, context))
75  return *err;
76 
77  uint256 marker;
78 
79  if (params.isMember(jss::marker))
80  {
81  auto const& m = params[jss::marker];
82  if (!m.isString())
83  return RPC::expected_field_error(jss::marker, "string");
84 
85  if (!marker.parseHex(m.asString()))
86  return RPC::invalid_field_error(jss::marker);
87  }
88 
89  auto const first = keylet::nftpage(keylet::nftpage_min(accountID), marker);
90  auto const last = keylet::nftpage_max(accountID);
91 
92  auto cp = ledger->read(Keylet(
94  ledger->succ(first.key, last.key.next()).value_or(last.key)));
95 
96  std::uint32_t cnt = 0;
97  auto& nfts = (result[jss::account_nfts] = Json::arrayValue);
98 
99  // Continue iteration from the current page:
100  bool pastMarker = marker.isZero();
101  uint256 const maskedMarker = marker & nft::pageMask;
102  while (cp)
103  {
104  auto arr = cp->getFieldArray(sfNFTokens);
105 
106  for (auto const& o : arr)
107  {
108  // Scrolling past the marker gets weird. We need to look at
109  // a couple of conditions.
110  //
111  // 1. If the low 96-bits don't match, then we compare only
112  // against the low 96-bits, since that's what determines
113  // the sort order of the pages.
114  //
115  // 2. However, within one page there can be a number of
116  // NFTokenIDs that all have the same low 96 bits. If we're
117  // in that case then we need to compare against the full
118  // 256 bits.
119  uint256 const nftokenID = o[sfNFTokenID];
120  uint256 const maskedNftokenID = nftokenID & nft::pageMask;
121 
122  if (!pastMarker && maskedNftokenID < maskedMarker)
123  continue;
124 
125  if (!pastMarker && maskedNftokenID == maskedMarker &&
126  nftokenID <= marker)
127  continue;
128 
129  pastMarker = true;
130 
131  {
132  Json::Value& obj = nfts.append(o.getJson(JsonOptions::none));
133 
134  // Pull out the components of the nft ID.
135  obj[sfFlags.jsonName] = nft::getFlags(nftokenID);
136  obj[sfIssuer.jsonName] = to_string(nft::getIssuer(nftokenID));
137  obj[sfNFTokenTaxon.jsonName] =
138  nft::toUInt32(nft::getTaxon(nftokenID));
139  obj[jss::nft_serial] = nft::getSerial(nftokenID);
140  if (std::uint16_t xferFee = {nft::getTransferFee(nftokenID)})
141  obj[sfTransferFee.jsonName] = xferFee;
142  }
143 
144  if (++cnt == limit)
145  {
146  result[jss::limit] = limit;
147  result[jss::marker] = to_string(o.getFieldH256(sfNFTokenID));
148  return result;
149  }
150  }
151 
152  if (auto npm = (*cp)[~sfNextPageMin])
153  cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm));
154  else
155  cp = nullptr;
156  }
157 
158  result[jss::account] = toBase58(accountID);
160  return result;
161 }
162 
165 {
166  auto const& params = context.params;
167  if (!params.isMember(jss::account))
168  return RPC::missing_field_error(jss::account);
169 
171  auto result = RPC::lookupLedger(ledger, context);
172  if (ledger == nullptr)
173  return result;
174 
175  auto const id = parseBase58<AccountID>(params[jss::account].asString());
176  if (!id)
177  {
179  return result;
180  }
181  auto const accountID{id.value()};
182 
183  if (!ledger->exists(keylet::account(accountID)))
184  return rpcError(rpcACT_NOT_FOUND);
185 
187 
188  if (params.isMember(jss::deletion_blockers_only) &&
189  params[jss::deletion_blockers_only].asBool())
190  {
191  struct
192  {
193  Json::StaticString name;
194  LedgerEntryType type;
195  } static constexpr deletionBlockers[] = {
196  {jss::check, ltCHECK},
197  {jss::escrow, ltESCROW},
198  {jss::nft_page, ltNFTOKEN_PAGE},
199  {jss::payment_channel, ltPAYCHAN},
200  {jss::state, ltRIPPLE_STATE},
201  {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID},
202  {jss::xchain_owned_create_account_claim_id,
204  {jss::bridge, ltBRIDGE}};
205 
206  typeFilter.emplace();
207  typeFilter->reserve(std::size(deletionBlockers));
208 
209  for (auto [name, type] : deletionBlockers)
210  {
211  if (params.isMember(jss::type) && name != params[jss::type])
212  {
213  continue;
214  }
215 
216  typeFilter->push_back(type);
217  }
218  }
219  else
220  {
221  auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params);
222 
223  if (rpcStatus)
224  {
225  result.clear();
226  rpcStatus.inject(result);
227  return result;
228  }
229  else if (type != ltANY)
230  {
231  typeFilter = std::vector<LedgerEntryType>({type});
232  }
233  }
234 
235  unsigned int limit;
236  if (auto err = readLimitField(limit, RPC::Tuning::accountObjects, context))
237  return *err;
238 
239  uint256 dirIndex;
240  uint256 entryIndex;
241  if (params.isMember(jss::marker))
242  {
243  auto const& marker = params[jss::marker];
244  if (!marker.isString())
245  return RPC::expected_field_error(jss::marker, "string");
246 
247  std::stringstream ss(marker.asString());
248  std::string s;
249  if (!std::getline(ss, s, ','))
250  return RPC::invalid_field_error(jss::marker);
251 
252  if (!dirIndex.parseHex(s))
253  return RPC::invalid_field_error(jss::marker);
254 
255  if (!std::getline(ss, s, ','))
256  return RPC::invalid_field_error(jss::marker);
257 
258  if (!entryIndex.parseHex(s))
259  return RPC::invalid_field_error(jss::marker);
260  }
261 
263  *ledger,
264  accountID,
265  typeFilter,
266  dirIndex,
267  entryIndex,
268  limit,
269  result))
270  {
271  result[jss::account_objects] = Json::arrayValue;
272  }
273 
274  result[jss::account] = toBase58(accountID);
276  return result;
277 }
278 
279 } // namespace ripple
ripple::doAccountNFTs
Json::Value doAccountNFTs(RPC::JsonContext &context)
General RPC command that can retrieve objects in the account root.
Definition: AccountObjects.cpp:51
sstream
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
ripple::nft::getFlags
std::uint16_t getFlags(uint256 const &id)
Definition: nft.h:59
std::string
STL class.
std::shared_ptr
STL class.
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::ltANY
@ ltANY
A special type, matching any ledger entry type.
Definition: LedgerFormats.h:207
ripple::Resource::feeMediumBurdenRPC
const Charge feeMediumBurdenRPC
ripple::sfNFTokenID
const SF_UINT256 sfNFTokenID
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::doAccountObjects
Json::Value doAccountObjects(RPC::JsonContext &context)
Definition: AccountObjects.cpp:164
ripple::RPC::Tuning::accountNFTokens
static constexpr LimitRange accountNFTokens
Limits for the account_nftokens command, in pages.
Definition: rpc/impl/Tuning.h:55
ripple::RPC::getAccountObjects
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
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
std::vector
STL class.
std::size
T size(T... args)
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
std::optional::emplace
T emplace(T... args)
std::stringstream
STL class.
ripple::ltCHECK
@ ltCHECK
A ledger object which describes a check.
Definition: LedgerFormats.h:155
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:163
ripple::RPC::lookupLedger
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:623
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:330
ripple::sfTransferFee
const SF_UINT16 sfTransferFee
ripple::nft::pageMask
constexpr uint256 pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:264
ripple::nft::getIssuer
AccountID getIssuer(uint256 const &id)
Definition: nft.h:119
ripple::base_uint< 256 >
ripple::keylet::nftpage_min
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Definition: Indexes.cpp:341
ripple::keylet::nftpage
Keylet nftpage(Keylet const &k, uint256 const &token)
Definition: Indexes.cpp:357
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:532
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:142
ripple::nft::toUInt32
std::uint32_t toUInt32(Taxon t)
Definition: nft.h:48
ripple::ltESCROW
@ ltESCROW
A ledger object describing a single escrow.
Definition: LedgerFormats.h:143
ripple::rpcACT_NOT_FOUND
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
ripple::keylet::nftpage_max
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Definition: Indexes.cpp:349
ripple::ReadView::exists
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
ripple::nft::getSerial
std::uint32_t getSerial(uint256 const &id)
Definition: nft.h:75
std::uint32_t
ripple::ReadView::succ
virtual std::optional< key_type > succ(key_type const &key, std::optional< key_type > const &last=std::nullopt) const =0
Return the key of the next state item.
ripple::RPC::Tuning::accountObjects
static constexpr LimitRange accountObjects
Limits for the account_objects command.
Definition: rpc/impl/Tuning.h:43
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::sfNFTokens
const SField sfNFTokens
ripple::ltNFTOKEN_PAGE
@ ltNFTOKEN_PAGE
A ledger object which contains a list of NFTs.
Definition: LedgerFormats.h:175
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::JsonOptions::none
@ none
Definition: STBase.h:42
ripple::ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID
@ ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID
A claim id for a cross chain create account transaction.
Definition: LedgerFormats.h:129
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::LedgerEntryType
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:53
ripple::ltBRIDGE
@ ltBRIDGE
The ledger object which lists details about sidechains.
Definition: LedgerFormats.h:99
ripple::sfIssuer
const SF_ACCOUNT sfIssuer
ripple::RPC::chooseLedgerEntryType
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:932
std::getline
T getline(T... args)
Json::StaticString
Lightweight wrapper to tag static string.
Definition: json_value.h:60
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::sfNextPageMin
const SF_UINT256 sfNextPageMin
ripple::ltXCHAIN_OWNED_CLAIM_ID
@ ltXCHAIN_OWNED_CLAIM_ID
A claim id for a cross chain transaction.
Definition: LedgerFormats.h:123
std::optional
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::sfNFTokenTaxon
const SF_UINT32 sfNFTokenTaxon
ripple::ltRIPPLE_STATE
@ ltRIPPLE_STATE
A ledger object which describes a bidirectional trust line.
Definition: LedgerFormats.h:74
ripple::nft::getTransferFee
std::uint16_t getTransferFee(uint256 const &id)
Definition: nft.h:67
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
ripple::nft::getTaxon
Taxon getTaxon(uint256 const &id)
Definition: nft.h:107
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::RPC::inject_error
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition: ErrorCodes.h:214
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:306
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::ltPAYCHAN
@ ltPAYCHAN
A ledger object describing a single unidirectional XRP payment channel.
Definition: LedgerFormats.h:149
string