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