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