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 = context.app.getTxQ().getAccountTxs(accountID);
132  if (!txs.empty())
133  {
134  jvQueueData[jss::txn_count] =
135  static_cast<Json::UInt>(txs.size());
136 
137  auto& jvQueueTx = jvQueueData[jss::transactions];
138  jvQueueTx = Json::arrayValue;
139 
140  std::uint32_t seqCount = 0;
141  std::uint32_t ticketCount = 0;
143  std::optional<std::uint32_t> highestSeq;
144  std::optional<std::uint32_t> lowestTicket;
145  std::optional<std::uint32_t> highestTicket;
146  bool anyAuthChanged = false;
147  XRPAmount totalSpend(0);
148 
149  // We expect txs to be returned sorted by SeqProxy. Verify
150  // that with a couple of asserts.
151  SeqProxy prevSeqProxy = SeqProxy::sequence(0);
152  for (auto const& tx : txs)
153  {
155 
156  if (tx.seqProxy.isSeq())
157  {
158  assert(prevSeqProxy < tx.seqProxy);
159  prevSeqProxy = tx.seqProxy;
160  jvTx[jss::seq] = tx.seqProxy.value();
161  ++seqCount;
162  if (!lowestSeq)
163  lowestSeq = tx.seqProxy.value();
164  highestSeq = tx.seqProxy.value();
165  }
166  else
167  {
168  assert(prevSeqProxy < tx.seqProxy);
169  prevSeqProxy = tx.seqProxy;
170  jvTx[jss::ticket] = tx.seqProxy.value();
171  ++ticketCount;
172  if (!lowestTicket)
173  lowestTicket = tx.seqProxy.value();
174  highestTicket = tx.seqProxy.value();
175  }
176 
177  jvTx[jss::fee_level] = to_string(tx.feeLevel);
178  if (tx.lastValid)
179  jvTx[jss::LastLedgerSequence] = *tx.lastValid;
180 
181  jvTx[jss::fee] = to_string(tx.consequences.fee());
182  auto const spend = tx.consequences.potentialSpend() +
183  tx.consequences.fee();
184  jvTx[jss::max_spend_drops] = to_string(spend);
185  totalSpend += spend;
186  bool const authChanged = tx.consequences.isBlocker();
187  if (authChanged)
188  anyAuthChanged = authChanged;
189  jvTx[jss::auth_change] = authChanged;
190 
191  jvQueueTx.append(std::move(jvTx));
192  }
193 
194  if (seqCount)
195  jvQueueData[jss::sequence_count] = seqCount;
196  if (ticketCount)
197  jvQueueData[jss::ticket_count] = ticketCount;
198  if (lowestSeq)
199  jvQueueData[jss::lowest_sequence] = *lowestSeq;
200  if (highestSeq)
201  jvQueueData[jss::highest_sequence] = *highestSeq;
202  if (lowestTicket)
203  jvQueueData[jss::lowest_ticket] = *lowestTicket;
204  if (highestTicket)
205  jvQueueData[jss::highest_ticket] = *highestTicket;
206 
207  jvQueueData[jss::auth_change_queued] = anyAuthChanged;
208  jvQueueData[jss::max_spend_drops_total] = to_string(totalSpend);
209  }
210  else
211  jvQueueData[jss::txn_count] = 0u;
212 
213  result[jss::queue_data] = std::move(jvQueueData);
214  }
215  }
216  else
217  {
218  result[jss::account] = toBase58(accountID);
220  }
221 
222  return result;
223 }
224 
228 {
229  // Return values
230  org::xrpl::rpc::v1::GetAccountInfoResponse result;
231  grpc::Status status = grpc::Status::OK;
232 
233  // input
234  org::xrpl::rpc::v1::GetAccountInfoRequest& params = context.params;
235 
236  // get ledger
238  auto lgrStatus = RPC::ledgerFromRequest(ledger, context);
239  if (lgrStatus || !ledger)
240  {
241  grpc::Status errorStatus;
242  if (lgrStatus.toErrorCode() == rpcINVALID_PARAMS)
243  {
244  errorStatus = grpc::Status(
245  grpc::StatusCode::INVALID_ARGUMENT, lgrStatus.message());
246  }
247  else
248  {
249  errorStatus =
250  grpc::Status(grpc::StatusCode::NOT_FOUND, lgrStatus.message());
251  }
252  return {result, errorStatus};
253  }
254 
255  result.set_ledger_index(ledger->info().seq);
256  result.set_validated(
257  RPC::isValidated(context.ledgerMaster, *ledger, context.app));
258 
259  // decode account
260  AccountID accountID;
261  std::string strIdent = params.account().address();
262  error_code_i code =
263  RPC::accountFromStringWithCode(accountID, strIdent, params.strict());
264  if (code != rpcSUCCESS)
265  {
266  grpc::Status errorStatus{
267  grpc::StatusCode::INVALID_ARGUMENT, "invalid account"};
268  return {result, errorStatus};
269  }
270 
271  // get account data
272  auto const sleAccepted = ledger->read(keylet::account(accountID));
273  if (sleAccepted)
274  {
275  RPC::convert(*result.mutable_account_data(), *sleAccepted);
276 
277  // signer lists
278  if (params.signer_lists())
279  {
280  auto const sleSigners = ledger->read(keylet::signers(accountID));
281  if (sleSigners)
282  {
283  org::xrpl::rpc::v1::SignerList& signerListProto =
284  *result.mutable_signer_list();
285  RPC::convert(signerListProto, *sleSigners);
286  }
287  }
288 
289  // queued transactions
290  if (params.queue())
291  {
292  if (!ledger->open())
293  {
294  grpc::Status errorStatus{
295  grpc::StatusCode::INVALID_ARGUMENT,
296  "requested queue but ledger is not open"};
297  return {result, errorStatus};
298  }
299  std::vector<TxQ::TxDetails> const txs =
300  context.app.getTxQ().getAccountTxs(accountID);
301  org::xrpl::rpc::v1::QueueData& queueData =
302  *result.mutable_queue_data();
303  RPC::convert(queueData, txs);
304  }
305  }
306  else
307  {
308  grpc::Status errorStatus{
309  grpc::StatusCode::NOT_FOUND, "account not found"};
310  return {result, errorStatus};
311  }
312 
313  return {result, status};
314 }
315 
316 } // 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:636
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::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::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:93
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:584
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:246
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:81
ripple::RPC::convert
void convert(org::xrpl::rpc::v1::TransactionResult &to, TER from)
Definition: GRPCHelpers.cpp:1108
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
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:1775
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:58
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
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:512
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:41
ripple::keylet::signers
static Keylet signers(AccountID const &account, std::uint32_t page) noexcept
Definition: Indexes.cpp:268
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:196
ripple::RPC::ledgerFromRequest
Status ledgerFromRequest(T &ledger, GRPCContext< R > &context)
Definition: RPCHelpers.cpp:297
ripple::RPC::accountFromString
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
Definition: RPCHelpers.cpp:86
ripple::doAccountInfoGrpc
std::pair< org::xrpl::rpc::v1::GetAccountInfoResponse, grpc::Status > doAccountInfoGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetAccountInfoRequest > &context)
Definition: AccountInfo.cpp:226
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::XRPAmount
Definition: XRPAmount.h:46