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