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