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 states that signer_lists is a bool, however
138  // assigning any string value works. Do not allow this.
139  // This check is for api Version 2 onwards only
140  if (!params[jss::signer_lists].isBool() && context.apiVersion > 1)
141  {
143  return result;
144  }
145 
146  // Return SignerList(s) if that is requested.
147  if (params.isMember(jss::signer_lists) &&
148  params[jss::signer_lists].asBool())
149  {
150  // We put the SignerList in an array because of an anticipated
151  // future when we support multiple signer lists on one account.
152  Json::Value jvSignerList = Json::arrayValue;
153 
154  // This code will need to be revisited if in the future we support
155  // multiple SignerLists on one account.
156  auto const sleSigners = ledger->read(keylet::signers(accountID));
157  if (sleSigners)
158  jvSignerList.append(sleSigners->getJson(JsonOptions::none));
159 
160  // Documentation states this is returned as part of the account_info
161  // response, but previously the code put it under account_data. We
162  // can move this to the documentated location from apiVersion 2
163  // onwards.
164  if (context.apiVersion == 1)
165  {
166  result[jss::account_data][jss::signer_lists] =
167  std::move(jvSignerList);
168  }
169  else
170  {
171  result[jss::signer_lists] = std::move(jvSignerList);
172  }
173  }
174  // Return queue info if that is requested
175  if (queue)
176  {
177  Json::Value jvQueueData = Json::objectValue;
178 
179  auto const txs = context.app.getTxQ().getAccountTxs(accountID);
180  if (!txs.empty())
181  {
182  jvQueueData[jss::txn_count] =
183  static_cast<Json::UInt>(txs.size());
184 
185  auto& jvQueueTx = jvQueueData[jss::transactions];
186  jvQueueTx = Json::arrayValue;
187 
188  std::uint32_t seqCount = 0;
189  std::uint32_t ticketCount = 0;
191  std::optional<std::uint32_t> highestSeq;
192  std::optional<std::uint32_t> lowestTicket;
193  std::optional<std::uint32_t> highestTicket;
194  bool anyAuthChanged = false;
195  XRPAmount totalSpend(0);
196 
197  // We expect txs to be returned sorted by SeqProxy. Verify
198  // that with a couple of asserts.
199  SeqProxy prevSeqProxy = SeqProxy::sequence(0);
200  for (auto const& tx : txs)
201  {
203 
204  if (tx.seqProxy.isSeq())
205  {
206  assert(prevSeqProxy < tx.seqProxy);
207  prevSeqProxy = tx.seqProxy;
208  jvTx[jss::seq] = tx.seqProxy.value();
209  ++seqCount;
210  if (!lowestSeq)
211  lowestSeq = tx.seqProxy.value();
212  highestSeq = tx.seqProxy.value();
213  }
214  else
215  {
216  assert(prevSeqProxy < tx.seqProxy);
217  prevSeqProxy = tx.seqProxy;
218  jvTx[jss::ticket] = tx.seqProxy.value();
219  ++ticketCount;
220  if (!lowestTicket)
221  lowestTicket = tx.seqProxy.value();
222  highestTicket = tx.seqProxy.value();
223  }
224 
225  jvTx[jss::fee_level] = to_string(tx.feeLevel);
226  if (tx.lastValid)
227  jvTx[jss::LastLedgerSequence] = *tx.lastValid;
228 
229  jvTx[jss::fee] = to_string(tx.consequences.fee());
230  auto const spend = tx.consequences.potentialSpend() +
231  tx.consequences.fee();
232  jvTx[jss::max_spend_drops] = to_string(spend);
233  totalSpend += spend;
234  bool const authChanged = tx.consequences.isBlocker();
235  if (authChanged)
236  anyAuthChanged = authChanged;
237  jvTx[jss::auth_change] = authChanged;
238 
239  jvQueueTx.append(std::move(jvTx));
240  }
241 
242  if (seqCount)
243  jvQueueData[jss::sequence_count] = seqCount;
244  if (ticketCount)
245  jvQueueData[jss::ticket_count] = ticketCount;
246  if (lowestSeq)
247  jvQueueData[jss::lowest_sequence] = *lowestSeq;
248  if (highestSeq)
249  jvQueueData[jss::highest_sequence] = *highestSeq;
250  if (lowestTicket)
251  jvQueueData[jss::lowest_ticket] = *lowestTicket;
252  if (highestTicket)
253  jvQueueData[jss::highest_ticket] = *highestTicket;
254 
255  jvQueueData[jss::auth_change_queued] = anyAuthChanged;
256  jvQueueData[jss::max_spend_drops_total] = to_string(totalSpend);
257  }
258  else
259  jvQueueData[jss::txn_count] = 0u;
260 
261  result[jss::queue_data] = std::move(jvQueueData);
262  }
263  }
264  else
265  {
266  result[jss::account] = toBase58(accountID);
268  }
269 
270  return result;
271 }
272 
273 } // namespace ripple
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::lsfPasswordSpent
@ lsfPasswordSpent
Definition: LedgerFormats.h:229
ripple::lsfGlobalFreeze
@ lsfGlobalFreeze
Definition: LedgerFormats.h:237
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:235
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:728
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:253
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:676
ripple::lsfDepositAuth
@ lsfDepositAuth
Definition: LedgerFormats.h:240
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:264
ripple::lsfRequireAuth
@ lsfRequireAuth
Definition: LedgerFormats.h:232
ripple::lsfDefaultRipple
@ lsfDefaultRipple
Definition: LedgerFormats.h:238
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:134
ripple::featureDisallowIncoming
const uint256 featureDisallowIncoming
ripple::JsonOptions::none
@ none
ripple::lsfDisallowIncomingPayChan
@ lsfDisallowIncomingPayChan
Definition: LedgerFormats.h:248
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:230
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::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::lsfDisallowIncomingNFTokenOffer
@ lsfDisallowIncomingNFTokenOffer
Definition: LedgerFormats.h:244
ripple::ReadView::rules
virtual Rules const & rules() const =0
Returns the tx processing rules.
ripple::lsfNoFreeze
@ lsfNoFreeze
Definition: LedgerFormats.h:236
ripple::lsfDisallowIncomingTrustline
@ lsfDisallowIncomingTrustline
Definition: LedgerFormats.h:250
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:246
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:234
ripple::keylet::signers
static Keylet signers(AccountID const &account, std::uint32_t page) noexcept
Definition: Indexes.cpp:269
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