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