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