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/json/json_writer.h>
23 #include <ripple/ledger/ReadView.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 #include <ripple/protocol/Indexes.h>
27 #include <ripple/protocol/LedgerFormats.h>
28 #include <ripple/protocol/jss.h>
29 #include <ripple/protocol/nftPageMask.h>
30 #include <ripple/resource/Fees.h>
31 #include <ripple/rpc/Context.h>
32 #include <ripple/rpc/impl/RPCHelpers.h>
33 #include <ripple/rpc/impl/Tuning.h>
34 
35 #include <sstream>
36 #include <string>
37 
38 namespace ripple {
39 
53 {
54  auto const& params = context.params;
55  if (!params.isMember(jss::account))
56  return RPC::missing_field_error(jss::account);
57 
59  auto result = RPC::lookupLedger(ledger, context);
60  if (ledger == nullptr)
61  return result;
62 
63  AccountID accountID;
64  {
65  auto const strIdent = params[jss::account].asString();
66  if (auto jv = RPC::accountFromString(accountID, strIdent))
67  {
68  for (auto it = jv.begin(); it != jv.end(); ++it)
69  result[it.memberName()] = *it;
70 
71  return result;
72  }
73  }
74 
75  if (!ledger->exists(keylet::account(accountID)))
76  return rpcError(rpcACT_NOT_FOUND);
77 
78  unsigned int limit;
79  if (auto err = readLimitField(limit, RPC::Tuning::accountNFTokens, context))
80  return *err;
81 
82  uint256 marker;
83 
84  if (params.isMember(jss::marker))
85  {
86  auto const& m = params[jss::marker];
87  if (!m.isString())
88  return RPC::expected_field_error(jss::marker, "string");
89 
90  if (!marker.parseHex(m.asString()))
91  return RPC::invalid_field_error(jss::marker);
92  }
93 
94  auto const first = keylet::nftpage(keylet::nftpage_min(accountID), marker);
95  auto const last = keylet::nftpage_max(accountID);
96 
97  auto cp = ledger->read(Keylet(
99  ledger->succ(first.key, last.key.next()).value_or(last.key)));
100 
101  std::uint32_t cnt = 0;
102  auto& nfts = (result[jss::account_nfts] = Json::arrayValue);
103 
104  // Continue iteration from the current page:
105  bool pastMarker = marker.isZero();
106  uint256 const maskedMarker = marker & nft::pageMask;
107  while (cp)
108  {
109  auto arr = cp->getFieldArray(sfNFTokens);
110 
111  for (auto const& o : arr)
112  {
113  // Scrolling past the marker gets weird. We need to look at
114  // a couple of conditions.
115  //
116  // 1. If the low 96-bits don't match, then we compare only
117  // against the low 96-bits, since that's what determines
118  // the sort order of the pages.
119  //
120  // 2. However, within one page there can be a number of
121  // NFTokenIDs that all have the same low 96 bits. If we're
122  // in that case then we need to compare against the full
123  // 256 bits.
124  uint256 const nftokenID = o[sfNFTokenID];
125  uint256 const maskedNftokenID = nftokenID & nft::pageMask;
126 
127  if (!pastMarker && maskedNftokenID < maskedMarker)
128  continue;
129 
130  if (!pastMarker && maskedNftokenID == maskedMarker &&
131  nftokenID <= marker)
132  continue;
133 
134  pastMarker = true;
135 
136  {
137  Json::Value& obj = nfts.append(o.getJson(JsonOptions::none));
138 
139  // Pull out the components of the nft ID.
140  obj[sfFlags.jsonName] = nft::getFlags(nftokenID);
141  obj[sfIssuer.jsonName] = to_string(nft::getIssuer(nftokenID));
142  obj[sfNFTokenTaxon.jsonName] =
143  nft::toUInt32(nft::getTaxon(nftokenID));
144  obj[jss::nft_serial] = nft::getSerial(nftokenID);
145  if (std::uint16_t xferFee = {nft::getTransferFee(nftokenID)})
146  obj[sfTransferFee.jsonName] = xferFee;
147  }
148 
149  if (++cnt == limit)
150  {
151  result[jss::limit] = limit;
152  result[jss::marker] = to_string(o.getFieldH256(sfNFTokenID));
153  return result;
154  }
155  }
156 
157  if (auto npm = (*cp)[~sfNextPageMin])
158  cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm));
159  else
160  cp = nullptr;
161  }
162 
163  result[jss::account] = toBase58(accountID);
165  return result;
166 }
167 
170 {
171  auto const& params = context.params;
172  if (!params.isMember(jss::account))
173  return RPC::missing_field_error(jss::account);
174 
176  auto result = RPC::lookupLedger(ledger, context);
177  if (ledger == nullptr)
178  return result;
179 
180  AccountID accountID;
181  {
182  auto const strIdent = params[jss::account].asString();
183  if (auto jv = RPC::accountFromString(accountID, strIdent))
184  {
185  for (auto it = jv.begin(); it != jv.end(); ++it)
186  result[it.memberName()] = *it;
187 
188  return result;
189  }
190  }
191 
192  if (!ledger->exists(keylet::account(accountID)))
193  return rpcError(rpcACT_NOT_FOUND);
194 
196 
197  if (params.isMember(jss::deletion_blockers_only) &&
198  params[jss::deletion_blockers_only].asBool())
199  {
200  struct
201  {
202  Json::StaticString name;
203  LedgerEntryType type;
204  } static constexpr deletionBlockers[] = {
205  {jss::check, ltCHECK},
206  {jss::escrow, ltESCROW},
207  {jss::nft_page, ltNFTOKEN_PAGE},
208  {jss::payment_channel, ltPAYCHAN},
209  {jss::state, ltRIPPLE_STATE}};
210 
211  typeFilter.emplace();
212  typeFilter->reserve(std::size(deletionBlockers));
213 
214  for (auto [name, type] : deletionBlockers)
215  {
216  if (params.isMember(jss::type) && name != params[jss::type])
217  {
218  continue;
219  }
220 
221  typeFilter->push_back(type);
222  }
223  }
224  else
225  {
226  auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params);
227 
228  if (rpcStatus)
229  {
230  result.clear();
231  rpcStatus.inject(result);
232  return result;
233  }
234  else if (type != ltANY)
235  {
236  typeFilter = std::vector<LedgerEntryType>({type});
237  }
238  }
239 
240  unsigned int limit;
241  if (auto err = readLimitField(limit, RPC::Tuning::accountObjects, context))
242  return *err;
243 
244  uint256 dirIndex;
245  uint256 entryIndex;
246  if (params.isMember(jss::marker))
247  {
248  auto const& marker = params[jss::marker];
249  if (!marker.isString())
250  return RPC::expected_field_error(jss::marker, "string");
251 
252  std::stringstream ss(marker.asString());
253  std::string s;
254  if (!std::getline(ss, s, ','))
255  return RPC::invalid_field_error(jss::marker);
256 
257  if (!dirIndex.parseHex(s))
258  return RPC::invalid_field_error(jss::marker);
259 
260  if (!std::getline(ss, s, ','))
261  return RPC::invalid_field_error(jss::marker);
262 
263  if (!entryIndex.parseHex(s))
264  return RPC::invalid_field_error(jss::marker);
265  }
266 
268  *ledger,
269  accountID,
270  typeFilter,
271  dirIndex,
272  entryIndex,
273  limit,
274  result))
275  {
276  result[jss::account_objects] = Json::arrayValue;
277  }
278 
279  result[jss::account] = toBase58(accountID);
281  return result;
282 }
283 
284 } // namespace ripple
ripple::doAccountNFTs
Json::Value doAccountNFTs(RPC::JsonContext &context)
General RPC command that can retrieve objects in the account root.
Definition: AccountObjects.cpp:52
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: NFTokenUtils.h:120
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:176
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:169
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:151
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:136
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:136
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:675
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:328
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:262
ripple::nft::getIssuer
AccountID getIssuer(uint256 const &id)
Definition: NFTokenUtils.h:180
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
ripple::keylet::nftpage_min
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Definition: Indexes.cpp:332
ripple::keylet::nftpage
Keylet nftpage(Keylet const &k, uint256 const &token)
Definition: Indexes.cpp:348
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:133
ripple::nft::toUInt32
std::uint32_t toUInt32(Taxon t)
Definition: NFTokenUtils.h:46
ripple::ltESCROW
@ ltESCROW
A ledger object describing a single escrow.
Definition: LedgerFormats.h:124
ripple::JsonOptions::none
@ none
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:340
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: NFTokenUtils.h:136
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:156
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::LedgerEntryType
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:53
ripple::sfIssuer
const SF_ACCOUNT sfIssuer
ripple::RPC::chooseLedgerEntryType
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:979
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
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: NFTokenUtils.h:128
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: NFTokenUtils.h:168
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:304
ripple::RPC::accountFromString
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
Definition: RPCHelpers.cpp:86
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:130
string