rippled
Loading...
Searching...
No Matches
AccountInfo.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/app/misc/TxQ.h>
22#include <xrpld/ledger/ReadView.h>
23#include <xrpld/rpc/Context.h>
24#include <xrpld/rpc/GRPCHandlers.h>
25#include <xrpld/rpc/detail/RPCHelpers.h>
26#include <xrpl/json/json_value.h>
27#include <xrpl/protocol/ErrorCodes.h>
28#include <xrpl/protocol/Indexes.h>
29#include <xrpl/protocol/RPCErr.h>
30#include <xrpl/protocol/UintTypes.h>
31#include <xrpl/protocol/jss.h>
32#include <grpc/status.h>
33
34namespace ripple {
35
36// {
37// account: <ident>,
38// ledger_hash : <ledger>
39// ledger_index : <ledger_index>
40// signer_lists : <bool> // optional (default false)
41// // if true return SignerList(s).
42// queue : <bool> // optional (default false)
43// // if true return information about transactions
44// // in the current TxQ, only if the requested
45// // ledger is open. Otherwise if true, returns an
46// // error.
47// }
48
49// TODO(tom): what is that "default"?
52{
53 auto& params = context.params;
54
55 std::string strIdent;
56 if (params.isMember(jss::account))
57 {
58 if (!params[jss::account].isString())
59 return RPC::invalid_field_error(jss::account);
60 strIdent = params[jss::account].asString();
61 }
62 else if (params.isMember(jss::ident))
63 {
64 if (!params[jss::ident].isString())
65 return RPC::invalid_field_error(jss::ident);
66 strIdent = params[jss::ident].asString();
67 }
68 else
69 return RPC::missing_field_error(jss::account);
70
72 auto result = RPC::lookupLedger(ledger, context);
73
74 if (!ledger)
75 return result;
76
77 // Get info on account.
78 auto id = parseBase58<AccountID>(strIdent);
79 if (!id)
80 {
82 return result;
83 }
84 auto const accountID{std::move(id.value())};
85
86 static constexpr std::
87 array<std::pair<std::string_view, LedgerSpecificFlags>, 9>
88 lsFlags{
89 {{"defaultRipple", lsfDefaultRipple},
90 {"depositAuth", lsfDepositAuth},
91 {"disableMasterKey", lsfDisableMaster},
92 {"disallowIncomingXRP", lsfDisallowXRP},
93 {"globalFreeze", lsfGlobalFreeze},
94 {"noFreeze", lsfNoFreeze},
95 {"passwordSpent", lsfPasswordSpent},
96 {"requireAuthorization", lsfRequireAuth},
97 {"requireDestinationTag", lsfRequireDestTag}}};
98
99 static constexpr std::
100 array<std::pair<std::string_view, LedgerSpecificFlags>, 4>
101 disallowIncomingFlags{
102 {{"disallowIncomingNFTokenOffer",
104 {"disallowIncomingCheck", lsfDisallowIncomingCheck},
105 {"disallowIncomingPayChan", lsfDisallowIncomingPayChan},
106 {"disallowIncomingTrustline", lsfDisallowIncomingTrustline}}};
107
109 allowTrustLineClawbackFlag{
110 "allowTrustLineClawback", lsfAllowTrustLineClawback};
111
112 auto const sleAccepted = ledger->read(keylet::account(accountID));
113 if (sleAccepted)
114 {
115 auto const queue =
116 params.isMember(jss::queue) && params[jss::queue].asBool();
117
118 if (queue && !ledger->open())
119 {
120 // It doesn't make sense to request the queue
121 // with any closed or validated ledger.
123 return result;
124 }
125
126 Json::Value jvAccepted(Json::objectValue);
127 RPC::injectSLE(jvAccepted, *sleAccepted);
128 result[jss::account_data] = jvAccepted;
129
131 for (auto const& lsf : lsFlags)
132 acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
133
134 if (ledger->rules().enabled(featureDisallowIncoming))
135 {
136 for (auto const& lsf : disallowIncomingFlags)
137 acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
138 }
139
140 if (ledger->rules().enabled(featureClawback))
141 acctFlags[allowTrustLineClawbackFlag.first.data()] =
142 sleAccepted->isFlag(allowTrustLineClawbackFlag.second);
143
144 result[jss::account_flags] = std::move(acctFlags);
145
146 // The document[https://xrpl.org/account_info.html#account_info] states
147 // that signer_lists is a bool, however assigning any string value
148 // works. Do not allow this. This check is for api Version 2 onwards
149 // only
150 if (context.apiVersion > 1u && params.isMember(jss::signer_lists) &&
151 !params[jss::signer_lists].isBool())
152 {
154 return result;
155 }
156
157 // Return SignerList(s) if that is requested.
158 if (params.isMember(jss::signer_lists) &&
159 params[jss::signer_lists].asBool())
160 {
161 // We put the SignerList in an array because of an anticipated
162 // future when we support multiple signer lists on one account.
163 Json::Value jvSignerList = Json::arrayValue;
164
165 // This code will need to be revisited if in the future we support
166 // multiple SignerLists on one account.
167 auto const sleSigners = ledger->read(keylet::signers(accountID));
168 if (sleSigners)
169 jvSignerList.append(sleSigners->getJson(JsonOptions::none));
170
171 // Documentation states this is returned as part of the account_info
172 // response, but previously the code put it under account_data. We
173 // can move this to the documentated location from apiVersion 2
174 // onwards.
175 if (context.apiVersion == 1)
176 {
177 result[jss::account_data][jss::signer_lists] =
178 std::move(jvSignerList);
179 }
180 else
181 {
182 result[jss::signer_lists] = std::move(jvSignerList);
183 }
184 }
185 // Return queue info if that is requested
186 if (queue)
187 {
188 Json::Value jvQueueData = Json::objectValue;
189
190 auto const txs = context.app.getTxQ().getAccountTxs(accountID);
191 if (!txs.empty())
192 {
193 jvQueueData[jss::txn_count] =
194 static_cast<Json::UInt>(txs.size());
195
196 auto& jvQueueTx = jvQueueData[jss::transactions];
197 jvQueueTx = Json::arrayValue;
198
199 std::uint32_t seqCount = 0;
200 std::uint32_t ticketCount = 0;
203 std::optional<std::uint32_t> lowestTicket;
204 std::optional<std::uint32_t> highestTicket;
205 bool anyAuthChanged = false;
206 XRPAmount totalSpend(0);
207
208 // We expect txs to be returned sorted by SeqProxy. Verify
209 // that with a couple of asserts.
210 SeqProxy prevSeqProxy = SeqProxy::sequence(0);
211 for (auto const& tx : txs)
212 {
214
215 if (tx.seqProxy.isSeq())
216 {
217 XRPL_ASSERT(
218 prevSeqProxy < tx.seqProxy,
219 "rpple::doAccountInfo : first sorted proxy");
220 prevSeqProxy = tx.seqProxy;
221 jvTx[jss::seq] = tx.seqProxy.value();
222 ++seqCount;
223 if (!lowestSeq)
224 lowestSeq = tx.seqProxy.value();
225 highestSeq = tx.seqProxy.value();
226 }
227 else
228 {
229 XRPL_ASSERT(
230 prevSeqProxy < tx.seqProxy,
231 "rpple::doAccountInfo : second sorted proxy");
232 prevSeqProxy = tx.seqProxy;
233 jvTx[jss::ticket] = tx.seqProxy.value();
234 ++ticketCount;
235 if (!lowestTicket)
236 lowestTicket = tx.seqProxy.value();
237 highestTicket = tx.seqProxy.value();
238 }
239
240 jvTx[jss::fee_level] = to_string(tx.feeLevel);
241 if (tx.lastValid)
242 jvTx[jss::LastLedgerSequence] = *tx.lastValid;
243
244 jvTx[jss::fee] = to_string(tx.consequences.fee());
245 auto const spend = tx.consequences.potentialSpend() +
246 tx.consequences.fee();
247 jvTx[jss::max_spend_drops] = to_string(spend);
248 totalSpend += spend;
249 bool const authChanged = tx.consequences.isBlocker();
250 if (authChanged)
251 anyAuthChanged = authChanged;
252 jvTx[jss::auth_change] = authChanged;
253
254 jvQueueTx.append(std::move(jvTx));
255 }
256
257 if (seqCount)
258 jvQueueData[jss::sequence_count] = seqCount;
259 if (ticketCount)
260 jvQueueData[jss::ticket_count] = ticketCount;
261 if (lowestSeq)
262 jvQueueData[jss::lowest_sequence] = *lowestSeq;
263 if (highestSeq)
264 jvQueueData[jss::highest_sequence] = *highestSeq;
265 if (lowestTicket)
266 jvQueueData[jss::lowest_ticket] = *lowestTicket;
267 if (highestTicket)
268 jvQueueData[jss::highest_ticket] = *highestTicket;
269
270 jvQueueData[jss::auth_change_queued] = anyAuthChanged;
271 jvQueueData[jss::max_spend_drops_total] = to_string(totalSpend);
272 }
273 else
274 jvQueueData[jss::txn_count] = 0u;
275
276 result[jss::queue_data] = std::move(jvQueueData);
277 }
278 }
279 else
280 {
281 result[jss::account] = toBase58(accountID);
283 }
284
285 return result;
286}
287
288} // 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
virtual TxQ & getTxQ()=0
A type that represents either a sequence value or a ticket value.
Definition: SeqProxy.h:56
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition: SeqProxy.h:76
std::vector< TxDetails > getAccountTxs(AccountID const &account) const
Returns information about the transactions currently in the queue for the account.
Definition: TxQ.cpp:1823
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
unsigned int UInt
Definition: json_forwards.h:27
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:315
void injectSLE(Json::Value &jv, SLE const &sle)
Inject JSON describing ledger entry.
Definition: RPCHelpers.cpp:673
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition: ErrorCodes.h:223
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:622
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:273
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:160
Keylet signers(AccountID const &account) noexcept
A SignerList.
Definition: Indexes.cpp:306
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
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
@ lsfRequireDestTag
@ lsfPasswordSpent
@ lsfDefaultRipple
@ lsfRequireAuth
@ lsfDisallowIncomingCheck
@ lsfAllowTrustLineClawback
@ lsfDisableMaster
@ lsfDepositAuth
@ lsfDisallowIncomingPayChan
@ lsfDisallowIncomingTrustline
@ lsfDisallowIncomingNFTokenOffer
@ lsfGlobalFreeze
@ lsfDisallowXRP
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
Json::Value doAccountInfo(RPC::JsonContext &context)
Definition: AccountInfo.cpp:51
unsigned int apiVersion
Definition: Context.h:50
Application & app
Definition: Context.h:42
Json::Value params
Definition: Context.h:64
T value(T... args)