xrpld
Loading...
Searching...
No Matches
AccountInfo.cpp
1#include <xrpld/app/main/Application.h>
2#include <xrpld/app/misc/TxQ.h>
3#include <xrpld/rpc/Context.h>
4#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
5
6#include <xrpl/basics/Blob.h>
7#include <xrpl/basics/Slice.h>
8#include <xrpl/basics/strHex.h>
9#include <xrpl/beast/utility/instrumentation.h>
10#include <xrpl/json/json_forwards.h>
11#include <xrpl/json/json_value.h>
12#include <xrpl/ledger/ReadView.h>
13#include <xrpl/ledger/helpers/AccountRootHelpers.h>
14#include <xrpl/protocol/AccountID.h>
15#include <xrpl/protocol/ErrorCodes.h>
16#include <xrpl/protocol/Feature.h>
17#include <xrpl/protocol/Indexes.h>
18#include <xrpl/protocol/LedgerFormats.h>
19#include <xrpl/protocol/SField.h>
20#include <xrpl/protocol/Units.h>
21#include <xrpl/protocol/XRPAmount.h>
22#include <xrpl/protocol/jss.h>
23
24#include <boost/algorithm/string/case_conv.hpp>
25#include <boost/format/free_funcs.hpp>
26
27#include <array>
28#include <cstdint>
29#include <memory>
30#include <optional>
31#include <string>
32#include <string_view>
33#include <utility>
34
35namespace xrpl {
36
49void
50injectSLE(json::Value& jv, SLE const& sle)
51{
53 if (sle.getType() == ltACCOUNT_ROOT)
54 {
55 if (sle.isFieldPresent(sfEmailHash))
56 {
57 auto const& hash = sle.getFieldH128(sfEmailHash);
58 Blob const b(hash.begin(), hash.end());
60 boost::to_lower(md5);
61 // VFALCO TODO Give a name to this constant and move it
62 // to a more visible location.
63 jv[jss::urlgravatar] = str(boost::format("https://www.gravatar.com/avatar/%s") % md5);
64 }
65 }
66 else
67 {
68 jv[jss::Invalid] = true;
69 }
70}
71
72// {
73// account: <ident>,
74// ledger_hash : <ledger>
75// ledger_index : <ledger_index>
76// signer_lists : <bool> // optional (default false)
77// // if true return SignerList(s).
78// queue : <bool> // optional (default false)
79// // if true return information about transactions
80// // in the current TxQ, only if the requested
81// // ledger is open. Otherwise if true, returns an
82// // error.
83// }
84
85// TODO(tom): what is that "default"?
88{
89 auto& params = context.params;
90
91 std::string strIdent;
92 if (params.isMember(jss::account))
93 {
94 if (!params[jss::account].isString())
95 return RPC::invalidFieldError(jss::account);
96 strIdent = params[jss::account].asString();
97 }
98 else if (params.isMember(jss::ident))
99 {
100 if (!params[jss::ident].isString())
101 return RPC::invalidFieldError(jss::ident);
102 strIdent = params[jss::ident].asString();
103 }
104 else
105 {
106 return RPC::missingFieldError(jss::account);
107 }
108
110 auto result = RPC::lookupLedger(ledger, context);
111
112 if (!ledger)
113 return result;
114
115 // Get info on account.
116 auto id = parseBase58<AccountID>(strIdent);
117 if (!id)
118 {
120 return result;
121 }
122 auto const accountID{id.value()};
123
125 {{"defaultRipple", lsfDefaultRipple},
126 {"depositAuth", lsfDepositAuth},
127 {"disableMasterKey", lsfDisableMaster},
128 {"disallowIncomingXRP", lsfDisallowXRP},
129 {"globalFreeze", lsfGlobalFreeze},
130 {"noFreeze", lsfNoFreeze},
131 {"passwordSpent", lsfPasswordSpent},
132 {"requireAuthorization", lsfRequireAuth},
133 {"requireDestinationTag", lsfRequireDestTag}}};
134
136 kDisallowIncomingFlags{
137 {{"disallowIncomingNFTokenOffer", lsfDisallowIncomingNFTokenOffer},
138 {"disallowIncomingCheck", lsfDisallowIncomingCheck},
139 {"disallowIncomingPayChan", lsfDisallowIncomingPayChan},
140 {"disallowIncomingTrustline", lsfDisallowIncomingTrustline}}};
141
142 static constexpr std::pair<std::string_view, LedgerSpecificFlags> kAllowTrustLineClawbackFlag{
143 "allowTrustLineClawback", lsfAllowTrustLineClawback};
144
145 static constexpr std::pair<std::string_view, LedgerSpecificFlags> kAllowTrustLineLockingFlag{
146 "allowTrustLineLocking", lsfAllowTrustLineLocking};
147
148 auto const sleAccepted = ledger->read(keylet::account(accountID));
149 if (sleAccepted)
150 {
151 auto const queue = params.isMember(jss::queue) && params[jss::queue].asBool();
152
153 if (queue && !ledger->open())
154 {
155 // It doesn't make sense to request the queue
156 // with any closed or validated ledger.
158 return result;
159 }
160
162 injectSLE(jvAccepted, *sleAccepted);
163 result[jss::account_data] = jvAccepted;
164
166 for (auto const& lsf : kLsFlags)
167 acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
168
169 for (auto const& lsf : kDisallowIncomingFlags)
170 acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
171
172 acctFlags[kAllowTrustLineClawbackFlag.first.data()] =
173 sleAccepted->isFlag(kAllowTrustLineClawbackFlag.second);
174
175 if (ledger->rules().enabled(featureTokenEscrow))
176 {
177 acctFlags[kAllowTrustLineLockingFlag.first.data()] =
178 sleAccepted->isFlag(kAllowTrustLineLockingFlag.second);
179 }
180
181 result[jss::account_flags] = std::move(acctFlags);
182
183 auto const pseudoFields = getPseudoAccountFields();
184 for (auto const& pseudoField : pseudoFields)
185 {
186 if (sleAccepted->isFieldPresent(*pseudoField))
187 {
188 std::string name = pseudoField->fieldName;
189 if (name.ends_with("ID"))
190 {
191 // Remove the ID suffix from the field name.
192 name = name.substr(0, name.size() - 2);
193 XRPL_ASSERT_PARTS(!name.empty(), "xrpl::doAccountInfo", "name is not empty");
194 }
195 // ValidPseudoAccounts invariant guarantees that only one field
196 // can be set
197 result[jss::pseudo_account][jss::type] = name;
198 break;
199 }
200 }
201
202 // The document[https://xrpl.org/account_info.html#account_info] states
203 // that signer_lists is a bool, however assigning any string value
204 // works. Do not allow this. This check is for api Version 2 onwards
205 // only
206 if (context.apiVersion > 1u && params.isMember(jss::signer_lists) &&
207 !params[jss::signer_lists].isBool())
208 {
210 return result;
211 }
212
213 // Return SignerList(s) if that is requested.
214 if (params.isMember(jss::signer_lists) && params[jss::signer_lists].asBool())
215 {
216 // We put the SignerList in an array because of an anticipated
217 // future when we support multiple signer lists on one account.
218 json::Value jvSignerList = json::ValueType::Array;
219
220 // This code will need to be revisited if in the future we support
221 // multiple SignerLists on one account.
222 auto const sleSigners = ledger->read(keylet::signerList(accountID));
223 if (sleSigners)
224 jvSignerList.append(sleSigners->getJson(JsonOptions::Values::None));
225
226 // Documentation states this is returned as part of the account_info
227 // response, but previously the code put it under account_data. We
228 // can move this to the documented location from apiVersion 2
229 // onwards.
230 if (context.apiVersion == 1)
231 {
232 result[jss::account_data][jss::signer_lists] = std::move(jvSignerList);
233 }
234 else
235 {
236 result[jss::signer_lists] = std::move(jvSignerList);
237 }
238 }
239 // Return queue info if that is requested
240 if (queue)
241 {
243
244 auto const txs = context.app.getTxQ().getAccountTxs(accountID);
245 if (!txs.empty())
246 {
247 jvQueueData[jss::txn_count] = static_cast<json::UInt>(txs.size());
248
249 auto& jvQueueTx = jvQueueData[jss::transactions];
250 jvQueueTx = json::ValueType::Array;
251
252 std::uint32_t seqCount = 0;
253 std::uint32_t ticketCount = 0;
256 std::optional<std::uint32_t> lowestTicket;
257 std::optional<std::uint32_t> highestTicket;
258 bool anyAuthChanged = false;
259 XRPAmount totalSpend(0);
260
261 // We expect txs to be returned sorted by SeqProxy. Verify
262 // that with a couple of asserts.
263 SeqProxy prevSeqProxy = SeqProxy::sequence(0);
264 for (auto const& tx : txs)
265 {
267
268 if (tx.seqProxy.isSeq())
269 {
270 XRPL_ASSERT(
271 prevSeqProxy < tx.seqProxy, "doAccountInfo : first sorted proxy");
272 prevSeqProxy = tx.seqProxy;
273 jvTx[jss::seq] = tx.seqProxy.value();
274 ++seqCount;
275 if (!lowestSeq)
276 lowestSeq = tx.seqProxy.value();
277 highestSeq = tx.seqProxy.value();
278 }
279 else
280 {
281 XRPL_ASSERT(
282 prevSeqProxy < tx.seqProxy, "doAccountInfo : second sorted proxy");
283 prevSeqProxy = tx.seqProxy;
284 jvTx[jss::ticket] = tx.seqProxy.value();
285 ++ticketCount;
286 if (!lowestTicket)
287 lowestTicket = tx.seqProxy.value();
288 highestTicket = tx.seqProxy.value();
289 }
290
291 jvTx[jss::fee_level] = to_string(tx.feeLevel);
292 if (tx.lastValid)
293 jvTx[jss::LastLedgerSequence] = *tx.lastValid;
294
295 jvTx[jss::fee] = to_string(tx.consequences.fee());
296 auto const spend = tx.consequences.potentialSpend() + tx.consequences.fee();
297 jvTx[jss::max_spend_drops] = to_string(spend);
298 totalSpend += spend;
299 bool const authChanged = tx.consequences.isBlocker();
300 if (authChanged)
301 anyAuthChanged = authChanged;
302 jvTx[jss::auth_change] = authChanged;
303
304 jvQueueTx.append(std::move(jvTx));
305 }
306
307 if (seqCount != 0u)
308 jvQueueData[jss::sequence_count] = seqCount;
309 if (ticketCount != 0u)
310 jvQueueData[jss::ticket_count] = ticketCount;
311 if (lowestSeq)
312 jvQueueData[jss::lowest_sequence] = *lowestSeq;
313 if (highestSeq)
314 jvQueueData[jss::highest_sequence] = *highestSeq;
315 if (lowestTicket)
316 jvQueueData[jss::lowest_ticket] = *lowestTicket;
317 if (highestTicket)
318 jvQueueData[jss::highest_ticket] = *highestTicket;
319
320 jvQueueData[jss::auth_change_queued] = anyAuthChanged;
321 jvQueueData[jss::max_spend_drops_total] = to_string(totalSpend);
322 }
323 else
324 {
325 jvQueueData[jss::txn_count] = 0u;
326 }
327
328 result[jss::queue_data] = std::move(jvQueueData);
329 }
330 }
331 else
332 {
333 result[jss::account] = toBase58(accountID);
335 }
336
337 return result;
338}
339
340} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
Value & append(Value const &value)
Append value to array at the end.
LedgerEntryType getType() const
json::Value getJson(JsonOptions options=JsonOptions::Values::None) const override
uint128 getFieldH128(SField const &field) const
Definition STObject.cpp:603
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:454
A type that represents either a sequence value or a ticket value.
Definition SeqProxy.h:36
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition SeqProxy.h:56
virtual TxQ & getTxQ()=0
std::vector< TxDetails > getAccountTxs(AccountID const &account) const
Returns information about the transactions currently in the queue for the account.
Definition TxQ.cpp:1783
T empty(T... args)
T ends_with(T... args)
unsigned int UInt
@ Array
array value (ordered list)
Definition json_value.h:25
@ Object
object value (collection of name/value pairs).
Definition json_value.h:26
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.
void injectError(ErrorCodeI code, json::Value &json)
Add or update the json update to reflect the error code.
json::Value invalidFieldError(std::string const &name)
Definition ErrorCodes.h:273
json::Value missingFieldError(std::string const &name)
Definition ErrorCodes.h:231
Keylet signerList(AccountID const &account) noexcept
A SignerList.
Definition Indexes.cpp:316
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::vector< SField const * > const & getPseudoAccountFields()
Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if set.
@ RpcActNotFound
Definition ErrorCodes.h:52
@ RpcActMalformed
Definition ErrorCodes.h:72
@ RpcInvalidParams
Definition ErrorCodes.h:66
void injectSLE(json::Value &jv, SLE const &sle)
Injects JSON describing a ledger entry.
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:93
json::Value doAccountInfo(RPC::JsonContext &context)
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
STLedgerEntry SLE
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:10
std::enable_if_t< std::is_same_v< T, char >||std::is_same_v< T, unsigned char >, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:215
T size(T... args)
Application & app
Definition Context.h:21
unsigned int apiVersion
Definition Context.h:29
json::Value params
Definition Context.h:43
T substr(T... args)
T value(T... args)