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/RPCHelpers.h>
31 
32 namespace ripple {
33 namespace RPC {
34 
35 LedgerHandler::LedgerHandler(JsonContext& context) : context_(context)
36 {
37 }
38 
39 Status
41 {
42  auto const& params = context_.params;
43  bool needsLedger = params.isMember(jss::ledger) ||
44  params.isMember(jss::ledger_hash) ||
45  params.isMember(jss::ledger_index) || context_.app.config().reporting();
46  if (!needsLedger)
47  return Status::OK;
48 
49  if (auto s = lookupLedger(ledger_, context_, result_))
50  return s;
51 
52  bool const full = params[jss::full].asBool();
53  bool const transactions = params[jss::transactions].asBool();
54  bool const accounts = params[jss::accounts].asBool();
55  bool const expand = params[jss::expand].asBool();
56  bool const binary = params[jss::binary].asBool();
57  bool const owner_funds = params[jss::owner_funds].asBool();
58  bool const queue = params[jss::queue].asBool();
59  auto type = chooseLedgerEntryType(params);
60  if (type.first)
61  return type.first;
62  type_ = type.second;
63 
64  options_ = (full ? LedgerFill::full : 0) |
65  (expand ? LedgerFill::expand : 0) |
66  (transactions ? LedgerFill::dumpTxrp : 0) |
67  (accounts ? LedgerFill::dumpState : 0) |
68  (binary ? LedgerFill::binary : 0) |
69  (owner_funds ? LedgerFill::ownerFunds : 0) |
70  (queue ? LedgerFill::dumpQueue : 0);
71 
72  if (full || accounts)
73  {
74  // Until some sane way to get full ledgers has been implemented,
75  // disallow retrieving all state nodes.
77  return rpcNO_PERMISSION;
78 
81  {
82  return rpcTOO_BUSY;
83  }
86  }
87  if (queue)
88  {
89  if (!ledger_ || !ledger_->open())
90  {
91  // It doesn't make sense to request the queue
92  // with a non-existent or closed/validated ledger.
93  return rpcINVALID_PARAMS;
94  }
95 
97  }
98 
99  return Status::OK;
100 }
101 
102 } // namespace RPC
103 
106 {
107  auto begin = std::chrono::system_clock::now();
108  org::xrpl::rpc::v1::GetLedgerRequest& request = context.params;
109  org::xrpl::rpc::v1::GetLedgerResponse response;
110  grpc::Status status = grpc::Status::OK;
111 
113  if (auto status = RPC::ledgerFromRequest(ledger, context))
114  {
115  grpc::Status errorStatus;
116  if (status.toErrorCode() == rpcINVALID_PARAMS)
117  {
118  errorStatus = grpc::Status(
119  grpc::StatusCode::INVALID_ARGUMENT, status.message());
120  }
121  else
122  {
123  errorStatus =
124  grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
125  }
126  return {response, errorStatus};
127  }
128 
129  Serializer s;
130  addRaw(ledger->info(), s, true);
131 
132  response.set_ledger_header(s.peekData().data(), s.getLength());
133 
134  if (request.transactions())
135  {
136  for (auto& i : ledger->txs)
137  {
138  assert(i.first);
139  if (request.expand())
140  {
141  auto txn =
142  response.mutable_transactions_list()->add_transactions();
143  Serializer sTxn = i.first->getSerializer();
144  txn->set_transaction_blob(sTxn.data(), sTxn.getLength());
145  if (i.second)
146  {
147  Serializer sMeta = i.second->getSerializer();
148  txn->set_metadata_blob(sMeta.data(), sMeta.getLength());
149  }
150  }
151  else
152  {
153  auto const& hash = i.first->getTransactionID();
154  response.mutable_hashes_list()->add_hashes(
155  hash.data(), hash.size());
156  }
157  }
158  }
159 
160  if (request.get_objects())
161  {
163  context.app.getLedgerMaster().getLedgerBySeq(ledger->seq() - 1);
164 
166  std::dynamic_pointer_cast<Ledger const>(parent);
167  if (!base)
168  {
169  grpc::Status errorStatus{
170  grpc::StatusCode::NOT_FOUND, "parent ledger not validated"};
171  return {response, errorStatus};
172  }
173 
175  std::dynamic_pointer_cast<Ledger const>(ledger);
176  if (!desired)
177  {
178  grpc::Status errorStatus{
179  grpc::StatusCode::NOT_FOUND, "ledger not validated"};
180  return {response, errorStatus};
181  }
182  SHAMap::Delta differences;
183 
184  int maxDifferences = std::numeric_limits<int>::max();
185 
186  bool res = base->stateMap().compare(
187  desired->stateMap(), differences, maxDifferences);
188  if (!res)
189  {
190  grpc::Status errorStatus{
191  grpc::StatusCode::RESOURCE_EXHAUSTED,
192  "too many differences between specified ledgers"};
193  return {response, errorStatus};
194  }
195 
196  for (auto& [k, v] : differences)
197  {
198  auto obj = response.mutable_ledger_objects()->add_objects();
199  auto inBase = v.first;
200  auto inDesired = v.second;
201 
202  obj->set_key(k.data(), k.size());
203  if (inDesired)
204  {
205  assert(inDesired->size() > 0);
206  obj->set_data(inDesired->data(), inDesired->size());
207  }
208  if (inBase && inDesired)
209  obj->set_mod_type(
210  org::xrpl::rpc::v1::RawLedgerObject::MODIFIED);
211  else if (inBase && !inDesired)
212  obj->set_mod_type(org::xrpl::rpc::v1::RawLedgerObject::DELETED);
213  else
214  obj->set_mod_type(org::xrpl::rpc::v1::RawLedgerObject::CREATED);
215  auto const blob = inDesired ? inDesired->slice() : inBase->slice();
216  auto const objectType =
217  static_cast<LedgerEntryType>(blob[1] << 8 | blob[2]);
218 
219  if (request.get_object_neighbors())
220  {
221  if (!(inBase && inDesired))
222  {
223  auto lb = desired->stateMap().lower_bound(k);
224  auto ub = desired->stateMap().upper_bound(k);
225  if (lb != desired->stateMap().end())
226  obj->set_predecessor(
227  lb->key().data(), lb->key().size());
228  if (ub != desired->stateMap().end())
229  obj->set_successor(ub->key().data(), ub->key().size());
230  if (objectType == ltDIR_NODE)
231  {
232  auto sle = std::make_shared<SLE>(SerialIter{blob}, k);
233  if (!sle->isFieldPresent(sfOwner))
234  {
235  auto bookBase = keylet::quality({ltDIR_NODE, k}, 0);
236  if (!inBase && inDesired)
237  {
238  auto firstBook =
239  desired->stateMap().upper_bound(
240  bookBase.key);
241  if (firstBook != desired->stateMap().end() &&
242  firstBook->key() <
243  getQualityNext(bookBase.key) &&
244  firstBook->key() == k)
245  {
246  auto succ = response.add_book_successors();
247  succ->set_book_base(
248  bookBase.key.data(),
249  bookBase.key.size());
250  succ->set_first_book(
251  firstBook->key().data(),
252  firstBook->key().size());
253  }
254  }
255  if (inBase && !inDesired)
256  {
257  auto oldFirstBook =
258  base->stateMap().upper_bound(bookBase.key);
259  if (oldFirstBook != base->stateMap().end() &&
260  oldFirstBook->key() <
261  getQualityNext(bookBase.key) &&
262  oldFirstBook->key() == k)
263  {
264  auto succ = response.add_book_successors();
265  succ->set_book_base(
266  bookBase.key.data(),
267  bookBase.key.size());
268  auto newFirstBook =
269  desired->stateMap().upper_bound(
270  bookBase.key);
271 
272  if (newFirstBook !=
273  desired->stateMap().end() &&
274  newFirstBook->key() <
275  getQualityNext(bookBase.key))
276  {
277  succ->set_first_book(
278  newFirstBook->key().data(),
279  newFirstBook->key().size());
280  }
281  }
282  }
283  }
284  }
285  }
286  }
287  }
288  response.set_objects_included(true);
289  response.set_object_neighbors_included(request.get_object_neighbors());
290  response.set_skiplist_included(true);
291  }
292 
293  response.set_validated(
294  RPC::isValidated(context.ledgerMaster, *ledger, context.app));
295 
296  auto end = std::chrono::system_clock::now();
297  auto duration =
298  std::chrono::duration_cast<std::chrono::milliseconds>(end - begin)
299  .count() *
300  1.0;
301  JLOG(context.j.warn())
302  << __func__ << " - Extract time = " << duration
303  << " - num objects = " << response.ledger_objects().objects_size()
304  << " - num txns = " << response.transactions_list().transactions_size()
305  << " - ms per obj "
306  << duration / response.ledger_objects().objects_size()
307  << " - ms per txn "
308  << duration / response.transactions_list().transactions_size();
309 
310  return {response, status};
311 }
312 } // 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::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:162
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
ripple::TxQ::getTxs
std::vector< TxDetails > getTxs() const
Returns information about all transactions currently in the queue.
Definition: TxQ.cpp:1796
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:105
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:100
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:577
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:317
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:1814
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
Find the first item after the given item.
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:505
ripple::RPC::LedgerHandler::LedgerHandler
LedgerHandler(JsonContext &)
Definition: LedgerHandler.cpp:35
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:203
ripple::RPC::chooseLedgerEntryType
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:881
ripple::rpcNO_PERMISSION
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
ripple::SHAMap::end
const_iterator end() const
Definition: SHAMap.h:744
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:40
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:228
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
Find the object with the greatest object id smaller than the input id.
Definition: SHAMap.cpp:646
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:296
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:333
std::chrono::system_clock::now
T now(T... args)