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