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