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/app/main/Application.h>
21#include <xrpld/ledger/ReadView.h>
22#include <xrpld/ledger/View.h>
23#include <xrpld/rpc/Context.h>
24#include <xrpld/rpc/detail/RPCHelpers.h>
25#include <xrpld/rpc/detail/Tuning.h>
26#include <xrpl/protocol/ErrorCodes.h>
27#include <xrpl/protocol/PublicKey.h>
28#include <xrpl/protocol/RPCErr.h>
29#include <xrpl/protocol/STAccount.h>
30#include <xrpl/protocol/jss.h>
31#include <xrpl/resource/Fees.h>
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 if (limit == 0u)
108
109 Json::Value jsonChannels{Json::arrayValue};
110 struct VisitData
111 {
113 AccountID const& accountID;
114 std::optional<AccountID> const& raDstAccount;
115 };
116 VisitData visitData = {{}, accountID, raDstAccount};
117 visitData.items.reserve(limit);
118 uint256 startAfter = beast::zero;
119 std::uint64_t startHint = 0;
120
121 if (params.isMember(jss::marker))
122 {
123 if (!params[jss::marker].isString())
124 return RPC::expected_field_error(jss::marker, "string");
125
126 // Marker is composed of a comma separated index and start hint. The
127 // former will be read as hex, and the latter using boost lexical cast.
128 std::stringstream marker(params[jss::marker].asString());
129 std::string value;
130 if (!std::getline(marker, value, ','))
132
133 if (!startAfter.parseHex(value))
135
136 if (!std::getline(marker, value, ','))
138
139 try
140 {
141 startHint = boost::lexical_cast<std::uint64_t>(value);
142 }
143 catch (boost::bad_lexical_cast&)
144 {
146 }
147
148 // We then must check if the object pointed to by the marker is actually
149 // owned by the account in the request.
150 auto const sle = ledger->read({ltANY, startAfter});
151
152 if (!sle)
154
155 if (!RPC::isRelatedToAccount(*ledger, sle, accountID))
157 }
158
159 auto count = 0;
160 std::optional<uint256> marker = {};
161 std::uint64_t nextHint = 0;
162 if (!forEachItemAfter(
163 *ledger,
164 accountID,
165 startAfter,
166 startHint,
167 limit + 1,
168 [&visitData, &accountID, &count, &limit, &marker, &nextHint](
169 std::shared_ptr<SLE const> const& sleCur) {
170 if (!sleCur)
171 {
172 UNREACHABLE("ripple::doAccountChannels : null SLE");
173 return false;
174 }
175
176 if (++count == limit)
177 {
178 marker = sleCur->key();
179 nextHint = RPC::getStartHint(sleCur, visitData.accountID);
180 }
181
182 if (count <= limit && sleCur->getType() == ltPAYCHAN &&
183 (*sleCur)[sfAccount] == accountID &&
184 (!visitData.raDstAccount ||
185 *visitData.raDstAccount == (*sleCur)[sfDestination]))
186 {
187 visitData.items.emplace_back(sleCur);
188 }
189
190 return true;
191 }))
192 {
194 }
195
196 // Both conditions need to be checked because marker is set on the limit-th
197 // item, but if there is no item on the limit + 1 iteration, then there is
198 // no need to return a marker.
199 if (count == limit + 1 && marker)
200 {
201 result[jss::limit] = limit;
202 result[jss::marker] =
203 to_string(*marker) + "," + std::to_string(nextHint);
204 }
205
206 result[jss::account] = toBase58(accountID);
207
208 for (auto const& item : visitData.items)
209 addChannel(jsonChannels, *item);
210
212 result[jss::channels] = std::move(jsonChannels);
213 return result;
214}
215
216} // namespace ripple
Represents a JSON value.
Definition: json_value.h:147
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:891
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:502
T empty(T... args)
T getline(T... args)
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
static LimitRange constexpr accountChannels
Limits for the account_channels command.
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:315
bool isRelatedToAccount(ReadView const &ledger, std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Tests if a SLE is owned by accountID.
Definition: RPCHelpers.cpp:116
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:339
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:623
std::uint64_t getStartHint(std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Gets the start hint for traversing account objects.
Definition: RPCHelpers.cpp:99
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:273
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:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:106
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:29
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
@ ltANY
A special type, matching any ledger entry type.
Definition: LedgerFormats.h:78
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:572
Json::Value doAccountChannels(RPC::JsonContext &context)
uint256 key
Definition: Keylet.h:40
Resource::Charge & loadType
Definition: Context.h:43
Json::Value params
Definition: Context.h:64
T to_string(T... args)