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/RippleState.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 };
40 
41 void
42 addLine(Json::Value& jsonLines, RippleState const& line)
43 {
44  STAmount const& saBalance(line.getBalance());
45  STAmount const& saLimit(line.getLimit());
46  STAmount const& saLimitPeer(line.getLimitPeer());
47  Json::Value& jPeer(jsonLines.append(Json::objectValue));
48 
49  jPeer[jss::account] = to_string(line.getAccountIDPeer());
50  // Amount reported is positive if current account holds other
51  // account's IOUs.
52  //
53  // Amount reported is negative if other account holds current
54  // account's IOUs.
55  jPeer[jss::balance] = saBalance.getText();
56  jPeer[jss::currency] = to_string(saBalance.issue().currency);
57  jPeer[jss::limit] = saLimit.getText();
58  jPeer[jss::limit_peer] = saLimitPeer.getText();
59  jPeer[jss::quality_in] = line.getQualityIn().value;
60  jPeer[jss::quality_out] = line.getQualityOut().value;
61  if (line.getAuth())
62  jPeer[jss::authorized] = true;
63  if (line.getAuthPeer())
64  jPeer[jss::peer_authorized] = true;
65  if (line.getNoRipple() || !line.getDefaultRipple())
66  jPeer[jss::no_ripple] = line.getNoRipple();
67  if (line.getNoRipplePeer() || !line.getDefaultRipple())
68  jPeer[jss::no_ripple_peer] = line.getNoRipplePeer();
69  if (line.getFreeze())
70  jPeer[jss::freeze] = true;
71  if (line.getFreezePeer())
72  jPeer[jss::freeze_peer] = true;
73 }
74 
75 // {
76 // account: <account>|<account_public_key>
77 // ledger_hash : <ledger>
78 // ledger_index : <ledger_index>
79 // limit: integer // optional
80 // marker: opaque // optional, resume previous query
81 // }
84 {
85  auto const& params(context.params);
86  if (!params.isMember(jss::account))
87  return RPC::missing_field_error(jss::account);
88 
90  auto result = RPC::lookupLedger(ledger, context);
91  if (!ledger)
92  return result;
93 
94  std::string strIdent(params[jss::account].asString());
95  AccountID accountID;
96 
97  if (auto jv = RPC::accountFromString(accountID, strIdent))
98  {
99  for (auto it = jv.begin(); it != jv.end(); ++it)
100  result[it.memberName()] = *it;
101  return result;
102  }
103 
104  if (!ledger->exists(keylet::account(accountID)))
105  return rpcError(rpcACT_NOT_FOUND);
106 
107  std::string strPeer;
108  if (params.isMember(jss::peer))
109  strPeer = params[jss::peer].asString();
110  auto hasPeer = !strPeer.empty();
111 
112  AccountID raPeerAccount;
113  if (hasPeer)
114  {
115  if (auto jv = RPC::accountFromString(raPeerAccount, strPeer))
116  {
117  for (auto it = jv.begin(); it != jv.end(); ++it)
118  result[it.memberName()] = *it;
119  return result;
120  }
121  }
122 
123  unsigned int limit;
124  if (auto err = readLimitField(limit, RPC::Tuning::accountLines, context))
125  return *err;
126 
127  Json::Value& jsonLines(result[jss::lines] = Json::arrayValue);
128  VisitData visitData = {{}, accountID, hasPeer, raPeerAccount};
129  unsigned int reserve(limit);
130  uint256 startAfter;
131  std::uint64_t startHint;
132 
133  if (params.isMember(jss::marker))
134  {
135  // We have a start point. Use limit - 1 from the result and use the
136  // very last one for the resume.
137  Json::Value const& marker(params[jss::marker]);
138 
139  if (!marker.isString())
140  return RPC::expected_field_error(jss::marker, "string");
141 
142  if (!startAfter.parseHex(marker.asString()))
143  return rpcError(rpcINVALID_PARAMS);
144 
145  auto const sleLine = ledger->read({ltRIPPLE_STATE, startAfter});
146 
147  if (!sleLine)
148  return rpcError(rpcINVALID_PARAMS);
149 
150  if (sleLine->getFieldAmount(sfLowLimit).getIssuer() == accountID)
151  startHint = sleLine->getFieldU64(sfLowNode);
152  else if (sleLine->getFieldAmount(sfHighLimit).getIssuer() == accountID)
153  startHint = sleLine->getFieldU64(sfHighNode);
154  else
155  return rpcError(rpcINVALID_PARAMS);
156 
157  // Caller provided the first line (startAfter), add it as first result
158  auto const line = RippleState::makeItem(accountID, sleLine);
159  if (line == nullptr)
160  return rpcError(rpcINVALID_PARAMS);
161 
162  addLine(jsonLines, *line);
163  visitData.items.reserve(reserve);
164  }
165  else
166  {
167  startHint = 0;
168  // We have no start point, limit should be one higher than requested.
169  visitData.items.reserve(++reserve);
170  }
171 
172  {
173  if (!forEachItemAfter(
174  *ledger,
175  accountID,
176  startAfter,
177  startHint,
178  reserve,
179  [&visitData](std::shared_ptr<SLE const> const& sleCur) {
180  auto const line =
181  RippleState::makeItem(visitData.accountID, sleCur);
182  if (line != nullptr &&
183  (!visitData.hasPeer ||
184  visitData.raPeerAccount == line->getAccountIDPeer()))
185  {
186  visitData.items.emplace_back(line);
187  return true;
188  }
189 
190  return false;
191  }))
192  {
193  return rpcError(rpcINVALID_PARAMS);
194  }
195  }
196 
197  if (visitData.items.size() == reserve)
198  {
199  result[jss::limit] = limit;
200 
201  RippleState::pointer line(visitData.items.back());
202  result[jss::marker] = to_string(line->key());
203  visitData.items.pop_back();
204  }
205 
206  result[jss::account] = context.app.accountIDCache().toBase58(accountID);
207 
208  for (auto const& item : visitData.items)
209  addLine(jsonLines, *item.get());
210 
212  return result;
213 }
214 
215 } // namespace ripple
ripple::RippleState
Wraps a trust line SLE for convenience.
Definition: RippleState.h:39
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
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
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
Json::Value::get
Value get(UInt index, const Value &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
Definition: json_value.cpp:834
std::vector
STL class.
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:510
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::VisitData::raPeerAccount
AccountID const & raPeerAccount
Definition: AccountLines.cpp:38
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
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:487
ripple::VisitData
Definition: AccountLines.cpp:33
ripple::Application::accountIDCache
virtual AccountIDCache const & accountIDCache() const =0
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:302
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:236
ripple::sfLowNode
const SF_UINT64 sfLowNode
ripple::Keylet::key
uint256 key
Definition: Keylet.h:41
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:134
ripple::RippleState::makeItem
static RippleState::pointer makeItem(AccountID const &accountID, std::shared_ptr< SLE const > sle)
Definition: RippleState.cpp:29
ripple::rpcACT_NOT_FOUND
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
ripple::STAmount
Definition: STAmount.h:42
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::ReadView::exists
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
std::uint64_t
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::addLine
void addLine(Json::Value &jsonLines, RippleState const &line)
Definition: AccountLines.cpp:42
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ltRIPPLE_STATE
@ ltRIPPLE_STATE
Definition: LedgerFormats.h:66
ripple::base_uint::parseHex
bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:384
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:197
ripple::VisitData::items
std::vector< RippleState::pointer > items
Definition: AccountLines.cpp:35
std::string::empty
T empty(T... args)
ripple::forEachItemAfter
bool forEachItemAfter(ReadView const &view, AccountID const &id, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(std::shared_ptr< SLE const > const &)> f)
Iterate all items after an item in an owner directory.
Definition: View.cpp:274
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::sfHighNode
const SF_UINT64 sfHighNode
ripple::RPC::accountFromString
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
Definition: RPCHelpers.cpp:82
ripple::doAccountLines
Json::Value doAccountLines(RPC::JsonContext &context)
Definition: AccountLines.cpp:83
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::AccountIDCache::toBase58
std::string toBase58(AccountID const &) const
Return ripple::toBase58 for the AccountID.
Definition: AccountID.cpp:134
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469