rippled
LedgerEntry.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/basics/StringUtilities.h>
22 #include <ripple/basics/strHex.h>
23 #include <ripple/beast/core/LexicalCast.h>
24 #include <ripple/json/json_errors.h>
25 #include <ripple/ledger/ReadView.h>
26 #include <ripple/net/RPCErr.h>
27 #include <ripple/protocol/ErrorCodes.h>
28 #include <ripple/protocol/Indexes.h>
29 #include <ripple/protocol/STXChainBridge.h>
30 #include <ripple/protocol/jss.h>
31 #include <ripple/rpc/Context.h>
32 #include <ripple/rpc/GRPCHandlers.h>
33 #include <ripple/rpc/impl/RPCHelpers.h>
34 
35 namespace ripple {
36 
37 // {
38 // ledger_hash : <ledger>
39 // ledger_index : <ledger_index>
40 // ...
41 // }
44 {
46  auto jvResult = RPC::lookupLedger(lpLedger, context);
47 
48  if (!lpLedger)
49  return jvResult;
50 
51  uint256 uNodeIndex;
52  bool bNodeBinary = false;
53  LedgerEntryType expectedType = ltANY;
54 
55  try
56  {
57  if (context.params.isMember(jss::index))
58  {
59  if (!uNodeIndex.parseHex(context.params[jss::index].asString()))
60  {
61  uNodeIndex = beast::zero;
62  jvResult[jss::error] = "malformedRequest";
63  }
64  }
65  else if (context.params.isMember(jss::account_root))
66  {
67  expectedType = ltACCOUNT_ROOT;
68  auto const account = parseBase58<AccountID>(
69  context.params[jss::account_root].asString());
70  if (!account || account->isZero())
71  jvResult[jss::error] = "malformedAddress";
72  else
73  uNodeIndex = keylet::account(*account).key;
74  }
75  else if (context.params.isMember(jss::check))
76  {
77  expectedType = ltCHECK;
78  if (!uNodeIndex.parseHex(context.params[jss::check].asString()))
79  {
80  uNodeIndex = beast::zero;
81  jvResult[jss::error] = "malformedRequest";
82  }
83  }
84  else if (context.params.isMember(jss::deposit_preauth))
85  {
86  expectedType = ltDEPOSIT_PREAUTH;
87 
88  if (!context.params[jss::deposit_preauth].isObject())
89  {
90  if (!context.params[jss::deposit_preauth].isString() ||
91  !uNodeIndex.parseHex(
92  context.params[jss::deposit_preauth].asString()))
93  {
94  uNodeIndex = beast::zero;
95  jvResult[jss::error] = "malformedRequest";
96  }
97  }
98  else if (
99  !context.params[jss::deposit_preauth].isMember(jss::owner) ||
100  !context.params[jss::deposit_preauth][jss::owner].isString() ||
101  !context.params[jss::deposit_preauth].isMember(
102  jss::authorized) ||
103  !context.params[jss::deposit_preauth][jss::authorized]
104  .isString())
105  {
106  jvResult[jss::error] = "malformedRequest";
107  }
108  else
109  {
110  auto const owner = parseBase58<AccountID>(
111  context.params[jss::deposit_preauth][jss::owner]
112  .asString());
113 
114  auto const authorized = parseBase58<AccountID>(
115  context.params[jss::deposit_preauth][jss::authorized]
116  .asString());
117 
118  if (!owner)
119  jvResult[jss::error] = "malformedOwner";
120  else if (!authorized)
121  jvResult[jss::error] = "malformedAuthorized";
122  else
123  uNodeIndex =
125  }
126  }
127  else if (context.params.isMember(jss::directory))
128  {
129  expectedType = ltDIR_NODE;
130  if (context.params[jss::directory].isNull())
131  {
132  jvResult[jss::error] = "malformedRequest";
133  }
134  else if (!context.params[jss::directory].isObject())
135  {
136  if (!uNodeIndex.parseHex(
137  context.params[jss::directory].asString()))
138  {
139  uNodeIndex = beast::zero;
140  jvResult[jss::error] = "malformedRequest";
141  }
142  }
143  else if (
144  context.params[jss::directory].isMember(jss::sub_index) &&
145  !context.params[jss::directory][jss::sub_index].isIntegral())
146  {
147  jvResult[jss::error] = "malformedRequest";
148  }
149  else
150  {
151  std::uint64_t uSubIndex =
152  context.params[jss::directory].isMember(jss::sub_index)
153  ? context.params[jss::directory][jss::sub_index].asUInt()
154  : 0;
155 
156  if (context.params[jss::directory].isMember(jss::dir_root))
157  {
158  uint256 uDirRoot;
159 
160  if (context.params[jss::directory].isMember(jss::owner))
161  {
162  // May not specify both dir_root and owner.
163  jvResult[jss::error] = "malformedRequest";
164  }
165  else if (!uDirRoot.parseHex(
166  context.params[jss::directory][jss::dir_root]
167  .asString()))
168  {
169  uNodeIndex = beast::zero;
170  jvResult[jss::error] = "malformedRequest";
171  }
172  else
173  {
174  uNodeIndex = keylet::page(uDirRoot, uSubIndex).key;
175  }
176  }
177  else if (context.params[jss::directory].isMember(jss::owner))
178  {
179  auto const ownerID = parseBase58<AccountID>(
180  context.params[jss::directory][jss::owner].asString());
181 
182  if (!ownerID)
183  {
184  jvResult[jss::error] = "malformedAddress";
185  }
186  else
187  {
188  uNodeIndex =
189  keylet::page(keylet::ownerDir(*ownerID), uSubIndex)
190  .key;
191  }
192  }
193  else
194  {
195  jvResult[jss::error] = "malformedRequest";
196  }
197  }
198  }
199  else if (context.params.isMember(jss::escrow))
200  {
201  expectedType = ltESCROW;
202  if (!context.params[jss::escrow].isObject())
203  {
204  if (!uNodeIndex.parseHex(
205  context.params[jss::escrow].asString()))
206  {
207  uNodeIndex = beast::zero;
208  jvResult[jss::error] = "malformedRequest";
209  }
210  }
211  else if (
212  !context.params[jss::escrow].isMember(jss::owner) ||
213  !context.params[jss::escrow].isMember(jss::seq) ||
214  !context.params[jss::escrow][jss::seq].isIntegral())
215  {
216  jvResult[jss::error] = "malformedRequest";
217  }
218  else
219  {
220  auto const id = parseBase58<AccountID>(
221  context.params[jss::escrow][jss::owner].asString());
222  if (!id)
223  jvResult[jss::error] = "malformedOwner";
224  else
225  uNodeIndex =
227  *id, context.params[jss::escrow][jss::seq].asUInt())
228  .key;
229  }
230  }
231  else if (context.params.isMember(jss::offer))
232  {
233  expectedType = ltOFFER;
234  if (!context.params[jss::offer].isObject())
235  {
236  if (!uNodeIndex.parseHex(context.params[jss::offer].asString()))
237  {
238  uNodeIndex = beast::zero;
239  jvResult[jss::error] = "malformedRequest";
240  }
241  }
242  else if (
243  !context.params[jss::offer].isMember(jss::account) ||
244  !context.params[jss::offer].isMember(jss::seq) ||
245  !context.params[jss::offer][jss::seq].isIntegral())
246  {
247  jvResult[jss::error] = "malformedRequest";
248  }
249  else
250  {
251  auto const id = parseBase58<AccountID>(
252  context.params[jss::offer][jss::account].asString());
253  if (!id)
254  jvResult[jss::error] = "malformedAddress";
255  else
256  uNodeIndex =
258  *id, context.params[jss::offer][jss::seq].asUInt())
259  .key;
260  }
261  }
262  else if (context.params.isMember(jss::payment_channel))
263  {
264  expectedType = ltPAYCHAN;
265 
266  if (!uNodeIndex.parseHex(
267  context.params[jss::payment_channel].asString()))
268  {
269  uNodeIndex = beast::zero;
270  jvResult[jss::error] = "malformedRequest";
271  }
272  }
273  else if (context.params.isMember(jss::ripple_state))
274  {
275  expectedType = ltRIPPLE_STATE;
276  Currency uCurrency;
277  Json::Value jvRippleState = context.params[jss::ripple_state];
278 
279  if (!jvRippleState.isObject() ||
280  !jvRippleState.isMember(jss::currency) ||
281  !jvRippleState.isMember(jss::accounts) ||
282  !jvRippleState[jss::accounts].isArray() ||
283  2 != jvRippleState[jss::accounts].size() ||
284  !jvRippleState[jss::accounts][0u].isString() ||
285  !jvRippleState[jss::accounts][1u].isString() ||
286  (jvRippleState[jss::accounts][0u].asString() ==
287  jvRippleState[jss::accounts][1u].asString()))
288  {
289  jvResult[jss::error] = "malformedRequest";
290  }
291  else
292  {
293  auto const id1 = parseBase58<AccountID>(
294  jvRippleState[jss::accounts][0u].asString());
295  auto const id2 = parseBase58<AccountID>(
296  jvRippleState[jss::accounts][1u].asString());
297  if (!id1 || !id2)
298  {
299  jvResult[jss::error] = "malformedAddress";
300  }
301  else if (!to_currency(
302  uCurrency,
303  jvRippleState[jss::currency].asString()))
304  {
305  jvResult[jss::error] = "malformedCurrency";
306  }
307  else
308  {
309  uNodeIndex = keylet::line(*id1, *id2, uCurrency).key;
310  }
311  }
312  }
313  else if (context.params.isMember(jss::ticket))
314  {
315  expectedType = ltTICKET;
316  if (!context.params[jss::ticket].isObject())
317  {
318  if (!uNodeIndex.parseHex(
319  context.params[jss::ticket].asString()))
320  {
321  uNodeIndex = beast::zero;
322  jvResult[jss::error] = "malformedRequest";
323  }
324  }
325  else if (
326  !context.params[jss::ticket].isMember(jss::account) ||
327  !context.params[jss::ticket].isMember(jss::ticket_seq) ||
328  !context.params[jss::ticket][jss::ticket_seq].isIntegral())
329  {
330  jvResult[jss::error] = "malformedRequest";
331  }
332  else
333  {
334  auto const id = parseBase58<AccountID>(
335  context.params[jss::ticket][jss::account].asString());
336  if (!id)
337  jvResult[jss::error] = "malformedAddress";
338  else
339  uNodeIndex = getTicketIndex(
340  *id,
341  context.params[jss::ticket][jss::ticket_seq].asUInt());
342  }
343  }
344  else if (context.params.isMember(jss::nft_page))
345  {
346  expectedType = ltNFTOKEN_PAGE;
347 
348  if (context.params[jss::nft_page].isString())
349  {
350  if (!uNodeIndex.parseHex(
351  context.params[jss::nft_page].asString()))
352  {
353  uNodeIndex = beast::zero;
354  jvResult[jss::error] = "malformedRequest";
355  }
356  }
357  else
358  {
359  jvResult[jss::error] = "malformedRequest";
360  }
361  }
362  else if (context.params.isMember(jss::amm))
363  {
364  expectedType = ltAMM;
365  if (!context.params[jss::amm].isObject())
366  {
367  if (!uNodeIndex.parseHex(context.params[jss::amm].asString()))
368  {
369  uNodeIndex = beast::zero;
370  jvResult[jss::error] = "malformedRequest";
371  }
372  }
373  else if (
374  !context.params[jss::amm].isMember(jss::asset) ||
375  !context.params[jss::amm].isMember(jss::asset2))
376  {
377  jvResult[jss::error] = "malformedRequest";
378  }
379  else
380  {
381  try
382  {
383  auto const issue =
384  issueFromJson(context.params[jss::amm][jss::asset]);
385  auto const issue2 =
386  issueFromJson(context.params[jss::amm][jss::asset2]);
387  uNodeIndex = keylet::amm(issue, issue2).key;
388  }
389  catch (std::runtime_error const&)
390  {
391  jvResult[jss::error] = "malformedRequest";
392  }
393  }
394  }
395  else if (context.params.isMember(jss::bridge))
396  {
397  expectedType = ltBRIDGE;
398 
399  // return the keylet for the specified bridge or nullopt if the
400  // request is malformed
401  auto const maybeKeylet = [&]() -> std::optional<Keylet> {
402  try
403  {
404  if (!context.params.isMember(jss::bridge_account))
405  return std::nullopt;
406 
407  auto const& jsBridgeAccount =
408  context.params[jss::bridge_account];
409  if (!jsBridgeAccount.isString())
410  {
411  return std::nullopt;
412  }
413  auto const account =
414  parseBase58<AccountID>(jsBridgeAccount.asString());
415  if (!account || account->isZero())
416  {
417  return std::nullopt;
418  }
419 
420  // This may throw and is the reason for the `try` block. The
421  // try block has a larger scope so the `bridge` variable
422  // doesn't need to be an optional.
423  STXChainBridge const bridge(context.params[jss::bridge]);
424  STXChainBridge::ChainType const chainType =
426  account == bridge.lockingChainDoor());
427  if (account != bridge.door(chainType))
428  return std::nullopt;
429 
430  return keylet::bridge(bridge, chainType);
431  }
432  catch (...)
433  {
434  return std::nullopt;
435  }
436  }();
437 
438  if (maybeKeylet)
439  {
440  uNodeIndex = maybeKeylet->key;
441  }
442  else
443  {
444  uNodeIndex = beast::zero;
445  jvResult[jss::error] = "malformedRequest";
446  }
447  }
448  else if (context.params.isMember(jss::xchain_owned_claim_id))
449  {
450  expectedType = ltXCHAIN_OWNED_CLAIM_ID;
451  auto& claim_id = context.params[jss::xchain_owned_claim_id];
452  if (claim_id.isString())
453  {
454  // we accept a node id as specifier of a xchain claim id
455  if (!uNodeIndex.parseHex(claim_id.asString()))
456  {
457  uNodeIndex = beast::zero;
458  jvResult[jss::error] = "malformedRequest";
459  }
460  }
461  else if (
462  !claim_id.isObject() ||
463  !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) &&
464  claim_id[sfIssuingChainDoor.getJsonName()].isString()) ||
465  !(claim_id.isMember(sfLockingChainDoor.getJsonName()) &&
466  claim_id[sfLockingChainDoor.getJsonName()].isString()) ||
467  !claim_id.isMember(sfIssuingChainIssue.getJsonName()) ||
468  !claim_id.isMember(sfLockingChainIssue.getJsonName()) ||
469  !claim_id.isMember(jss::xchain_owned_claim_id))
470  {
471  jvResult[jss::error] = "malformedRequest";
472  }
473  else
474  {
475  // if not specified with a node id, a claim_id is specified by
476  // four strings defining the bridge (locking_chain_door,
477  // locking_chain_issue, issuing_chain_door, issuing_chain_issue)
478  // and the claim id sequence number.
479  auto lockingChainDoor = parseBase58<AccountID>(
480  claim_id[sfLockingChainDoor.getJsonName()].asString());
481  auto issuingChainDoor = parseBase58<AccountID>(
482  claim_id[sfIssuingChainDoor.getJsonName()].asString());
483  Issue lockingChainIssue, issuingChainIssue;
484  bool valid = lockingChainDoor && issuingChainDoor;
485  if (valid)
486  {
487  try
488  {
489  lockingChainIssue = issueFromJson(
490  claim_id[sfLockingChainIssue.getJsonName()]);
491  issuingChainIssue = issueFromJson(
492  claim_id[sfIssuingChainIssue.getJsonName()]);
493  }
494  catch (std::runtime_error const& ex)
495  {
496  valid = false;
497  jvResult[jss::error] = "malformedRequest";
498  }
499  }
500 
501  if (valid && claim_id[jss::xchain_owned_claim_id].isIntegral())
502  {
503  auto seq = claim_id[jss::xchain_owned_claim_id].asUInt();
504 
505  STXChainBridge bridge_spec(
506  *lockingChainDoor,
507  lockingChainIssue,
508  *issuingChainDoor,
509  issuingChainIssue);
510  Keylet keylet = keylet::xChainClaimID(bridge_spec, seq);
511  uNodeIndex = keylet.key;
512  }
513  }
514  }
515  else if (context.params.isMember(
516  jss::xchain_owned_create_account_claim_id))
517  {
518  // see object definition in LedgerFormats.cpp
520  auto& claim_id =
521  context.params[jss::xchain_owned_create_account_claim_id];
522  if (claim_id.isString())
523  {
524  // we accept a node id as specifier of a xchain create account
525  // claim_id
526  if (!uNodeIndex.parseHex(claim_id.asString()))
527  {
528  uNodeIndex = beast::zero;
529  jvResult[jss::error] = "malformedRequest";
530  }
531  }
532  else if (
533  !claim_id.isObject() ||
534  !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) &&
535  claim_id[sfIssuingChainDoor.getJsonName()].isString()) ||
536  !(claim_id.isMember(sfLockingChainDoor.getJsonName()) &&
537  claim_id[sfLockingChainDoor.getJsonName()].isString()) ||
538  !claim_id.isMember(sfIssuingChainIssue.getJsonName()) ||
539  !claim_id.isMember(sfLockingChainIssue.getJsonName()) ||
540  !claim_id.isMember(jss::xchain_owned_create_account_claim_id))
541  {
542  jvResult[jss::error] = "malformedRequest";
543  }
544  else
545  {
546  // if not specified with a node id, a create account claim_id is
547  // specified by four strings defining the bridge
548  // (locking_chain_door, locking_chain_issue, issuing_chain_door,
549  // issuing_chain_issue) and the create account claim id sequence
550  // number.
551  auto lockingChainDoor = parseBase58<AccountID>(
552  claim_id[sfLockingChainDoor.getJsonName()].asString());
553  auto issuingChainDoor = parseBase58<AccountID>(
554  claim_id[sfIssuingChainDoor.getJsonName()].asString());
555  Issue lockingChainIssue, issuingChainIssue;
556  bool valid = lockingChainDoor && issuingChainDoor;
557  if (valid)
558  {
559  try
560  {
561  lockingChainIssue = issueFromJson(
562  claim_id[sfLockingChainIssue.getJsonName()]);
563  issuingChainIssue = issueFromJson(
564  claim_id[sfIssuingChainIssue.getJsonName()]);
565  }
566  catch (std::runtime_error const& ex)
567  {
568  valid = false;
569  jvResult[jss::error] = "malformedRequest";
570  }
571  }
572 
573  if (valid &&
574  claim_id[jss::xchain_owned_create_account_claim_id]
575  .isIntegral())
576  {
577  auto seq =
578  claim_id[jss::xchain_owned_create_account_claim_id]
579  .asUInt();
580 
581  STXChainBridge bridge_spec(
582  *lockingChainDoor,
583  lockingChainIssue,
584  *issuingChainDoor,
585  issuingChainIssue);
586  Keylet keylet =
587  keylet::xChainCreateAccountClaimID(bridge_spec, seq);
588  uNodeIndex = keylet.key;
589  }
590  }
591  }
592  else if (context.params.isMember(jss::did))
593  {
594  expectedType = ltDID;
595  auto const account =
596  parseBase58<AccountID>(context.params[jss::did].asString());
597  if (!account || account->isZero())
598  jvResult[jss::error] = "malformedAddress";
599  else
600  uNodeIndex = keylet::did(*account).key;
601  }
602  else if (context.params.isMember(jss::oracle))
603  {
604  expectedType = ltORACLE;
605  if (!context.params[jss::oracle].isObject())
606  {
607  if (!uNodeIndex.parseHex(
608  context.params[jss::oracle].asString()))
609  {
610  uNodeIndex = beast::zero;
611  jvResult[jss::error] = "malformedRequest";
612  }
613  }
614  else if (
615  !context.params[jss::oracle].isMember(
616  jss::oracle_document_id) ||
617  !context.params[jss::oracle].isMember(jss::account))
618  {
619  jvResult[jss::error] = "malformedRequest";
620  }
621  else
622  {
623  uNodeIndex = beast::zero;
624  auto const& oracle = context.params[jss::oracle];
625  auto const documentID = [&]() -> std::optional<std::uint32_t> {
626  auto const& id = oracle[jss::oracle_document_id];
627  if (id.isConvertibleTo(Json::ValueType::uintValue))
628  return std::make_optional(id.asUInt());
629  else if (id.isString())
630  {
631  std::uint32_t v;
632  if (beast::lexicalCastChecked(v, id.asString()))
633  return std::make_optional(v);
634  }
635  return std::nullopt;
636  }();
637  auto const account =
638  parseBase58<AccountID>(oracle[jss::account].asString());
639  if (!account || account->isZero())
640  jvResult[jss::error] = "malformedAddress";
641  else if (!documentID)
642  jvResult[jss::error] = "malformedDocumentID";
643  else
644  uNodeIndex = keylet::oracle(*account, *documentID).key;
645  }
646  }
647  else
648  {
649  if (context.params.isMember("params") &&
650  context.params["params"].isArray() &&
651  context.params["params"].size() == 1 &&
652  context.params["params"][0u].isString())
653  {
654  if (!uNodeIndex.parseHex(
655  context.params["params"][0u].asString()))
656  {
657  uNodeIndex = beast::zero;
658  jvResult[jss::error] = "malformedRequest";
659  }
660  }
661  else
662  {
663  if (context.apiVersion < 2u)
664  jvResult[jss::error] = "unknownOption";
665  else
666  jvResult[jss::error] = "invalidParams";
667  }
668  }
669  }
670  catch (Json::error& e)
671  {
672  if (context.apiVersion > 1u)
673  {
674  // For apiVersion 2 onwards, any parsing failures that throw
675  // this
676  // exception return an invalidParam error.
677  uNodeIndex = beast::zero;
678  jvResult[jss::error] = "invalidParams";
679  }
680  else
681  throw;
682  }
683 
684  if (uNodeIndex.isNonZero())
685  {
686  auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex));
687  if (context.params.isMember(jss::binary))
688  bNodeBinary = context.params[jss::binary].asBool();
689 
690  if (!sleNode)
691  {
692  // Not found.
693  jvResult[jss::error] = "entryNotFound";
694  }
695  else if (
696  (expectedType != ltANY) && (expectedType != sleNode->getType()))
697  {
698  jvResult[jss::error] = "unexpectedLedgerType";
699  }
700  else if (bNodeBinary)
701  {
702  Serializer s;
703 
704  sleNode->add(s);
705 
706  jvResult[jss::node_binary] = strHex(s.peekData());
707  jvResult[jss::index] = to_string(uNodeIndex);
708  }
709  else
710  {
711  jvResult[jss::node] = sleNode->getJson(JsonOptions::none);
712  jvResult[jss::index] = to_string(uNodeIndex);
713  }
714  }
715 
716  return jvResult;
717 }
718 
722 {
723  org::xrpl::rpc::v1::GetLedgerEntryRequest& request = context.params;
724  org::xrpl::rpc::v1::GetLedgerEntryResponse response;
725  grpc::Status status = grpc::Status::OK;
726 
728  if (auto status = RPC::ledgerFromRequest(ledger, context))
729  {
730  grpc::Status errorStatus;
731  if (status.toErrorCode() == rpcINVALID_PARAMS)
732  {
733  errorStatus = grpc::Status(
734  grpc::StatusCode::INVALID_ARGUMENT, status.message());
735  }
736  else
737  {
738  errorStatus =
739  grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
740  }
741  return {response, errorStatus};
742  }
743 
744  auto key = uint256::fromVoidChecked(request.key());
745  if (!key)
746  {
747  grpc::Status errorStatus{
748  grpc::StatusCode::INVALID_ARGUMENT, "index malformed"};
749  return {response, errorStatus};
750  }
751 
752  auto const sleNode = ledger->read(keylet::unchecked(*key));
753  if (!sleNode)
754  {
755  grpc::Status errorStatus{
756  grpc::StatusCode::NOT_FOUND, "object not found"};
757  return {response, errorStatus};
758  }
759  else
760  {
761  Serializer s;
762  sleNode->add(s);
763 
764  auto& stateObject = *response.mutable_ledger_object();
765  stateObject.set_data(s.peekData().data(), s.getLength());
766  stateObject.set_key(request.key());
767  *(response.mutable_ledger()) = request.ledger();
768  return {response, status};
769  }
770 }
771 } // namespace ripple
Json::error
Definition: json_errors.h:27
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:313
ripple::to_currency
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::ltTICKET
@ ltTICKET
A ledger object which describes a ticket.
Definition: LedgerFormats.h:80
ripple::doLedgerEntry
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:43
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
ripple::Issue
A currency issued by an account.
Definition: Issue.h:35
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
ripple::STXChainBridge::srcChain
static ChainType srcChain(bool wasLockingChainSend)
Definition: STXChainBridge.h:219
std::shared_ptr
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::ltANY
@ ltANY
A special type, matching any ledger entry type.
Definition: LedgerFormats.h:212
ripple::ltORACLE
@ ltORACLE
A ledger object which tracks Oracle.
Definition: LedgerFormats.h:198
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:537
ripple::STXChainBridge::ChainType
ChainType
Definition: STXChainBridge.h:43
ripple::sfLockingChainDoor
const SF_ACCOUNT sfLockingChainDoor
std::pair
ripple::keylet::oracle
Keylet oracle(AccountID const &account, std::uint32_t const &documentID) noexcept
Definition: Indexes.cpp:449
ripple::keylet::amm
Keylet amm(Issue const &issue1, Issue const &issue2) noexcept
AMM entry.
Definition: Indexes.cpp:384
std::make_optional
T make_optional(T... args)
ripple::keylet::offer
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition: Indexes.cpp:232
ripple::keylet::did
Keylet did(AccountID const &account) noexcept
Definition: Indexes.cpp:443
ripple::keylet::xChainClaimID
Keylet xChainClaimID(STXChainBridge const &bridge, std::uint64_t seq)
Definition: Indexes.cpp:415
Json::Value::isNull
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:967
ripple::ltCHECK
@ ltCHECK
A ledger object which describes a check.
Definition: LedgerFormats.h:155
ripple::SField::getJsonName
Json::StaticString const & getJsonName() const
Definition: SField.h:216
ripple::base_uint< 256 >::fromVoidChecked
static std::optional< base_uint > fromVoidChecked(T const &from)
Definition: base_uint.h:319
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:623
ripple::getTicketIndex
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
Definition: Indexes.cpp:125
ripple::ltDIR_NODE
@ ltDIR_NODE
A ledger object which contains a list of object identifiers.
Definition: LedgerFormats.h:66
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::base_uint< 256 >
ripple::keylet::escrow
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Definition: Indexes.cpp:328
ripple::ltOFFER
@ ltOFFER
A ledger object which describes an offer on the DEX.
Definition: LedgerFormats.h:92
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:532
ripple::authorized
static bool authorized(Port const &port, std::map< std::string, std::string > const &h)
Definition: ServerHandler.cpp:84
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:143
ripple::sfLockingChainIssue
const SF_ISSUE sfLockingChainIssue
ripple::ltESCROW
@ ltESCROW
A ledger object describing a single escrow.
Definition: LedgerFormats.h:143
ripple::doLedgerEntryGrpc
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
Definition: LedgerEntry.cpp:720
ripple::ltDID
@ ltDID
The ledger object which tracks the DID.
Definition: LedgerFormats.h:193
ripple::keylet::bridge
Keylet bridge(STXChainBridge const &bridge, STXChainBridge::ChainType chainType)
Definition: Indexes.cpp:402
ripple::keylet::page
Keylet page(uint256 const &key, std::uint64_t index) noexcept
A page in a directory.
Definition: Indexes.cpp:319
ripple::RPC::GRPCContext
Definition: Context.h:70
ripple::ltDEPOSIT_PREAUTH
@ ltDEPOSIT_PREAUTH
A ledger object which describes a deposit preauthorization.
Definition: LedgerFormats.h:161
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
std::runtime_error
STL class.
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::uint64_t
ripple::issueFromJson
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
ripple::keylet::line
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:203
ripple::keylet::unchecked
Keylet unchecked(uint256 const &key) noexcept
Any ledger entry.
Definition: Indexes.cpp:307
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::STXChainBridge
Definition: STXChainBridge.h:33
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::Serializer
Definition: Serializer.h:40
ripple::RPC::GRPCContext::params
RequestType params
Definition: Context.h:72
ripple::ltNFTOKEN_PAGE
@ ltNFTOKEN_PAGE
A ledger object which contains a list of NFTs.
Definition: LedgerFormats.h:175
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::JsonOptions::none
@ none
Definition: STBase.h:42
ripple::ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID
@ ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID
A claim id for a cross chain create account transaction.
Definition: LedgerFormats.h:129
ripple::LedgerEntryType
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:53
ripple::ltBRIDGE
@ ltBRIDGE
The ledger object which lists details about sidechains.
Definition: LedgerFormats.h:99
beast::lexicalCastChecked
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Definition: LexicalCast.h:164
ripple::ltACCOUNT_ROOT
@ ltACCOUNT_ROOT
A ledger object which describes an account.
Definition: LedgerFormats.h:59
ripple::Serializer::peekData
Blob const & peekData() const
Definition: Serializer.h:169
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
Json::Value::isIntegral
bool isIntegral() const
Definition: json_value.cpp:991
ripple::RPC::Context::apiVersion
unsigned int apiVersion
Definition: Context.h:50
ripple::keylet::xChainCreateAccountClaimID
Keylet xChainCreateAccountClaimID(STXChainBridge const &bridge, std::uint64_t seq)
Definition: Indexes.cpp:429
ripple::ltXCHAIN_OWNED_CLAIM_ID
@ ltXCHAIN_OWNED_CLAIM_ID
A claim id for a cross chain transaction.
Definition: LedgerFormats.h:123
std::optional
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::sfIssuingChainDoor
const SF_ACCOUNT sfIssuingChainDoor
ripple::ltRIPPLE_STATE
@ ltRIPPLE_STATE
A ledger object which describes a bidirectional trust line.
Definition: LedgerFormats.h:74
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
ripple::Serializer::getLength
int getLength() const
Definition: Serializer.h:200
ripple::sfIssuingChainIssue
const SF_ISSUE sfIssuingChainIssue
ripple::keylet::depositPreauth
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition: Indexes.cpp:297
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:395
ripple::ltAMM
@ ltAMM
The ledger object which tracks the AMM.
Definition: LedgerFormats.h:187
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::ltPAYCHAN
@ ltPAYCHAN
A ledger object describing a single unidirectional XRP payment channel.
Definition: LedgerFormats.h:149
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469