rippled
LedgerHandler.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/ledger/LedgerToJson.h>
21 #include <ripple/app/main/Application.h>
22 #include <ripple/app/misc/LoadFeeTrack.h>
23 #include <ripple/json/Object.h>
24 #include <ripple/protocol/ErrorCodes.h>
25 #include <ripple/protocol/jss.h>
26 #include <ripple/resource/Fees.h>
27 #include <ripple/rpc/GRPCHandlers.h>
28 #include <ripple/rpc/Role.h>
29 #include <ripple/rpc/handlers/LedgerHandler.h>
30 #include <ripple/rpc/impl/GRPCHelpers.h>
31 #include <ripple/rpc/impl/RPCHelpers.h>
32 
33 namespace ripple {
34 namespace RPC {
35 
36 LedgerHandler::LedgerHandler(JsonContext& context) : context_(context)
37 {
38 }
39 
40 Status
42 {
43  auto const& params = context_.params;
44  bool needsLedger = params.isMember(jss::ledger) ||
45  params.isMember(jss::ledger_hash) ||
46  params.isMember(jss::ledger_index) || context_.app.config().reporting();
47  if (!needsLedger)
48  return Status::OK;
49 
50  if (auto s = lookupLedger(ledger_, context_, result_))
51  return s;
52 
53  bool const full = params[jss::full].asBool();
54  bool const transactions = params[jss::transactions].asBool();
55  bool const accounts = params[jss::accounts].asBool();
56  bool const expand = params[jss::expand].asBool();
57  bool const binary = params[jss::binary].asBool();
58  bool const owner_funds = params[jss::owner_funds].asBool();
59  bool const queue = params[jss::queue].asBool();
60  auto type = chooseLedgerEntryType(params);
61  if (type.first)
62  return type.first;
63  type_ = type.second;
64 
65  options_ = (full ? LedgerFill::full : 0) |
66  (expand ? LedgerFill::expand : 0) |
67  (transactions ? LedgerFill::dumpTxrp : 0) |
68  (accounts ? LedgerFill::dumpState : 0) |
69  (binary ? LedgerFill::binary : 0) |
70  (owner_funds ? LedgerFill::ownerFunds : 0) |
71  (queue ? LedgerFill::dumpQueue : 0);
72 
73  if (full || accounts)
74  {
75  // Until some sane way to get full ledgers has been implemented,
76  // disallow retrieving all state nodes.
78  return rpcNO_PERMISSION;
79 
82  {
83  return rpcTOO_BUSY;
84  }
87  }
88  if (queue)
89  {
90  if (!ledger_ || !ledger_->open())
91  {
92  // It doesn't make sense to request the queue
93  // with a non-existent or closed/validated ledger.
94  return rpcINVALID_PARAMS;
95  }
96 
98  }
99 
100  return Status::OK;
101 }
102 
103 } // namespace RPC
104 
107 {
108  auto begin = std::chrono::system_clock::now();
109  org::xrpl::rpc::v1::GetLedgerRequest& request = context.params;
110  org::xrpl::rpc::v1::GetLedgerResponse response;
111  grpc::Status status = grpc::Status::OK;
112 
114  if (auto status = RPC::ledgerFromRequest(ledger, context))
115  {
116  grpc::Status errorStatus;
117  if (status.toErrorCode() == rpcINVALID_PARAMS)
118  {
119  errorStatus = grpc::Status(
120  grpc::StatusCode::INVALID_ARGUMENT, status.message());
121  }
122  else
123  {
124  errorStatus =
125  grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
126  }
127  return {response, errorStatus};
128  }
129 
130  Serializer s;
131  addRaw(ledger->info(), s, true);
132 
133  response.set_ledger_header(s.peekData().data(), s.getLength());
134 
135  if (request.transactions())
136  {
137  for (auto& i : ledger->txs)
138  {
139  assert(i.first);
140  if (request.expand())
141  {
142  auto txn =
143  response.mutable_transactions_list()->add_transactions();
144  Serializer sTxn = i.first->getSerializer();
145  txn->set_transaction_blob(sTxn.data(), sTxn.getLength());
146  if (i.second)
147  {
148  Serializer sMeta = i.second->getSerializer();
149  txn->set_metadata_blob(sMeta.data(), sMeta.getLength());
150  }
151  }
152  else
153  {
154  auto const& hash = i.first->getTransactionID();
155  response.mutable_hashes_list()->add_hashes(
156  hash.data(), hash.size());
157  }
158  }
159  }
160 
161  if (request.get_objects())
162  {
164  context.app.getLedgerMaster().getLedgerBySeq(ledger->seq() - 1);
165 
167  std::dynamic_pointer_cast<Ledger const>(parent);
168  if (!base)
169  {
170  grpc::Status errorStatus{
171  grpc::StatusCode::NOT_FOUND, "parent ledger not validated"};
172  return {response, errorStatus};
173  }
174 
176  std::dynamic_pointer_cast<Ledger const>(ledger);
177  if (!desired)
178  {
179  grpc::Status errorStatus{
180  grpc::StatusCode::NOT_FOUND, "ledger not validated"};
181  return {response, errorStatus};
182  }
183  SHAMap::Delta differences;
184 
185  int maxDifferences = std::numeric_limits<int>::max();
186 
187  bool res = base->stateMap().compare(
188  desired->stateMap(), differences, maxDifferences);
189  if (!res)
190  {
191  grpc::Status errorStatus{
192  grpc::StatusCode::RESOURCE_EXHAUSTED,
193  "too many differences between specified ledgers"};
194  return {response, errorStatus};
195  }
196 
197  for (auto& [k, v] : differences)
198  {
199  auto obj = response.mutable_ledger_objects()->add_objects();
200  auto inBase = v.first;
201  auto inDesired = v.second;
202 
203  obj->set_key(k.data(), k.size());
204  if (inDesired)
205  {
206  assert(inDesired->size() > 0);
207  obj->set_data(inDesired->data(), inDesired->size());
208  }
209  if (inBase && inDesired)
210  obj->set_mod_type(
211  org::xrpl::rpc::v1::RawLedgerObject::MODIFIED);
212  else if (inBase && !inDesired)
213  obj->set_mod_type(org::xrpl::rpc::v1::RawLedgerObject::DELETED);
214  else
215  obj->set_mod_type(org::xrpl::rpc::v1::RawLedgerObject::CREATED);
216  auto const blob = inDesired ? inDesired->slice() : inBase->slice();
217  auto const objectType =
218  static_cast<LedgerEntryType>(blob[1] << 8 | blob[2]);
219 
220  if (request.get_object_neighbors())
221  {
222  if (!(inBase && inDesired))
223  {
224  auto lb = desired->stateMap().lower_bound(k);
225  auto ub = desired->stateMap().upper_bound(k);
226  if (lb != desired->stateMap().end())
227  obj->set_predecessor(
228  lb->key().data(), lb->key().size());
229  if (ub != desired->stateMap().end())
230  obj->set_successor(ub->key().data(), ub->key().size());
231  if (objectType == ltDIR_NODE)
232  {
233  auto sle = std::make_shared<SLE>(SerialIter{blob}, k);
234  if (!sle->isFieldPresent(sfOwner))
235  {
236  auto bookBase = keylet::quality({ltDIR_NODE, k}, 0);
237  if (!inBase && inDesired)
238  {
239  auto firstBook =
240  desired->stateMap().upper_bound(
241  bookBase.key);
242  if (firstBook != desired->stateMap().end() &&
243  firstBook->key() <
244  getQualityNext(bookBase.key) &&
245  firstBook->key() == k)
246  {
247  auto succ = response.add_book_successors();
248  succ->set_book_base(
249  bookBase.key.data(),
250  bookBase.key.size());
251  succ->set_first_book(
252  firstBook->key().data(),
253  firstBook->key().size());
254  }
255  }
256  if (inBase && !inDesired)
257  {
258  auto oldFirstBook =
259  base->stateMap().upper_bound(bookBase.key);
260  if (oldFirstBook != base->stateMap().end() &&
261  oldFirstBook->key() <
262  getQualityNext(bookBase.key) &&
263  oldFirstBook->key() == k)
264  {
265  auto succ = response.add_book_successors();
266  succ->set_book_base(
267  bookBase.key.data(),
268  bookBase.key.size());
269  auto newFirstBook =
270  desired->stateMap().upper_bound(
271  bookBase.key);
272 
273  if (newFirstBook !=
274  desired->stateMap().end() &&
275  newFirstBook->key() <
276  getQualityNext(bookBase.key))
277  {
278  succ->set_first_book(
279  newFirstBook->key().data(),
280  newFirstBook->key().size());
281  }
282  }
283  }
284  }
285  }
286  }
287  }
288  }
289  response.set_objects_included(true);
290  response.set_object_neighbors_included(request.get_object_neighbors());
291  response.set_skiplist_included(true);
292  }
293 
294  response.set_validated(
295  RPC::isValidated(context.ledgerMaster, *ledger, context.app));
296 
297  auto end = std::chrono::system_clock::now();
298  auto duration =
299  std::chrono::duration_cast<std::chrono::milliseconds>(end - begin)
300  .count() *
301  1.0;
302  JLOG(context.j.warn())
303  << __func__ << " - Extract time = " << duration
304  << " - num objects = " << response.ledger_objects().objects_size()
305  << " - num txns = " << response.transactions_list().transactions_size()
306  << " - ms per obj "
307  << duration / response.ledger_objects().objects_size()
308  << " - ms per txn "
309  << duration / response.transactions_list().transactions_size();
310 
311  return {response, status};
312 }
313 } // namespace ripple
ripple::ReadView::info
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
ripple::LedgerFill::dumpTxrp
@ dumpTxrp
Definition: LedgerToJson.h:46
ripple::RPC::Status::OK
static constexpr Code OK
Definition: Status.h:46
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::RPC::LedgerHandler::context_
JsonContext & context_
Definition: LedgerHandler.h:80
std::shared_ptr
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::TxQ::getTxs
std::vector< TxDetails > getTxs(ReadView const &view) const
Returns information about all transactions currently in the queue.
Definition: TxQ.cpp:1764
ripple::Resource::feeMediumBurdenRPC
const Charge feeMediumBurdenRPC
std::pair
ripple::sfOwner
const SF_ACCOUNT sfOwner
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s, bool includeHash)
Definition: View.cpp:164
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
ripple::RPC::LedgerHandler::ledger_
std::shared_ptr< ReadView const > ledger_
Definition: LedgerHandler.h:81
ripple::LedgerFill::dumpQueue
@ dumpQueue
Definition: LedgerToJson.h:52
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
ripple::doLedgerGrpc
std::pair< org::xrpl::rpc::v1::GetLedgerResponse, grpc::Status > doLedgerGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerRequest > &context)
Definition: LedgerHandler.cpp:106
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::rpcTOO_BUSY
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
ripple::getQualityNext
uint256 getQualityNext(uint256 const &uBase)
Definition: Indexes.cpp:97
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::LedgerFill::expand
@ expand
Definition: LedgerToJson.h:48
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:582
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::ltDIR_NODE
@ ltDIR_NODE
A ledger object which contains a list of object identifiers.
Definition: LedgerFormats.h:66
ripple::Serializer::data
void const * data() const noexcept
Definition: Serializer.h:75
ripple::RPC::Context::j
const beast::Journal j
Definition: Context.h:41
ripple::LoadFeeTrack::isLoadedLocal
bool isLoadedLocal() const
Definition: LoadFeeTrack.h:126
ripple::Config::reporting
bool reporting() const
Definition: Config.h:316
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::Application::config
virtual Config & config()=0
ripple::Ledger::stateMap
SHAMap const & stateMap() const
Definition: Ledger.h:307
ripple::LedgerFill::full
@ full
Definition: LedgerToJson.h:49
ripple::RPC::GRPCContext
Definition: Context.h:70
ripple::Application::getTxQ
virtual TxQ & getTxQ()=0
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::LedgerMaster::getLedgerBySeq
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
Definition: LedgerMaster.cpp:1776
ripple::SerialIter
Definition: Serializer.h:310
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::map
STL class.
ripple::RPC::Status
Status represents the results of an operation that might fail.
Definition: Status.h:39
ripple::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:124
ripple::Serializer
Definition: Serializer.h:39
ripple::LedgerFill::binary
@ binary
Definition: LedgerToJson.h:50
ripple::SHAMap::upper_bound
const_iterator upper_bound(uint256 const &id) const
Definition: SHAMap.cpp:609
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::LedgerFill::ownerFunds
@ ownerFunds
Definition: LedgerToJson.h:51
ripple::RPC::isValidated
bool isValidated(LedgerMaster &ledgerMaster, ReadView const &ledger, Application &app)
Definition: RPCHelpers.cpp:510
ripple::RPC::LedgerHandler::LedgerHandler
LedgerHandler(JsonContext &)
Definition: LedgerHandler.cpp:36
ripple::LedgerEntryType
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:53
ripple::ReadView::seq
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition: ReadView.h:260
ripple::RPC::chooseLedgerEntryType
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:882
ripple::rpcNO_PERMISSION
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
ripple::SHAMap::end
const_iterator end() const
Definition: SHAMap.h:738
ripple::RPC::LedgerHandler::type_
LedgerEntryType type_
Definition: LedgerHandler.h:85
ripple::Serializer::peekData
Blob const & peekData() const
Definition: Serializer.h:168
ripple::RPC::LedgerHandler::check
Status check()
Definition: LedgerHandler.cpp:41
ripple::SHAMap::compare
bool compare(SHAMap const &otherMap, Delta &differences, int maxCount) const
Definition: SHAMapDelta.cpp:128
ripple::keylet::quality
Keylet quality(Keylet const &k, std::uint64_t q) noexcept
The initial directory page for a specific quality.
Definition: Indexes.cpp:225
ripple::RPC::LedgerHandler::options_
int options_
Definition: LedgerHandler.h:84
ripple::RPC::LedgerHandler::queueTxs_
std::vector< TxQ::TxDetails > queueTxs_
Definition: LedgerHandler.h:82
ripple::SHAMap::lower_bound
const_iterator lower_bound(uint256 const &id) const
Definition: SHAMap.cpp:648
ripple::LedgerFill::dumpState
@ dumpState
Definition: LedgerToJson.h:47
std::numeric_limits::max
T max(T... args)
ripple::Serializer::getLength
int getLength() const
Definition: Serializer.h:199
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
std::vector::data
T data(T... args)
ripple::RPC::ledgerFromRequest
Status ledgerFromRequest(T &ledger, GRPCContext< R > &context)
Definition: RPCHelpers.cpp:295
ripple::Resource::feeHighBurdenRPC
const Charge feeHighBurdenRPC
ripple::RPC::LedgerHandler::result_
Json::Value result_
Definition: LedgerHandler.h:83
ripple::ReadView::txs
txs_type txs
Definition: ReadView.h:390
std::chrono::system_clock::now
T now(T... args)