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/GRPCHelpers.h>
31 #include <ripple/rpc/impl/RPCHelpers.h>
32 #include <grpc/status.h>
33 
34 namespace ripple {
35 
36 // {
37 // account: <ident>,
38 // strict: <bool> // optional (default false)
39 // // if true only allow public keys and addresses.
40 // ledger_hash : <ledger>
41 // ledger_index : <ledger_index>
42 // signer_lists : <bool> // optional (default false)
43 // // if true return SignerList(s).
44 // queue : <bool> // optional (default false)
45 // // if true return information about transactions
46 // // in the current TxQ, only if the requested
47 // // ledger is open. Otherwise if true, returns an
48 // // error.
49 // }
50 
51 // TODO(tom): what is that "default"?
54 {
55  auto& params = context.params;
56 
57  std::string strIdent;
58  if (params.isMember(jss::account))
59  strIdent = params[jss::account].asString();
60  else if (params.isMember(jss::ident))
61  strIdent = params[jss::ident].asString();
62  else
63  return RPC::missing_field_error(jss::account);
64 
66  auto result = RPC::lookupLedger(ledger, context);
67 
68  if (!ledger)
69  return result;
70 
71  bool bStrict = params.isMember(jss::strict) && params[jss::strict].asBool();
72  AccountID accountID;
73 
74  // Get info on account.
75 
76  auto jvAccepted = RPC::accountFromString(accountID, strIdent, bStrict);
77 
78  if (jvAccepted)
79  return jvAccepted;
80 
81  auto const sleAccepted = ledger->read(keylet::account(accountID));
82  if (sleAccepted)
83  {
84  auto const queue =
85  params.isMember(jss::queue) && params[jss::queue].asBool();
86 
87  if (queue && !ledger->open())
88  {
89  // It doesn't make sense to request the queue
90  // with any closed or validated ledger.
92  return result;
93  }
94 
95  RPC::injectSLE(jvAccepted, *sleAccepted);
96  result[jss::account_data] = jvAccepted;
97 
98  // Return SignerList(s) if that is requested.
99  if (params.isMember(jss::signer_lists) &&
100  params[jss::signer_lists].asBool())
101  {
102  // We put the SignerList in an array because of an anticipated
103  // future when we support multiple signer lists on one account.
104  Json::Value jvSignerList = Json::arrayValue;
105 
106  // This code will need to be revisited if in the future we support
107  // multiple SignerLists on one account.
108  auto const sleSigners = ledger->read(keylet::signers(accountID));
109  if (sleSigners)
110  jvSignerList.append(sleSigners->getJson(JsonOptions::none));
111 
112  // Documentation states this is returned as part of the account_info
113  // response, but previously the code put it under account_data. We
114  // can move this to the documentated location from apiVersion 2
115  // onwards.
116  if (context.apiVersion == 1)
117  {
118  result[jss::account_data][jss::signer_lists] =
119  std::move(jvSignerList);
120  }
121  else
122  {
123  result[jss::signer_lists] = std::move(jvSignerList);
124  }
125  }
126  // Return queue info if that is requested
127  if (queue)
128  {
129  Json::Value jvQueueData = Json::objectValue;
130 
131  auto const txs =
132  context.app.getTxQ().getAccountTxs(accountID, *ledger);
133  if (!txs.empty())
134  {
135  jvQueueData[jss::txn_count] =
136  static_cast<Json::UInt>(txs.size());
137 
138  auto& jvQueueTx = jvQueueData[jss::transactions];
139  jvQueueTx = Json::arrayValue;
140 
141  std::uint32_t seqCount = 0;
142  std::uint32_t ticketCount = 0;
144  std::optional<std::uint32_t> highestSeq;
145  std::optional<std::uint32_t> lowestTicket;
146  std::optional<std::uint32_t> highestTicket;
147  bool anyAuthChanged = false;
148  XRPAmount totalSpend(0);
149 
150  // We expect txs to be returned sorted by SeqProxy. Verify
151  // that with a couple of asserts.
152  SeqProxy prevSeqProxy = SeqProxy::sequence(0);
153  for (auto const& tx : txs)
154  {
156 
157  if (tx.seqProxy.isSeq())
158  {
159  assert(prevSeqProxy < tx.seqProxy);
160  prevSeqProxy = tx.seqProxy;
161  jvTx[jss::seq] = tx.seqProxy.value();
162  ++seqCount;
163  if (!lowestSeq)
164  lowestSeq = tx.seqProxy.value();
165  highestSeq = tx.seqProxy.value();
166  }
167  else
168  {
169  assert(prevSeqProxy < tx.seqProxy);
170  prevSeqProxy = tx.seqProxy;
171  jvTx[jss::ticket] = tx.seqProxy.value();
172  ++ticketCount;
173  if (!lowestTicket)
174  lowestTicket = tx.seqProxy.value();
175  highestTicket = tx.seqProxy.value();
176  }
177 
178  jvTx[jss::fee_level] = to_string(tx.feeLevel);
179  if (tx.lastValid)
180  jvTx[jss::LastLedgerSequence] = *tx.lastValid;
181 
182  jvTx[jss::fee] = to_string(tx.consequences.fee());
183  auto const spend = tx.consequences.potentialSpend() +
184  tx.consequences.fee();
185  jvTx[jss::max_spend_drops] = to_string(spend);
186  totalSpend += spend;
187  bool const authChanged = tx.consequences.isBlocker();
188  if (authChanged)
189  anyAuthChanged = authChanged;
190  jvTx[jss::auth_change] = authChanged;
191 
192  jvQueueTx.append(std::move(jvTx));
193  }
194 
195  if (seqCount)
196  jvQueueData[jss::sequence_count] = seqCount;
197  if (ticketCount)
198  jvQueueData[jss::ticket_count] = ticketCount;
199  if (lowestSeq)
200  jvQueueData[jss::lowest_sequence] = *lowestSeq;
201  if (highestSeq)
202  jvQueueData[jss::highest_sequence] = *highestSeq;
203  if (lowestTicket)
204  jvQueueData[jss::lowest_ticket] = *lowestTicket;
205  if (highestTicket)
206  jvQueueData[jss::highest_ticket] = *highestTicket;
207 
208  jvQueueData[jss::auth_change_queued] = anyAuthChanged;
209  jvQueueData[jss::max_spend_drops_total] = to_string(totalSpend);
210  }
211  else
212  jvQueueData[jss::txn_count] = 0u;
213 
214  result[jss::queue_data] = std::move(jvQueueData);
215  }
216  }
217  else
218  {
219  result[jss::account] = context.app.accountIDCache().toBase58(accountID);
221  }
222 
223  return result;
224 }
225 
229 {
230  // Return values
231  org::xrpl::rpc::v1::GetAccountInfoResponse result;
232  grpc::Status status = grpc::Status::OK;
233 
234  // input
235  org::xrpl::rpc::v1::GetAccountInfoRequest& params = context.params;
236 
237  // get ledger
239  auto lgrStatus = RPC::ledgerFromRequest(ledger, context);
240  if (lgrStatus || !ledger)
241  {
242  grpc::Status errorStatus;
243  if (lgrStatus.toErrorCode() == rpcINVALID_PARAMS)
244  {
245  errorStatus = grpc::Status(
246  grpc::StatusCode::INVALID_ARGUMENT, lgrStatus.message());
247  }
248  else
249  {
250  errorStatus =
251  grpc::Status(grpc::StatusCode::NOT_FOUND, lgrStatus.message());
252  }
253  return {result, errorStatus};
254  }
255 
256  result.set_ledger_index(ledger->info().seq);
257  result.set_validated(
258  RPC::isValidated(context.ledgerMaster, *ledger, context.app));
259 
260  // decode account
261  AccountID accountID;
262  std::string strIdent = params.account().address();
263  error_code_i code =
264  RPC::accountFromStringWithCode(accountID, strIdent, params.strict());
265  if (code != rpcSUCCESS)
266  {
267  grpc::Status errorStatus{
268  grpc::StatusCode::INVALID_ARGUMENT, "invalid account"};
269  return {result, errorStatus};
270  }
271 
272  // get account data
273  auto const sleAccepted = ledger->read(keylet::account(accountID));
274  if (sleAccepted)
275  {
276  RPC::convert(*result.mutable_account_data(), *sleAccepted);
277 
278  // signer lists
279  if (params.signer_lists())
280  {
281  auto const sleSigners = ledger->read(keylet::signers(accountID));
282  if (sleSigners)
283  {
284  org::xrpl::rpc::v1::SignerList& signerListProto =
285  *result.mutable_signer_list();
286  RPC::convert(signerListProto, *sleSigners);
287  }
288  }
289 
290  // queued transactions
291  if (params.queue())
292  {
293  if (!ledger->open())
294  {
295  grpc::Status errorStatus{
296  grpc::StatusCode::INVALID_ARGUMENT,
297  "requested queue but ledger is not open"};
298  return {result, errorStatus};
299  }
300  std::vector<TxQ::TxDetails> const txs =
301  context.app.getTxQ().getAccountTxs(accountID, *ledger);
302  org::xrpl::rpc::v1::QueueData& queueData =
303  *result.mutable_queue_data();
304  RPC::convert(queueData, txs);
305  }
306  }
307  else
308  {
309  grpc::Status errorStatus{
310  grpc::StatusCode::NOT_FOUND, "account not found"};
311  return {result, errorStatus};
312  }
313 
314  return {result, status};
315 }
316 
317 } // namespace ripple
ripple::ReadView::info
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
ripple::RPC::JsonContext
Definition: Context.h:53
std::string
STL class.
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:53
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:592
std::pair
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
std::vector
STL class.
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
ripple::SeqProxy::sequence
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition: SeqProxy.h:76
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:92
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:540
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::Application::accountIDCache
virtual AccountIDCache const & accountIDCache() const =0
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:243
ripple::base_uint< 160, detail::AccountIDTag >
ripple::RPC::convert
void convert(org::xrpl::rpc::v1::TransactionResult &to, TER from)
Definition: GRPCHelpers.cpp:961
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::RPC::accountFromStringWithCode
error_code_i accountFromStringWithCode(AccountID &result, std::string const &strIdent, bool bStrict)
Decode account ID from string.
Definition: RPCHelpers.cpp:55
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:130
ripple::JsonOptions::none
@ none
ripple::RPC::GRPCContext
Definition: Context.h:70
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.
std::optional::value
T value(T... args)
ripple::RPC::GRPCContext::params
RequestType params
Definition: Context.h:72
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::RPC::isValidated
bool isValidated(LedgerMaster &ledgerMaster, ReadView const &ledger, Application &app)
Definition: RPCHelpers.cpp:468
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
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:38
ripple::TxQ::getAccountTxs
std::vector< TxDetails > getAccountTxs(AccountID const &account, ReadView const &view) const
Returns information about the transactions currently in the queue for the account.
Definition: TxQ.cpp:1759
ripple::keylet::signers
static Keylet signers(AccountID const &account, std::uint32_t page) noexcept
Definition: Indexes.cpp:265
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:193
ripple::RPC::ledgerFromRequest
Status ledgerFromRequest(T &ledger, GRPCContext< R > &context)
Definition: RPCHelpers.cpp:253
ripple::RPC::accountFromString
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
Definition: RPCHelpers.cpp:83
ripple::doAccountInfoGrpc
std::pair< org::xrpl::rpc::v1::GetAccountInfoResponse, grpc::Status > doAccountInfoGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetAccountInfoRequest > &context)
Definition: AccountInfo.cpp:227
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::AccountIDCache::toBase58
std::string toBase58(AccountID const &) const
Return ripple::toBase58 for the AccountID.
Definition: AccountID.cpp:134