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  startAfter.SetHex(marker.asString());
143  auto const sleLine = ledger->read({ltRIPPLE_STATE, startAfter});
144 
145  if (!sleLine)
146  return rpcError(rpcINVALID_PARAMS);
147 
148  if (sleLine->getFieldAmount(sfLowLimit).getIssuer() == accountID)
149  startHint = sleLine->getFieldU64(sfLowNode);
150  else if (sleLine->getFieldAmount(sfHighLimit).getIssuer() == accountID)
151  startHint = sleLine->getFieldU64(sfHighNode);
152  else
153  return rpcError(rpcINVALID_PARAMS);
154 
155  // Caller provided the first line (startAfter), add it as first result
156  auto const line = RippleState::makeItem(accountID, sleLine);
157  if (line == nullptr)
158  return rpcError(rpcINVALID_PARAMS);
159 
160  addLine(jsonLines, *line);
161  visitData.items.reserve(reserve);
162  }
163  else
164  {
165  startHint = 0;
166  // We have no start point, limit should be one higher than requested.
167  visitData.items.reserve(++reserve);
168  }
169 
170  {
171  if (!forEachItemAfter(
172  *ledger,
173  accountID,
174  startAfter,
175  startHint,
176  reserve,
177  [&visitData](std::shared_ptr<SLE const> const& sleCur) {
178  auto const line =
179  RippleState::makeItem(visitData.accountID, sleCur);
180  if (line != nullptr &&
181  (!visitData.hasPeer ||
182  visitData.raPeerAccount == line->getAccountIDPeer()))
183  {
184  visitData.items.emplace_back(line);
185  return true;
186  }
187 
188  return false;
189  }))
190  {
191  return rpcError(rpcINVALID_PARAMS);
192  }
193  }
194 
195  if (visitData.items.size() == reserve)
196  {
197  result[jss::limit] = limit;
198 
199  RippleState::pointer line(visitData.items.back());
200  result[jss::marker] = to_string(line->key());
201  visitData.items.pop_back();
202  }
203 
204  result[jss::account] = context.app.accountIDCache().toBase58(accountID);
205 
206  for (auto const& item : visitData.items)
207  addLine(jsonLines, *item.get());
208 
210  return result;
211 }
212 
213 } // 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::sfHighLimit
const SF_Amount sfHighLimit(access, STI_AMOUNT, 7, "HighLimit")
Definition: SField.h:447
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::sfLowLimit
const SF_Amount sfLowLimit(access, STI_AMOUNT, 6, "LowLimit")
Definition: SField.h:446
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::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint< 160, detail::AccountIDTag >
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
ripple::sfHighNode
const SF_U64 sfHighNode(access, STI_UINT64, 8, "HighNode")
Definition: SField.h:404
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:129
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::base_uint::SetHex
bool SetHex(const char *psz, bool bStrict=false)
Parse a hex string into a base_uint The input can be:
Definition: base_uint.h:406
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::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::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::sfLowNode
const SF_U64 sfLowNode(access, STI_UINT64, 7, "LowNode")
Definition: SField.h:403
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
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:177
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469