rippled
AccountLines.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/paths/TrustLine.h>
22 #include <ripple/ledger/ReadView.h>
23 #include <ripple/net/RPCErr.h>
24 #include <ripple/protocol/ErrorCodes.h>
25 #include <ripple/protocol/jss.h>
26 #include <ripple/resource/Fees.h>
27 #include <ripple/rpc/Context.h>
28 #include <ripple/rpc/impl/RPCHelpers.h>
29 #include <ripple/rpc/impl/Tuning.h>
30 
31 namespace ripple {
32 
33 struct VisitData
34 {
37  bool hasPeer;
39 
41  uint32_t foundCount;
42 };
43 
44 void
45 addLine(Json::Value& jsonLines, RPCTrustLine const& line)
46 {
47  STAmount const& saBalance(line.getBalance());
48  STAmount const& saLimit(line.getLimit());
49  STAmount const& saLimitPeer(line.getLimitPeer());
50  Json::Value& jPeer(jsonLines.append(Json::objectValue));
51 
52  jPeer[jss::account] = to_string(line.getAccountIDPeer());
53  // Amount reported is positive if current account holds other
54  // account's IOUs.
55  //
56  // Amount reported is negative if other account holds current
57  // account's IOUs.
58  jPeer[jss::balance] = saBalance.getText();
59  jPeer[jss::currency] = to_string(saBalance.issue().currency);
60  jPeer[jss::limit] = saLimit.getText();
61  jPeer[jss::limit_peer] = saLimitPeer.getText();
62  jPeer[jss::quality_in] = line.getQualityIn().value;
63  jPeer[jss::quality_out] = line.getQualityOut().value;
64  if (line.getAuth())
65  jPeer[jss::authorized] = true;
66  if (line.getAuthPeer())
67  jPeer[jss::peer_authorized] = true;
68  if (line.getNoRipple() || !line.getDefaultRipple())
69  jPeer[jss::no_ripple] = line.getNoRipple();
70  if (line.getNoRipplePeer() || !line.getDefaultRipple())
71  jPeer[jss::no_ripple_peer] = line.getNoRipplePeer();
72  if (line.getFreeze())
73  jPeer[jss::freeze] = true;
74  if (line.getFreezePeer())
75  jPeer[jss::freeze_peer] = true;
76 }
77 
78 // {
79 // account: <account>|<account_public_key>
80 // ledger_hash : <ledger>
81 // ledger_index : <ledger_index>
82 // limit: integer // optional
83 // marker: opaque // optional, resume previous query
84 // ignore_default: bool // do not return lines in default state (on
85 // this account's side)
86 // }
89 {
90  auto const& params(context.params);
91  if (!params.isMember(jss::account))
92  return RPC::missing_field_error(jss::account);
93 
95  auto result = RPC::lookupLedger(ledger, context);
96  if (!ledger)
97  return result;
98 
99  std::string strIdent(params[jss::account].asString());
100  AccountID accountID;
101 
102  if (auto jv = RPC::accountFromString(accountID, strIdent))
103  {
104  for (auto it = jv.begin(); it != jv.end(); ++it)
105  result[it.memberName()] = *it;
106  return result;
107  }
108 
109  if (!ledger->exists(keylet::account(accountID)))
110  return rpcError(rpcACT_NOT_FOUND);
111 
112  std::string strPeer;
113  if (params.isMember(jss::peer))
114  strPeer = params[jss::peer].asString();
115  auto hasPeer = !strPeer.empty();
116 
117  AccountID raPeerAccount;
118  if (hasPeer)
119  {
120  if (auto jv = RPC::accountFromString(raPeerAccount, strPeer))
121  {
122  for (auto it = jv.begin(); it != jv.end(); ++it)
123  result[it.memberName()] = *it;
124  return result;
125  }
126  }
127 
128  unsigned int limit;
129  if (auto err = readLimitField(limit, RPC::Tuning::accountLines, context))
130  return *err;
131 
132  if (limit == 0)
133  return rpcError(rpcINVALID_PARAMS);
134 
135  // this flag allows the requester to ask incoming trustlines in default
136  // state be omitted
137  bool ignoreDefault = params.isMember(jss::ignore_default) &&
138  params[jss::ignore_default].asBool();
139 
140  Json::Value& jsonLines(result[jss::lines] = Json::arrayValue);
141  VisitData visitData = {
142  {}, accountID, hasPeer, raPeerAccount, ignoreDefault, 0};
143  uint256 startAfter = beast::zero;
144  std::uint64_t startHint = 0;
145 
146  if (params.isMember(jss::marker))
147  {
148  if (!params[jss::marker].isString())
149  return RPC::expected_field_error(jss::marker, "string");
150 
151  // Marker is composed of a comma separated index and start hint. The
152  // former will be read as hex, and the latter using boost lexical cast.
153  std::stringstream marker(params[jss::marker].asString());
154  std::string value;
155  if (!std::getline(marker, value, ','))
156  return rpcError(rpcINVALID_PARAMS);
157 
158  if (!startAfter.parseHex(value))
159  return rpcError(rpcINVALID_PARAMS);
160 
161  if (!std::getline(marker, value, ','))
162  return rpcError(rpcINVALID_PARAMS);
163 
164  try
165  {
166  startHint = boost::lexical_cast<std::uint64_t>(value);
167  }
168  catch (boost::bad_lexical_cast&)
169  {
170  return rpcError(rpcINVALID_PARAMS);
171  }
172 
173  // We then must check if the object pointed to by the marker is actually
174  // owned by the account in the request.
175  auto const sle = ledger->read({ltANY, startAfter});
176 
177  if (!sle)
178  return rpcError(rpcINVALID_PARAMS);
179 
180  if (!RPC::isRelatedToAccount(*ledger, sle, accountID))
181  return rpcError(rpcINVALID_PARAMS);
182  }
183 
184  auto count = 0;
185  std::optional<uint256> marker = {};
186  std::uint64_t nextHint = 0;
187  {
188  if (!forEachItemAfter(
189  *ledger,
190  accountID,
191  startAfter,
192  startHint,
193  limit + 1,
194  [&visitData, &count, &marker, &limit, &nextHint](
195  std::shared_ptr<SLE const> const& sleCur) {
196  if (!sleCur)
197  {
198  assert(false);
199  return false;
200  }
201 
202  if (++count == limit)
203  {
204  marker = sleCur->key();
205  nextHint =
206  RPC::getStartHint(sleCur, visitData.accountID);
207  }
208 
209  if (sleCur->getType() != ltRIPPLE_STATE)
210  return true;
211 
212  bool ignore = false;
213  if (visitData.ignoreDefault)
214  {
215  if (sleCur->getFieldAmount(sfLowLimit).getIssuer() ==
216  visitData.accountID)
217  ignore =
218  !(sleCur->getFieldU32(sfFlags) & lsfLowReserve);
219  else
220  ignore = !(
221  sleCur->getFieldU32(sfFlags) & lsfHighReserve);
222  }
223 
224  if (!ignore && count <= limit)
225  {
226  auto const line =
227  RPCTrustLine::makeItem(visitData.accountID, sleCur);
228 
229  if (line &&
230  (!visitData.hasPeer ||
231  visitData.raPeerAccount ==
232  line->getAccountIDPeer()))
233  {
234  visitData.items.emplace_back(*line);
235  }
236  }
237 
238  return true;
239  }))
240  {
241  return rpcError(rpcINVALID_PARAMS);
242  }
243  }
244 
245  // Both conditions need to be checked because marker is set on the limit-th
246  // item, but if there is no item on the limit + 1 iteration, then there is
247  // no need to return a marker.
248  if (count == limit + 1 && marker)
249  {
250  result[jss::limit] = limit;
251  result[jss::marker] =
252  to_string(*marker) + "," + std::to_string(nextHint);
253  }
254 
255  result[jss::account] = toBase58(accountID);
256 
257  for (auto const& item : visitData.items)
258  addLine(jsonLines, item);
259 
261  return result;
262 }
263 
264 } // namespace ripple
ripple::STLedgerEntry::key
uint256 const & key() const
Returns the 'key' (or 'index') of this item.
Definition: STLedgerEntry.h:113
ripple::VisitData::hasPeer
bool hasPeer
Definition: AccountLines.cpp:37
ripple::RPC::JsonContext
Definition: Context.h:53
std::string
STL class.
std::shared_ptr
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
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::forEachItemAfter
bool forEachItemAfter(ReadView const &view, Keylet const &root, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items after an item in the given directory.
Definition: View.cpp:394
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:347
ripple::lsfLowReserve
@ lsfLowReserve
Definition: LedgerFormats.h:252
ripple::Resource::feeMediumBurdenRPC
const Charge feeMediumBurdenRPC
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
std::vector
STL class.
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:550
ripple::VisitData::foundCount
uint32_t foundCount
Definition: AccountLines.cpp:41
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::VisitData::raPeerAccount
AccountID const & raPeerAccount
Definition: AccountLines.cpp:38
ripple::RPCTrustLine
Definition: TrustLine.h:204
std::stringstream
STL class.
ripple::VisitData::ignoreDefault
bool ignoreDefault
Definition: AccountLines.cpp:40
ripple::VisitData::items
std::vector< RPCTrustLine > items
Definition: AccountLines.cpp:35
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:592
ripple::VisitData
Definition: AccountLines.cpp:33
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:328
ripple::STAmount::getIssuer
AccountID const & getIssuer() const
Definition: STAmount.h:359
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:262
ripple::base_uint< 160, detail::AccountIDTag >
ripple::sfLowLimit
const SF_AMOUNT sfLowLimit
ripple::VisitData::accountID
AccountID const & accountID
Definition: AccountLines.cpp:36
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::RPC::Tuning::accountLines
static constexpr LimitRange accountLines
Limits for the account_lines command.
Definition: rpc/impl/Tuning.h:37
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
ripple::rpcACT_NOT_FOUND
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
std::to_string
T to_string(T... args)
ripple::STAmount
Definition: STAmount.h:45
ripple::ReadView::exists
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
std::uint64_t
ripple::STLedgerEntry::getType
LedgerEntryType getType() const
Definition: STLedgerEntry.h:119
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::getline
T getline(T... args)
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::RPC::getStartHint
std::uint64_t getStartHint(std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Gets the start hint for traversing account objects.
Definition: RPCHelpers.cpp:96
ripple::RPCTrustLine::makeItem
static std::optional< RPCTrustLine > makeItem(AccountID const &accountID, std::shared_ptr< SLE const > const &sle)
Definition: TrustLine.cpp:110
std::string::empty
T empty(T... args)
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::ltRIPPLE_STATE
@ ltRIPPLE_STATE
A ledger object which describes a bidirectional trust line.
Definition: LedgerFormats.h:74
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:559
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::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::lsfHighReserve
@ lsfHighReserve
Definition: LedgerFormats.h:253
ripple::STObject::getFieldAmount
STAmount const & getFieldAmount(SField const &field) const
Definition: STObject.cpp:603
ripple::RPC::accountFromString
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
Definition: RPCHelpers.cpp:86
ripple::RPC::isRelatedToAccount
bool isRelatedToAccount(ReadView const &ledger, std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Tests if a SLE is owned by accountID.
Definition: RPCHelpers.cpp:113
ripple::addLine
void addLine(Json::Value &jsonLines, RPCTrustLine const &line)
Definition: AccountLines.cpp:45
ripple::doAccountLines
Json::Value doAccountLines(RPC::JsonContext &context)
Definition: AccountLines.cpp:88
Json::Value
Represents a JSON value.
Definition: json_value.h:145