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  allowClawbackFlag{"allowClawback", lsfAllowClawback};
101 
102  auto const sleAccepted = ledger->read(keylet::account(accountID));
103  if (sleAccepted)
104  {
105  auto const queue =
106  params.isMember(jss::queue) && params[jss::queue].asBool();
107 
108  if (queue && !ledger->open())
109  {
110  // It doesn't make sense to request the queue
111  // with any closed or validated ledger.
113  return result;
114  }
115 
116  Json::Value jvAccepted(Json::objectValue);
117  RPC::injectSLE(jvAccepted, *sleAccepted);
118  result[jss::account_data] = jvAccepted;
119 
120  Json::Value acctFlags{Json::objectValue};
121  for (auto const& lsf : lsFlags)
122  acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
123 
124  if (ledger->rules().enabled(featureDisallowIncoming))
125  {
126  for (auto const& lsf : disallowIncomingFlags)
127  acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
128  }
129 
130  if (ledger->rules().enabled(featureClawback))
131  acctFlags[allowClawbackFlag.first.data()] =
132  sleAccepted->isFlag(allowClawbackFlag.second);
133 
134  result[jss::account_flags] = std::move(acctFlags);
135 
136  // The document states that signer_lists is a bool, however
137  // assigning any string value works. Do not allow this.
138  // This check is for api Version 2 onwards only
139  if (!params[jss::signer_lists].isBool() && context.apiVersion > 1)
140  {
142  return result;
143  }
144 
145  // Return SignerList(s) if that is requested.
146  if (params.isMember(jss::signer_lists) &&
147  params[jss::signer_lists].asBool())
148  {
149  // We put the SignerList in an array because of an anticipated
150  // future when we support multiple signer lists on one account.
151  Json::Value jvSignerList = Json::arrayValue;
152 
153  // This code will need to be revisited if in the future we support
154  // multiple SignerLists on one account.
155  auto const sleSigners = ledger->read(keylet::signers(accountID));
156  if (sleSigners)
157  jvSignerList.append(sleSigners->getJson(JsonOptions::none));
158 
159  // Documentation states this is returned as part of the account_info
160  // response, but previously the code put it under account_data. We
161  // can move this to the documentated location from apiVersion 2
162  // onwards.
163  if (context.apiVersion == 1)
164  {
165  result[jss::account_data][jss::signer_lists] =
166  std::move(jvSignerList);
167  }
168  else
169  {
170  result[jss::signer_lists] = std::move(jvSignerList);
171  }
172  }
173  // Return queue info if that is requested
174  if (queue)
175  {
176  Json::Value jvQueueData = Json::objectValue;
177 
178  auto const txs = context.app.getTxQ().getAccountTxs(accountID);
179  if (!txs.empty())
180  {
181  jvQueueData[jss::txn_count] =
182  static_cast<Json::UInt>(txs.size());
183 
184  auto& jvQueueTx = jvQueueData[jss::transactions];
185  jvQueueTx = Json::arrayValue;
186 
187  std::uint32_t seqCount = 0;
188  std::uint32_t ticketCount = 0;
190  std::optional<std::uint32_t> highestSeq;
191  std::optional<std::uint32_t> lowestTicket;
192  std::optional<std::uint32_t> highestTicket;
193  bool anyAuthChanged = false;
194  XRPAmount totalSpend(0);
195 
196  // We expect txs to be returned sorted by SeqProxy. Verify
197  // that with a couple of asserts.
198  SeqProxy prevSeqProxy = SeqProxy::sequence(0);
199  for (auto const& tx : txs)
200  {
202 
203  if (tx.seqProxy.isSeq())
204  {
205  assert(prevSeqProxy < tx.seqProxy);
206  prevSeqProxy = tx.seqProxy;
207  jvTx[jss::seq] = tx.seqProxy.value();
208  ++seqCount;
209  if (!lowestSeq)
210  lowestSeq = tx.seqProxy.value();
211  highestSeq = tx.seqProxy.value();
212  }
213  else
214  {
215  assert(prevSeqProxy < tx.seqProxy);
216  prevSeqProxy = tx.seqProxy;
217  jvTx[jss::ticket] = tx.seqProxy.value();
218  ++ticketCount;
219  if (!lowestTicket)
220  lowestTicket = tx.seqProxy.value();
221  highestTicket = tx.seqProxy.value();
222  }
223 
224  jvTx[jss::fee_level] = to_string(tx.feeLevel);
225  if (tx.lastValid)
226  jvTx[jss::LastLedgerSequence] = *tx.lastValid;
227 
228  jvTx[jss::fee] = to_string(tx.consequences.fee());
229  auto const spend = tx.consequences.potentialSpend() +
230  tx.consequences.fee();
231  jvTx[jss::max_spend_drops] = to_string(spend);
232  totalSpend += spend;
233  bool const authChanged = tx.consequences.isBlocker();
234  if (authChanged)
235  anyAuthChanged = authChanged;
236  jvTx[jss::auth_change] = authChanged;
237 
238  jvQueueTx.append(std::move(jvTx));
239  }
240 
241  if (seqCount)
242  jvQueueData[jss::sequence_count] = seqCount;
243  if (ticketCount)
244  jvQueueData[jss::ticket_count] = ticketCount;
245  if (lowestSeq)
246  jvQueueData[jss::lowest_sequence] = *lowestSeq;
247  if (highestSeq)
248  jvQueueData[jss::highest_sequence] = *highestSeq;
249  if (lowestTicket)
250  jvQueueData[jss::lowest_ticket] = *lowestTicket;
251  if (highestTicket)
252  jvQueueData[jss::highest_ticket] = *highestTicket;
253 
254  jvQueueData[jss::auth_change_queued] = anyAuthChanged;
255  jvQueueData[jss::max_spend_drops_total] = to_string(totalSpend);
256  }
257  else
258  jvQueueData[jss::txn_count] = 0u;
259 
260  result[jss::queue_data] = std::move(jvQueueData);
261  }
262  }
263  else
264  {
265  result[jss::account] = toBase58(accountID);
267  }
268 
269  return result;
270 }
271 
272 } // 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:727
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::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:675
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::lsfAllowClawback
@ lsfAllowClawback
Definition: LedgerFormats.h:253
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