xrpld
Loading...
Searching...
No Matches
AccountLines.cpp
1#include <xrpld/rpc/Context.h>
2#include <xrpld/rpc/detail/RPCHelpers.h>
3#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
4#include <xrpld/rpc/detail/TrustLine.h>
5#include <xrpld/rpc/detail/Tuning.h>
6
7#include <xrpl/basics/base_uint.h>
8#include <xrpl/beast/utility/Zero.h>
9#include <xrpl/beast/utility/instrumentation.h>
10#include <xrpl/core/ServiceRegistry.h>
11#include <xrpl/json/json_value.h>
12#include <xrpl/ledger/ReadView.h>
13#include <xrpl/ledger/helpers/DirectoryHelpers.h>
14#include <xrpl/protocol/AccountID.h>
15#include <xrpl/protocol/ErrorCodes.h>
16#include <xrpl/protocol/Indexes.h>
17#include <xrpl/protocol/LedgerFormats.h>
18#include <xrpl/protocol/RPCErr.h>
19#include <xrpl/protocol/SField.h>
20#include <xrpl/protocol/STAmount.h>
21#include <xrpl/protocol/UintTypes.h>
22#include <xrpl/protocol/jss.h>
23#include <xrpl/resource/Fees.h>
24
25#include <boost/lexical_cast.hpp>
26#include <boost/lexical_cast/bad_lexical_cast.hpp>
27
28#include <cstdint>
29#include <memory>
30#include <optional>
31#include <sstream>
32#include <string>
33#include <vector>
34
35namespace xrpl {
36
37void
38addLine(json::Value& jsonLines, RPCTrustLine const& line)
39{
40 STAmount const& saBalance(line.getBalance());
41 STAmount const& saLimit(line.getLimit());
42 STAmount const& saLimitPeer(line.getLimitPeer());
44
45 jPeer[jss::account] = to_string(line.getAccountIDPeer());
46 // Amount reported is positive if current account holds other
47 // account's IOUs.
48 //
49 // Amount reported is negative if other account holds current
50 // account's IOUs.
51 jPeer[jss::balance] = saBalance.getText();
52 jPeer[jss::currency] = to_string(saBalance.get<Issue>().currency);
53 jPeer[jss::limit] = saLimit.getText();
54 jPeer[jss::limit_peer] = saLimitPeer.getText();
55 jPeer[jss::quality_in] = line.getQualityIn().value;
56 jPeer[jss::quality_out] = line.getQualityOut().value;
57 if (line.getAuth())
58 jPeer[jss::authorized] = true;
59 if (line.getAuthPeer())
60 jPeer[jss::peer_authorized] = true;
61 if (line.getNoRipple())
62 jPeer[jss::no_ripple] = true;
63 if (line.getNoRipplePeer())
64 jPeer[jss::no_ripple_peer] = true;
65 if (line.getFreeze())
66 jPeer[jss::freeze] = true;
67 if (line.getFreezePeer())
68 jPeer[jss::freeze_peer] = true;
69 if (line.getDeepFreeze())
70 jPeer[jss::deep_freeze] = true;
71 if (line.getDeepFreezePeer())
72 jPeer[jss::deep_freeze_peer] = true;
73}
74
75// {
76// account: <account>
77// ledger_hash : <ledger>
78// ledger_index : <ledger_index>
79// limit: integer // optional
80// marker: opaque // optional, resume previous query
81// ignore_default: bool // do not return lines in default state (on
82// this account's side)
83// }
86{
87 auto const& params(context.params);
88 if (!params.isMember(jss::account))
89 return RPC::missingFieldError(jss::account);
90
91 if (!params[jss::account].isString())
92 return RPC::invalidFieldError(jss::account);
93
95 auto result = RPC::lookupLedger(ledger, context);
96 if (!ledger)
97 return result;
98
99 auto id = parseBase58<AccountID>(params[jss::account].asString());
100 if (!id)
101 {
103 return result;
104 }
105 auto const accountID{id.value()};
106
107 if (!ledger->exists(keylet::account(accountID)))
108 return rpcError(RpcActNotFound);
109
110 std::string strPeer;
111 if (params.isMember(jss::peer))
112 strPeer = params[jss::peer].asString();
113
114 auto const raPeerAccount = [&]() -> std::optional<AccountID> {
115 return strPeer.empty() ? std::nullopt : parseBase58<AccountID>(strPeer);
116 }();
117 if (!strPeer.empty() && !raPeerAccount)
118 {
120 return result;
121 }
122
123 unsigned int limit = 0;
124 if (auto err = readLimitField(limit, RPC::Tuning::kAccountLines, context))
125 return *err;
126
127 // this flag allows the requester to ask incoming trustlines in default
128 // state be omitted
129 bool const ignoreDefault =
130 params.isMember(jss::ignore_default) && params[jss::ignore_default].asBool();
131
132 json::Value& jsonLines(result[jss::lines] = json::ValueType::Array);
133 struct VisitData
134 {
136 AccountID const& accountID;
137 std::optional<AccountID> const& raPeerAccount;
138 bool ignoreDefault;
139 uint32_t foundCount;
140 };
141 VisitData visitData = {
142 .items = {},
143 .accountID = accountID,
144 .raPeerAccount = raPeerAccount,
145 .ignoreDefault = ignoreDefault,
146 .foundCount = 0};
147 uint256 startAfter = beast::kZero;
148 std::uint64_t startHint = 0;
149
150 if (params.isMember(jss::marker))
151 {
152 if (!params[jss::marker].isString())
153 return RPC::expectedFieldError(jss::marker, "string");
154
155 // Marker is composed of a comma separated index and start hint. The
156 // former will be read as hex, and the latter using boost lexical cast.
157 std::stringstream marker(params[jss::marker].asString());
158 std::string value;
159 if (!std::getline(marker, value, ','))
161
162 if (!startAfter.parseHex(value))
164
165 if (!std::getline(marker, value, ','))
167
168 try
169 {
170 startHint = boost::lexical_cast<std::uint64_t>(value);
171 }
172 catch (boost::bad_lexical_cast&)
173 {
175 }
176
177 // We then must check if the object pointed to by the marker is actually
178 // owned by the account in the request.
179 auto const sle = ledger->read({ltANY, startAfter});
180
181 if (!sle)
183
184 if (!RPC::isRelatedToAccount(*ledger, sle, accountID))
186 }
187
188 auto count = 0;
189 std::optional<uint256> marker = {};
190 std::uint64_t nextHint = 0;
191 {
192 if (!forEachItemAfter(
193 *ledger,
194 accountID,
195 startAfter,
196 startHint,
197 limit + 1,
198 [&visitData, &count, &marker, &limit, &nextHint](SLE::const_ref sleCur) {
199 if (!sleCur)
200 {
201 // LCOV_EXCL_START
202 UNREACHABLE("xrpl::doAccountLines : null SLE");
203 return false;
204 // LCOV_EXCL_STOP
205 }
206
207 if (++count == limit)
208 {
209 marker = sleCur->key();
210 nextHint = RPC::getStartHint(sleCur, visitData.accountID);
211 }
212
213 if (sleCur->getType() != ltRIPPLE_STATE)
214 return true;
215
216 bool ignore = false;
217 if (visitData.ignoreDefault)
218 {
219 if (sleCur->getFieldAmount(sfLowLimit).getIssuer() == visitData.accountID)
220 {
221 ignore = !sleCur->isFlag(lsfLowReserve);
222 }
223 else
224 {
225 ignore = !sleCur->isFlag(lsfHighReserve);
226 }
227 }
228
229 if (!ignore && count <= limit)
230 {
231 auto const line = RPCTrustLine::makeItem(visitData.accountID, sleCur);
232
233 if (line &&
234 (!visitData.raPeerAccount ||
235 *visitData.raPeerAccount == line->getAccountIDPeer()))
236 {
237 visitData.items.emplace_back(*line);
238 }
239 }
240
241 return true;
242 }))
243 {
245 }
246 }
247
248 // Both conditions need to be checked because marker is set on the limit-th
249 // item, but if there is no item on the limit + 1 iteration, then there is
250 // no need to return a marker.
251 if (count == limit + 1 && marker)
252 {
253 result[jss::limit] = limit;
254 result[jss::marker] = to_string(*marker) + "," + std::to_string(nextHint);
255 }
256
257 result[jss::account] = toBase58(accountID);
258
259 for (auto const& item : visitData.items)
260 addLine(jsonLines, item);
261
263 return result;
264}
265
266} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
Value & append(Value const &value)
Append value to array at the end.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:507
A currency issued by an account.
Definition Issue.h:13
Currency currency
Definition Issue.h:15
Rate const & getQualityIn() const
Definition TrustLine.h:196
static std::optional< RPCTrustLine > makeItem(AccountID const &accountID, SLE::const_ref sle)
Definition TrustLine.cpp:87
Rate const & getQualityOut() const
Definition TrustLine.h:202
constexpr TIss const & get() const
std::string getText() const override
Definition STAmount.cpp:646
std::shared_ptr< STLedgerEntry const > const & const_ref
AccountID const & getAccountIDPeer() const
Definition TrustLine.h:65
bool getNoRipplePeer() const
Definition TrustLine.h:90
bool getAuth() const
Definition TrustLine.h:72
STAmount const & getLimit() const
Definition TrustLine.h:142
bool getDeepFreeze() const
Have we set the deep freeze flag on our peer.
Definition TrustLine.h:116
bool getFreezePeer() const
Has the peer set the freeze flag on us.
Definition TrustLine.h:123
bool getDeepFreezePeer() const
Has the peer set the deep freeze flag on us.
Definition TrustLine.h:130
STAmount const & getLimitPeer() const
Definition TrustLine.h:148
bool getFreeze() const
Have we set the freeze flag on our peer.
Definition TrustLine.h:109
bool getAuthPeer() const
Definition TrustLine.h:78
STAmount const & getBalance() const
Definition TrustLine.h:136
bool getNoRipple() const
Definition TrustLine.h:84
T empty(T... args)
T getline(T... args)
@ Array
array value (ordered list)
Definition json_value.h:25
@ Object
object value (collection of name/value pairs).
Definition json_value.h:26
static constexpr LimitRange kAccountLines
Limits for the account_lines command.
bool isRelatedToAccount(ReadView const &ledger, SLE::const_ref sle, AccountID const &accountID)
Tests if a ledger entry (SLE) is owned by the specified account.
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext const &context, json::Value &result)
Looks up a ledger from a request and fills a json::Value with ledger data.
std::uint64_t getStartHint(SLE::const_ref sle, AccountID const &accountID)
Gets the start hint for traversing account objects.
void injectError(ErrorCodeI code, json::Value &json)
Add or update the json update to reflect the error code.
json::Value invalidFieldError(std::string const &name)
Definition ErrorCodes.h:273
json::Value missingFieldError(std::string const &name)
Definition ErrorCodes.h:231
json::Value expectedFieldError(std::string const &name, std::string const &type)
Definition ErrorCodes.h:297
Charge const kFeeMediumBurdenRpc
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ RpcActNotFound
Definition ErrorCodes.h:52
@ RpcActMalformed
Definition ErrorCodes.h:72
@ RpcInvalidParams
Definition ErrorCodes.h:66
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:93
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
json::Value rpcError(ErrorCodeI iError)
Definition RPCErr.cpp:13
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
void addLine(json::Value &jsonLines, RPCTrustLine const &line)
@ ltANY
A special type, matching any ledger entry type.
json::Value doAccountLines(RPC::JsonContext &context)
BaseUInt< 256 > uint256
Definition base_uint.h:562
bool forEachItemAfter(ReadView const &view, Keylet const &root, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(SLE::const_ref)> const &f)
Iterate all items after an item in the given directory.
Resource::Charge & loadType
Definition Context.h:22
json::Value params
Definition Context.h:43
std::uint32_t value
Definition Rate.h:21
T to_string(T... args)