rippled
Loading...
Searching...
No Matches
AccountChannels.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/rpc/Context.h>
21#include <xrpld/rpc/detail/RPCHelpers.h>
22#include <xrpld/rpc/detail/Tuning.h>
23
24#include <xrpl/ledger/ReadView.h>
25#include <xrpl/ledger/View.h>
26#include <xrpl/protocol/ErrorCodes.h>
27#include <xrpl/protocol/PublicKey.h>
28#include <xrpl/protocol/RPCErr.h>
29#include <xrpl/protocol/jss.h>
30#include <xrpl/resource/Fees.h>
31
32namespace ripple {
33
34void
35addChannel(Json::Value& jsonLines, SLE const& line)
36{
37 Json::Value& jDst(jsonLines.append(Json::objectValue));
38 jDst[jss::channel_id] = to_string(line.key());
39 jDst[jss::account] = to_string(line[sfAccount]);
40 jDst[jss::destination_account] = to_string(line[sfDestination]);
41 jDst[jss::amount] = line[sfAmount].getText();
42 jDst[jss::balance] = line[sfBalance].getText();
43 if (publicKeyType(line[sfPublicKey]))
44 {
45 PublicKey const pk(line[sfPublicKey]);
46 jDst[jss::public_key] = toBase58(TokenType::AccountPublic, pk);
47 jDst[jss::public_key_hex] = strHex(pk);
48 }
49 jDst[jss::settle_delay] = line[sfSettleDelay];
50 if (auto const& v = line[~sfExpiration])
51 jDst[jss::expiration] = *v;
52 if (auto const& v = line[~sfCancelAfter])
53 jDst[jss::cancel_after] = *v;
54 if (auto const& v = line[~sfSourceTag])
55 jDst[jss::source_tag] = *v;
56 if (auto const& v = line[~sfDestinationTag])
57 jDst[jss::destination_tag] = *v;
58}
59
60// {
61// account: <account>
62// ledger_hash : <ledger>
63// ledger_index : <ledger_index>
64// limit: integer // optional
65// marker: opaque // optional, resume previous query
66// }
69{
70 auto const& params(context.params);
71 if (!params.isMember(jss::account))
72 return RPC::missing_field_error(jss::account);
73
74 if (!params[jss::account].isString())
75 return RPC::invalid_field_error(jss::account);
76
78 auto result = RPC::lookupLedger(ledger, context);
79 if (!ledger)
80 return result;
81
82 auto id = parseBase58<AccountID>(params[jss::account].asString());
83 if (!id)
84 {
86 }
87 AccountID const accountID{std::move(id.value())};
88
89 if (!ledger->exists(keylet::account(accountID)))
91
92 std::string strDst;
93 if (params.isMember(jss::destination_account))
94 strDst = params[jss::destination_account].asString();
95
96 auto const raDstAccount = [&]() -> std::optional<AccountID> {
97 return strDst.empty() ? std::nullopt : parseBase58<AccountID>(strDst);
98 }();
99 if (!strDst.empty() && !raDstAccount)
101
102 unsigned int limit;
103 if (auto err = readLimitField(limit, RPC::Tuning::accountChannels, context))
104 return *err;
105
106 Json::Value jsonChannels{Json::arrayValue};
107 struct VisitData
108 {
110 AccountID const& accountID;
111 std::optional<AccountID> const& raDstAccount;
112 };
113 VisitData visitData = {{}, accountID, raDstAccount};
114 visitData.items.reserve(limit);
115 uint256 startAfter = beast::zero;
116 std::uint64_t startHint = 0;
117
118 if (params.isMember(jss::marker))
119 {
120 if (!params[jss::marker].isString())
121 return RPC::expected_field_error(jss::marker, "string");
122
123 // Marker is composed of a comma separated index and start hint. The
124 // former will be read as hex, and the latter using boost lexical cast.
125 std::stringstream marker(params[jss::marker].asString());
126 std::string value;
127 if (!std::getline(marker, value, ','))
129
130 if (!startAfter.parseHex(value))
132
133 if (!std::getline(marker, value, ','))
135
136 try
137 {
138 startHint = boost::lexical_cast<std::uint64_t>(value);
139 }
140 catch (boost::bad_lexical_cast&)
141 {
143 }
144
145 // We then must check if the object pointed to by the marker is actually
146 // owned by the account in the request.
147 auto const sle = ledger->read({ltANY, startAfter});
148
149 if (!sle)
151
152 if (!RPC::isRelatedToAccount(*ledger, sle, accountID))
154 }
155
156 auto count = 0;
157 std::optional<uint256> marker = {};
158 std::uint64_t nextHint = 0;
159 if (!forEachItemAfter(
160 *ledger,
161 accountID,
162 startAfter,
163 startHint,
164 limit + 1,
165 [&visitData, &accountID, &count, &limit, &marker, &nextHint](
166 std::shared_ptr<SLE const> const& sleCur) {
167 if (!sleCur)
168 {
169 // LCOV_EXCL_START
170 UNREACHABLE("ripple::doAccountChannels : null SLE");
171 return false;
172 // LCOV_EXCL_STOP
173 }
174
175 if (++count == limit)
176 {
177 marker = sleCur->key();
178 nextHint = RPC::getStartHint(sleCur, visitData.accountID);
179 }
180
181 if (count <= limit && sleCur->getType() == ltPAYCHAN &&
182 (*sleCur)[sfAccount] == accountID &&
183 (!visitData.raDstAccount ||
184 *visitData.raDstAccount == (*sleCur)[sfDestination]))
185 {
186 visitData.items.emplace_back(sleCur);
187 }
188
189 return true;
190 }))
191 {
193 }
194
195 // Both conditions need to be checked because marker is set on the limit-th
196 // item, but if there is no item on the limit + 1 iteration, then there is
197 // no need to return a marker.
198 if (count == limit + 1 && marker)
199 {
200 result[jss::limit] = limit;
201 result[jss::marker] =
202 to_string(*marker) + "," + std::to_string(nextHint);
203 }
204
205 result[jss::account] = toBase58(accountID);
206
207 for (auto const& item : visitData.items)
208 addChannel(jsonChannels, *item);
209
211 result[jss::channels] = std::move(jsonChannels);
212 return result;
213}
214
215} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
Value & append(Value const &value)
Append value to array at the end.
A public key.
Definition PublicKey.h:62
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 accountChannels
Limits for the account_channels 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.
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 addChannel(Json::Value &jsonLines, SLE const &line)
@ rpcACT_NOT_FOUND
Definition ErrorCodes.h:70
@ rpcACT_MALFORMED
Definition ErrorCodes.h:90
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:84
Json::Value rpcError(int iError)
Definition RPCErr.cpp:31
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:30
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.
Json::Value doAccountChannels(RPC::JsonContext &context)
uint256 key
Definition Keylet.h:40
Resource::Charge & loadType
Definition Context.h:42
T to_string(T... args)