rippled
Loading...
Searching...
No Matches
LedgerEntry.cpp
1#include <xrpld/rpc/Context.h>
2#include <xrpld/rpc/GRPCHandlers.h>
3#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
4#include <xrpld/rpc/handlers/LedgerEntryHelpers.h>
5
6#include <xrpl/basics/StringUtilities.h>
7#include <xrpl/basics/strHex.h>
8#include <xrpl/beast/core/LexicalCast.h>
9#include <xrpl/json/json_errors.h>
10#include <xrpl/ledger/CredentialHelpers.h>
11#include <xrpl/ledger/ReadView.h>
12#include <xrpl/protocol/ErrorCodes.h>
13#include <xrpl/protocol/Indexes.h>
14#include <xrpl/protocol/LedgerFormats.h>
15#include <xrpl/protocol/RPCErr.h>
16#include <xrpl/protocol/STXChainBridge.h>
17#include <xrpl/protocol/jss.h>
18
19namespace xrpl {
20
22 Json::Value const&,
24 unsigned const apiVersion)>;
25
28 Keylet const& keylet,
29 Json::Value const& params,
30 Json::StaticString const& fieldName,
31 unsigned const apiVersion);
32
33// Helper function to return FunctionType for objects that have a fixed
34// location. That is, they don't take parameters to compute the index.
35// e.g. amendments, fees, negative UNL, etc.
36static FunctionType
37fixed(Keylet const& keylet)
38{
39 return [keylet](
40 Json::Value const& params,
41 Json::StaticString const fieldName,
42 unsigned const apiVersion) -> Expected<uint256, Json::Value> {
43 return parseFixed(keylet, params, fieldName, apiVersion);
44 };
45}
46
47static Expected<uint256, Json::Value>
49 Json::Value const& params,
50 Json::StaticString const fieldName,
51 std::string const& expectedType = "hex string or object")
52{
53 if (auto const uNodeIndex = LedgerEntryHelpers::parse<uint256>(params))
54 {
55 return *uNodeIndex;
56 }
58 "malformedRequest", fieldName, expectedType);
59}
60
61static Expected<uint256, Json::Value>
63 Json::Value const& params,
64 Json::StaticString const fieldName,
65 unsigned const apiVersion)
66{
67 if (apiVersion > 2u && params.isString())
68 {
69 std::string const index = params.asString();
70 if (index == jss::amendments.c_str())
71 return keylet::amendments().key;
72 if (index == jss::fee.c_str())
73 return keylet::fees().key;
74 if (index == jss::nunl)
75 return keylet::negativeUNL().key;
76 if (index == jss::hashes)
77 // Note this only finds the "short" skip list. Use "hashes":index to
78 // get the long list.
79 return keylet::skip().key;
80 }
81 return parseObjectID(params, fieldName, "hex string");
82}
83
84static Expected<uint256, Json::Value>
86 Json::Value const& params,
87 Json::StaticString const fieldName,
88 [[maybe_unused]] unsigned const apiVersion)
89{
90 if (auto const account = LedgerEntryHelpers::parse<AccountID>(params))
91 {
92 return keylet::account(*account).key;
93 }
94
96 "malformedAddress", fieldName, "AccountID");
97}
98
100
103 Json::Value const& params,
104 Json::StaticString const fieldName,
105 [[maybe_unused]] unsigned const apiVersion)
106{
107 if (!params.isObject())
108 {
109 return parseObjectID(params, fieldName);
110 }
111
112 if (auto const value =
113 LedgerEntryHelpers::hasRequired(params, {jss::asset, jss::asset2});
114 !value)
115 {
116 return Unexpected(value.error());
117 }
118
119 auto const asset = LedgerEntryHelpers::requiredIssue(
120 params, jss::asset, "malformedRequest");
121 if (!asset)
122 return Unexpected(asset.error());
123
124 auto const asset2 = LedgerEntryHelpers::requiredIssue(
125 params, jss::asset2, "malformedRequest");
126 if (!asset2)
127 return Unexpected(asset2.error());
128
129 return keylet::amm(*asset, *asset2).key;
130}
131
132static Expected<uint256, Json::Value>
134 Json::Value const& params,
135 Json::StaticString const fieldName,
136 [[maybe_unused]] unsigned const apiVersion)
137{
138 if (!params.isMember(jss::bridge))
139 {
141 }
142
143 if (params[jss::bridge].isString())
144 {
145 return parseObjectID(params, fieldName);
146 }
147
148 auto const bridge =
149 LedgerEntryHelpers::parseBridgeFields(params[jss::bridge]);
150 if (!bridge)
151 return Unexpected(bridge.error());
152
153 auto const account = LedgerEntryHelpers::requiredAccountID(
154 params, jss::bridge_account, "malformedBridgeAccount");
155 if (!account)
156 return Unexpected(account.error());
157
158 STXChainBridge::ChainType const chainType =
159 STXChainBridge::srcChain(account.value() == bridge->lockingChainDoor());
160 if (account.value() != bridge->door(chainType))
161 return LedgerEntryHelpers::malformedError("malformedRequest", "");
162
163 return keylet::bridge(*bridge, chainType).key;
164}
165
166static Expected<uint256, Json::Value>
168 Json::Value const& params,
169 Json::StaticString const fieldName,
170 [[maybe_unused]] unsigned const apiVersion)
171{
172 return parseObjectID(params, fieldName, "hex string");
173}
174
175static Expected<uint256, Json::Value>
177 Json::Value const& cred,
178 Json::StaticString const fieldName,
179 [[maybe_unused]] unsigned const apiVersion)
180{
181 if (!cred.isObject())
182 {
183 return parseObjectID(cred, fieldName);
184 }
185
186 auto const subject = LedgerEntryHelpers::requiredAccountID(
187 cred, jss::subject, "malformedRequest");
188 if (!subject)
189 return Unexpected(subject.error());
190
191 auto const issuer = LedgerEntryHelpers::requiredAccountID(
192 cred, jss::issuer, "malformedRequest");
193 if (!issuer)
194 return Unexpected(issuer.error());
195
196 auto const credType = LedgerEntryHelpers::requiredHexBlob(
197 cred,
198 jss::credential_type,
200 "malformedRequest");
201 if (!credType)
202 return Unexpected(credType.error());
203
204 return keylet::credential(
205 *subject, *issuer, Slice(credType->data(), credType->size()))
206 .key;
207}
208
209static Expected<uint256, Json::Value>
211 Json::Value const& params,
212 Json::StaticString const fieldName,
213 [[maybe_unused]] unsigned const apiVersion)
214{
215 if (!params.isObject())
216 {
217 return parseObjectID(params, fieldName);
218 }
219
220 auto const account = LedgerEntryHelpers::requiredAccountID(
221 params, jss::account, "malformedAddress");
222 if (!account)
223 return Unexpected(account.error());
224
225 auto const authorize = LedgerEntryHelpers::requiredAccountID(
226 params, jss::authorize, "malformedAddress");
227 if (!authorize)
228 return Unexpected(authorize.error());
229
230 return keylet::delegate(*account, *authorize).key;
231}
232
233static Expected<STArray, Json::Value>
235{
236 if (!jv.isArray())
237 {
239 "malformedAuthorizedCredentials",
240 jss::authorized_credentials,
241 "array");
242 }
243
244 std::uint32_t const n = jv.size();
246 {
248 "malformedAuthorizedCredentials",
249 "Invalid field '" + std::string(jss::authorized_credentials) +
250 "', array too long."));
251 }
252
253 if (n == 0)
254 {
256 "malformedAuthorizedCredentials",
257 "Invalid field '" + std::string(jss::authorized_credentials) +
258 "', array empty."));
259 }
260
261 STArray arr(sfAuthorizeCredentials, n);
262 for (auto const& jo : jv)
263 {
264 if (!jo.isObject())
265 {
267 "malformedAuthorizedCredentials",
268 jss::authorized_credentials,
269 "array");
270 }
271
272 if (auto const value = LedgerEntryHelpers::hasRequired(
273 jo,
274 {jss::issuer, jss::credential_type},
275 "malformedAuthorizedCredentials");
276 !value)
277 {
278 return Unexpected(value.error());
279 }
280
281 auto const issuer = LedgerEntryHelpers::requiredAccountID(
282 jo, jss::issuer, "malformedAuthorizedCredentials");
283 if (!issuer)
284 return Unexpected(issuer.error());
285
286 auto const credentialType = LedgerEntryHelpers::requiredHexBlob(
287 jo,
288 jss::credential_type,
290 "malformedAuthorizedCredentials");
291 if (!credentialType)
292 return Unexpected(credentialType.error());
293
294 auto credential = STObject::makeInnerObject(sfCredential);
295 credential.setAccountID(sfIssuer, *issuer);
296 credential.setFieldVL(sfCredentialType, *credentialType);
297 arr.push_back(std::move(credential));
298 }
299
300 return arr;
301}
302
303static Expected<uint256, Json::Value>
305 Json::Value const& dp,
306 Json::StaticString const fieldName,
307 [[maybe_unused]] unsigned const apiVersion)
308{
309 if (!dp.isObject())
310 {
311 return parseObjectID(dp, fieldName);
312 }
313
314 if ((dp.isMember(jss::authorized) ==
315 dp.isMember(jss::authorized_credentials)))
316 {
318 "malformedRequest",
319 "Must have exactly one of `authorized` and "
320 "`authorized_credentials`.");
321 }
322
323 auto const owner =
324 LedgerEntryHelpers::requiredAccountID(dp, jss::owner, "malformedOwner");
325 if (!owner)
326 {
327 return Unexpected(owner.error());
328 }
329
330 if (dp.isMember(jss::authorized))
331 {
332 if (auto const authorized =
333 LedgerEntryHelpers::parse<AccountID>(dp[jss::authorized]))
334 {
335 return keylet::depositPreauth(*owner, *authorized).key;
336 }
338 "malformedAuthorized", jss::authorized, "AccountID");
339 }
340
341 auto const& ac(dp[jss::authorized_credentials]);
342 auto const arr = parseAuthorizeCredentials(ac);
343 if (!arr.has_value())
344 return Unexpected(arr.error());
345
346 auto const& sorted = credentials::makeSorted(arr.value());
347 if (sorted.empty())
348 {
349 // TODO: this error message is bad/inaccurate
351 "malformedAuthorizedCredentials",
352 jss::authorized_credentials,
353 "array");
354 }
355
356 return keylet::depositPreauth(*owner, std::move(sorted)).key;
357}
358
359static Expected<uint256, Json::Value>
361 Json::Value const& params,
362 Json::StaticString const fieldName,
363 [[maybe_unused]] unsigned const apiVersion)
364{
365 auto const account = LedgerEntryHelpers::parse<AccountID>(params);
366 if (!account)
367 {
369 "malformedAddress", fieldName, "AccountID");
370 }
371
372 return keylet::did(*account).key;
373}
374
375static Expected<uint256, Json::Value>
377 Json::Value const& params,
378 Json::StaticString const fieldName,
379 [[maybe_unused]] unsigned const apiVersion)
380{
381 if (!params.isObject())
382 {
383 return parseObjectID(params, fieldName);
384 }
385
386 if (params.isMember(jss::sub_index) &&
387 (!params[jss::sub_index].isConvertibleTo(Json::uintValue) ||
388 params[jss::sub_index].isBool()))
389 {
391 "malformedRequest", jss::sub_index, "number");
392 }
393
394 if (params.isMember(jss::owner) == params.isMember(jss::dir_root))
395 {
397 "malformedRequest",
398 "Must have exactly one of `owner` and `dir_root` fields.");
399 }
400
401 std::uint64_t uSubIndex = params.get(jss::sub_index, 0).asUInt();
402
403 if (params.isMember(jss::dir_root))
404 {
405 if (auto const uDirRoot =
406 LedgerEntryHelpers::parse<uint256>(params[jss::dir_root]))
407 {
408 return keylet::page(*uDirRoot, uSubIndex).key;
409 }
410
412 "malformedDirRoot", jss::dir_root, "hash");
413 }
414
415 if (params.isMember(jss::owner))
416 {
417 auto const ownerID =
418 LedgerEntryHelpers::parse<AccountID>(params[jss::owner]);
419 if (!ownerID)
420 {
422 "malformedAddress", jss::owner, "AccountID");
423 }
424
425 return keylet::page(keylet::ownerDir(*ownerID), uSubIndex).key;
426 }
427
428 return LedgerEntryHelpers::malformedError("malformedRequest", "");
429}
430
431static Expected<uint256, Json::Value>
433 Json::Value const& params,
434 Json::StaticString const fieldName,
435 [[maybe_unused]] unsigned const apiVersion)
436{
437 if (!params.isObject())
438 {
439 return parseObjectID(params, fieldName);
440 }
441
443 params, jss::owner, "malformedOwner");
444 if (!id)
445 return Unexpected(id.error());
446 auto const seq =
447 LedgerEntryHelpers::requiredUInt32(params, jss::seq, "malformedSeq");
448 if (!seq)
449 return Unexpected(seq.error());
450
451 return keylet::escrow(*id, *seq).key;
452}
453
455
458 Keylet const& keylet,
459 Json::Value const& params,
460 Json::StaticString const& fieldName,
461 [[maybe_unused]] unsigned const apiVersion)
462{
463 if (!params.isBool())
464 {
465 return parseObjectID(params, fieldName, "hex string");
466 }
467 if (!params.asBool())
468 {
470 "invalidParams", fieldName, "true");
471 }
472
473 return keylet.key;
474}
475
476static Expected<uint256, Json::Value>
478 Json::Value const& params,
479 Json::StaticString const fieldName,
480 unsigned const apiVersion)
481{
482 if (params.isUInt() || params.isInt())
483 {
484 // If the index doesn't parse as a UInt, throw
485 auto const index = params.asUInt();
486
487 // Return the "long" skip list for the given ledger index.
488 auto const keylet = keylet::skip(index);
489 return keylet.key;
490 }
491 // Return the key in `params` or the "short" skip list, which contains
492 // hashes since the last flag ledger.
493 return parseFixed(keylet::skip(), params, fieldName, apiVersion);
494}
495
496static Expected<uint256, Json::Value>
498 Json::Value const& params,
499 Json::StaticString const fieldName,
500 [[maybe_unused]] unsigned const apiVersion)
501{
502 if (!params.isObject())
503 {
504 return parseObjectID(params, fieldName, "hex string");
505 }
506
508 params, jss::owner, "malformedOwner");
509 if (!id)
510 return Unexpected(id.error());
511 auto const seq =
512 LedgerEntryHelpers::requiredUInt32(params, jss::seq, "malformedSeq");
513 if (!seq)
514 return Unexpected(seq.error());
515
516 return keylet::loanbroker(*id, *seq).key;
517}
518
519static Expected<uint256, Json::Value>
521 Json::Value const& params,
522 Json::StaticString const fieldName,
523 [[maybe_unused]] unsigned const apiVersion)
524{
525 if (!params.isObject())
526 {
527 return parseObjectID(params, fieldName, "hex string");
528 }
529
531 params, jss::loan_broker_id, "malformedBroker");
532 if (!id)
533 return Unexpected(id.error());
534 auto const seq = LedgerEntryHelpers::requiredUInt32(
535 params, jss::loan_seq, "malformedSeq");
536 if (!seq)
537 return Unexpected(seq.error());
538
539 return keylet::loan(*id, *seq).key;
540}
541
542static Expected<uint256, Json::Value>
544 Json::Value const& params,
545 Json::StaticString const fieldName,
546 [[maybe_unused]] unsigned const apiVersion)
547{
548 if (!params.isObject())
549 {
550 return parseObjectID(params, fieldName);
551 }
552
553 auto const mptIssuanceID = LedgerEntryHelpers::requiredUInt192(
554 params, jss::mpt_issuance_id, "malformedMPTIssuanceID");
555 if (!mptIssuanceID)
556 return Unexpected(mptIssuanceID.error());
557
558 auto const account = LedgerEntryHelpers::requiredAccountID(
559 params, jss::account, "malformedAccount");
560 if (!account)
561 return Unexpected(account.error());
562
563 return keylet::mptoken(*mptIssuanceID, *account).key;
564}
565
566static Expected<uint256, Json::Value>
568 Json::Value const& params,
569 Json::StaticString const fieldName,
570 [[maybe_unused]] unsigned const apiVersion)
571{
572 auto const mptIssuanceID = LedgerEntryHelpers::parse<uint192>(params);
573 if (!mptIssuanceID)
575 "malformedMPTokenIssuance", fieldName, "Hash192");
576
577 return keylet::mptIssuance(*mptIssuanceID).key;
578}
579
580static Expected<uint256, Json::Value>
582 Json::Value const& params,
583 Json::StaticString const fieldName,
584 [[maybe_unused]] unsigned const apiVersion)
585{
586 return parseObjectID(params, fieldName, "hex string");
587}
588
589static Expected<uint256, Json::Value>
591 Json::Value const& params,
592 Json::StaticString const fieldName,
593 [[maybe_unused]] unsigned const apiVersion)
594{
595 return parseObjectID(params, fieldName, "hex string");
596}
597
599
602 Json::Value const& params,
603 Json::StaticString const fieldName,
604 [[maybe_unused]] unsigned const apiVersion)
605{
606 if (!params.isObject())
607 {
608 return parseObjectID(params, fieldName);
609 }
610
612 params, jss::account, "malformedAddress");
613 if (!id)
614 return Unexpected(id.error());
615
616 auto const seq = LedgerEntryHelpers::requiredUInt32(
617 params, jss::seq, "malformedRequest");
618 if (!seq)
619 return Unexpected(seq.error());
620
621 return keylet::offer(*id, *seq).key;
622}
623
624static Expected<uint256, Json::Value>
626 Json::Value const& params,
627 Json::StaticString const fieldName,
628 [[maybe_unused]] unsigned const apiVersion)
629{
630 if (!params.isObject())
631 {
632 return parseObjectID(params, fieldName);
633 }
634
636 params, jss::account, "malformedAccount");
637 if (!id)
638 return Unexpected(id.error());
639
640 auto const seq = LedgerEntryHelpers::requiredUInt32(
641 params, jss::oracle_document_id, "malformedDocumentID");
642 if (!seq)
643 return Unexpected(seq.error());
644
645 return keylet::oracle(*id, *seq).key;
646}
647
648static Expected<uint256, Json::Value>
650 Json::Value const& params,
651 Json::StaticString const fieldName,
652 [[maybe_unused]] unsigned const apiVersion)
653{
654 return parseObjectID(params, fieldName, "hex string");
655}
656
657static Expected<uint256, Json::Value>
659 Json::Value const& pd,
660 Json::StaticString const fieldName,
661 [[maybe_unused]] unsigned const apiVersion)
662{
663 if (pd.isString())
664 {
665 return parseObjectID(pd, fieldName);
666 }
667
668 if (!pd.isObject())
669 {
671 "malformedRequest", fieldName, "hex string or object");
672 }
673
674 auto const account = LedgerEntryHelpers::requiredAccountID(
675 pd, jss::account, "malformedAddress");
676 if (!account)
677 return Unexpected(account.error());
678
679 auto const seq =
680 LedgerEntryHelpers::requiredUInt32(pd, jss::seq, "malformedRequest");
681 if (!seq)
682 return Unexpected(seq.error());
683
684 return keylet::permissionedDomain(*account, pd[jss::seq].asUInt()).key;
685}
686
687static Expected<uint256, Json::Value>
689 Json::Value const& jvRippleState,
690 Json::StaticString const fieldName,
691 [[maybe_unused]] unsigned const apiVersion)
692{
693 Currency uCurrency;
694
695 if (!jvRippleState.isObject())
696 {
697 return parseObjectID(jvRippleState, fieldName);
698 }
699
700 if (auto const value = LedgerEntryHelpers::hasRequired(
701 jvRippleState, {jss::currency, jss::accounts});
702 !value)
703 {
704 return Unexpected(value.error());
705 }
706
707 if (!jvRippleState[jss::accounts].isArray() ||
708 jvRippleState[jss::accounts].size() != 2)
709 {
711 "malformedRequest", jss::accounts, "length-2 array of Accounts");
712 }
713
714 auto const id1 =
715 LedgerEntryHelpers::parse<AccountID>(jvRippleState[jss::accounts][0u]);
716 auto const id2 =
717 LedgerEntryHelpers::parse<AccountID>(jvRippleState[jss::accounts][1u]);
718 if (!id1 || !id2)
719 {
721 "malformedAddress", jss::accounts, "array of Accounts");
722 }
723 if (id1 == id2)
724 {
726 "malformedRequest", "Cannot have a trustline to self.");
727 }
728
729 if (!jvRippleState[jss::currency].isString() ||
730 jvRippleState[jss::currency] == "" ||
731 !to_currency(uCurrency, jvRippleState[jss::currency].asString()))
732 {
734 "malformedCurrency", jss::currency, "Currency");
735 }
736
737 return keylet::line(*id1, *id2, uCurrency).key;
738}
739
740static Expected<uint256, Json::Value>
742 Json::Value const& params,
743 Json::StaticString const fieldName,
744 [[maybe_unused]] unsigned const apiVersion)
745{
746 return parseObjectID(params, fieldName, "hex string");
747}
748
749static Expected<uint256, Json::Value>
751 Json::Value const& params,
752 Json::StaticString const fieldName,
753 [[maybe_unused]] unsigned const apiVersion)
754{
755 if (!params.isObject())
756 {
757 return parseObjectID(params, fieldName);
758 }
759
761 params, jss::account, "malformedAddress");
762 if (!id)
763 return Unexpected(id.error());
764
765 auto const seq = LedgerEntryHelpers::requiredUInt32(
766 params, jss::ticket_seq, "malformedRequest");
767 if (!seq)
768 return Unexpected(seq.error());
769
770 return getTicketIndex(*id, *seq);
771}
772
773static Expected<uint256, Json::Value>
775 Json::Value const& params,
776 Json::StaticString const fieldName,
777 [[maybe_unused]] unsigned const apiVersion)
778{
779 if (!params.isObject())
780 {
781 return parseObjectID(params, fieldName);
782 }
783
785 params, jss::owner, "malformedOwner");
786 if (!id)
787 return Unexpected(id.error());
788
789 auto const seq = LedgerEntryHelpers::requiredUInt32(
790 params, jss::seq, "malformedRequest");
791 if (!seq)
792 return Unexpected(seq.error());
793
794 return keylet::vault(*id, *seq).key;
795}
796
797static Expected<uint256, Json::Value>
799 Json::Value const& claim_id,
800 Json::StaticString const fieldName,
801 [[maybe_unused]] unsigned const apiVersion)
802{
803 if (!claim_id.isObject())
804 {
805 return parseObjectID(claim_id, fieldName);
806 }
807
808 auto const bridge_spec = LedgerEntryHelpers::parseBridgeFields(claim_id);
809 if (!bridge_spec)
810 return Unexpected(bridge_spec.error());
811
812 auto const seq = LedgerEntryHelpers::requiredUInt32(
813 claim_id, jss::xchain_owned_claim_id, "malformedXChainOwnedClaimID");
814 if (!seq)
815 {
816 return Unexpected(seq.error());
817 }
818
819 Keylet keylet = keylet::xChainClaimID(*bridge_spec, *seq);
820 return keylet.key;
821}
822
823static Expected<uint256, Json::Value>
825 Json::Value const& claim_id,
826 Json::StaticString const fieldName,
827 [[maybe_unused]] unsigned const apiVersion)
828{
829 if (!claim_id.isObject())
830 {
831 return parseObjectID(claim_id, fieldName);
832 }
833
834 auto const bridge_spec = LedgerEntryHelpers::parseBridgeFields(claim_id);
835 if (!bridge_spec)
836 return Unexpected(bridge_spec.error());
837
838 auto const seq = LedgerEntryHelpers::requiredUInt32(
839 claim_id,
840 jss::xchain_owned_create_account_claim_id,
841 "malformedXChainOwnedCreateAccountClaimID");
842 if (!seq)
843 {
844 return Unexpected(seq.error());
845 }
846
847 Keylet keylet = keylet::xChainCreateAccountClaimID(*bridge_spec, *seq);
848 return keylet.key;
849}
850
857
858// {
859// ledger_hash : <ledger>
860// ledger_index : <ledger_index>
861// ...
862// }
865{
866 static auto ledgerEntryParsers = std::to_array<LedgerEntry>({
867#pragma push_macro("LEDGER_ENTRY")
868#undef LEDGER_ENTRY
869
870#define LEDGER_ENTRY(tag, value, name, rpcName, fields) \
871 {jss::rpcName, parse##name, tag},
872
873#include <xrpl/protocol/detail/ledger_entries.macro>
874
875#undef LEDGER_ENTRY
876#pragma pop_macro("LEDGER_ENTRY")
877 {jss::index, parseIndex, ltANY},
878 // aliases
879 {jss::account_root, parseAccountRoot, ltACCOUNT_ROOT},
880 {jss::ripple_state, parseRippleState, ltRIPPLE_STATE},
881 });
882
883 auto const hasMoreThanOneMember = [&]() {
884 int count = 0;
885
886 for (auto const& ledgerEntry : ledgerEntryParsers)
887 {
888 if (context.params.isMember(ledgerEntry.fieldName))
889 {
890 count++;
891 if (count > 1) // Early exit if more than one is found
892 return true;
893 }
894 }
895 return false; // Return false if <= 1 is found
896 }();
897
898 if (hasMoreThanOneMember)
899 {
900 return RPC::make_param_error("Too many fields provided.");
901 }
902
904 auto jvResult = RPC::lookupLedger(lpLedger, context);
905
906 if (!lpLedger)
907 return jvResult;
908
909 uint256 uNodeIndex;
910 LedgerEntryType expectedType = ltANY;
911
912 try
913 {
914 bool found = false;
915 for (auto const& ledgerEntry : ledgerEntryParsers)
916 {
917 if (context.params.isMember(ledgerEntry.fieldName))
918 {
919 expectedType = ledgerEntry.expectedType;
920 // `Bridge` is the only type that involves two fields at the
921 // `ledger_entry` param level.
922 // So that parser needs to have the whole `params` field.
923 // All other parsers only need the one field name's info.
924 Json::Value const& params = ledgerEntry.fieldName == jss::bridge
925 ? context.params
926 : context.params[ledgerEntry.fieldName];
927 auto const result = ledgerEntry.parseFunction(
928 params, ledgerEntry.fieldName, context.apiVersion);
929 if (!result)
930 return result.error();
931
932 uNodeIndex = result.value();
933 found = true;
934 break;
935 }
936 }
937 if (!found)
938 {
939 if (context.apiVersion < 2u)
940 {
941 jvResult[jss::error] = "unknownOption";
942 return jvResult;
943 }
944 return RPC::make_param_error("No ledger_entry params provided.");
945 }
946 }
947 catch (Json::error& e)
948 {
949 if (context.apiVersion > 1u)
950 {
951 // For apiVersion 2 onwards, any parsing failures that throw
952 // this exception return an invalidParam error.
954 }
955 else
956 throw;
957 }
958
959 // Return the computed index regardless of whether the node exists.
960 jvResult[jss::index] = to_string(uNodeIndex);
961
962 if (uNodeIndex.isZero())
963 {
965 return jvResult;
966 }
967
968 auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex));
969
970 bool bNodeBinary = false;
971 if (context.params.isMember(jss::binary))
972 bNodeBinary = context.params[jss::binary].asBool();
973
974 if (!sleNode)
975 {
976 // Not found.
978 return jvResult;
979 }
980
981 if ((expectedType != ltANY) && (expectedType != sleNode->getType()))
982 {
984 return jvResult;
985 }
986
987 if (bNodeBinary)
988 {
989 Serializer s;
990
991 sleNode->add(s);
992
993 jvResult[jss::node_binary] = strHex(s.peekData());
994 }
995 else
996 {
997 jvResult[jss::node] = sleNode->getJson(JsonOptions::none);
998 }
999
1000 return jvResult;
1001}
1002
1006{
1007 org::xrpl::rpc::v1::GetLedgerEntryRequest& request = context.params;
1008 org::xrpl::rpc::v1::GetLedgerEntryResponse response;
1009 grpc::Status status = grpc::Status::OK;
1010
1012 if (auto status = RPC::ledgerFromRequest(ledger, context))
1013 {
1014 grpc::Status errorStatus;
1015 if (status.toErrorCode() == rpcINVALID_PARAMS)
1016 {
1017 errorStatus = grpc::Status(
1018 grpc::StatusCode::INVALID_ARGUMENT, status.message());
1019 }
1020 else
1021 {
1022 errorStatus =
1023 grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
1024 }
1025 return {response, errorStatus};
1026 }
1027
1028 auto const key = uint256::fromVoidChecked(request.key());
1029 if (!key)
1030 {
1031 grpc::Status errorStatus{
1032 grpc::StatusCode::INVALID_ARGUMENT, "index malformed"};
1033 return {response, errorStatus};
1034 }
1035
1036 auto const sleNode = ledger->read(keylet::unchecked(*key));
1037 if (!sleNode)
1038 {
1039 grpc::Status errorStatus{
1040 grpc::StatusCode::NOT_FOUND, "object not found"};
1041 return {response, errorStatus};
1042 }
1043
1044 Serializer s;
1045 sleNode->add(s);
1046
1047 auto& stateObject = *response.mutable_ledger_object();
1048 stateObject.set_data(s.peekData().data(), s.getLength());
1049 stateObject.set_key(request.key());
1050 *(response.mutable_ledger()) = request.ledger();
1051 return {response, status};
1052}
1053} // namespace xrpl
Lightweight wrapper to tag static string.
Definition json_value.h:45
Represents a JSON value.
Definition json_value.h:131
bool isArray() const
UInt size() const
Number of values in array or object.
bool isString() const
UInt asUInt() const
bool isObject() const
std::string asString() const
Returns the unquoted string value.
bool isBool() const
bool asBool() const
bool isUInt() const
bool isMember(char const *key) const
Return true if the object has a member named key.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
bool isConvertibleTo(ValueType other) const
bool isInt() const
void push_back(STObject const &object)
Definition STArray.h:193
static STObject makeInnerObject(SField const &name)
Definition STObject.cpp:76
static ChainType srcChain(bool wasLockingChainSend)
Blob const & peekData() const
Definition Serializer.h:183
int getLength() const
Definition Serializer.h:214
An immutable linear range of bytes.
Definition Slice.h:27
static std::optional< base_uint > fromVoidChecked(T const &from)
Definition base_uint.h:307
bool isZero() const
Definition base_uint.h:521
T data(T... args)
T is_same_v
@ uintValue
unsigned integer value
Definition json_value.h:22
Expected< std::uint32_t, Json::Value > requiredUInt32(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Expected< AccountID, Json::Value > requiredAccountID(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Unexpected< Json::Value > missingFieldError(Json::StaticString const field, std::optional< std::string > err=std::nullopt)
Expected< uint192, Json::Value > requiredUInt192(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Expected< bool, Json::Value > hasRequired(Json::Value const &params, std::initializer_list< Json::StaticString > fields, std::optional< std::string > err=std::nullopt)
Expected< Blob, Json::Value > requiredHexBlob(Json::Value const &params, Json::StaticString const fieldName, std::size_t maxLength, std::string const &err)
Expected< Issue, Json::Value > requiredIssue(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Expected< STXChainBridge, Json::Value > parseBridgeFields(Json::Value const &params)
Unexpected< Json::Value > malformedError(std::string const &err, std::string const &message)
Expected< uint256, Json::Value > requiredUInt256(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Unexpected< Json::Value > invalidFieldError(std::string const &err, Json::StaticString const field, std::string const &type)
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
Definition ErrorCodes.h:230
Status ledgerFromRequest(T &ledger, GRPCContext< R > const &context)
Retrieves a ledger from a gRPC request context.
void inject_error(error_code_i code, Json::Value &json)
Add or update the json update to reflect the error code.
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext const &context, Json::Value &result)
Looks up a ledger from a request and fills a Json::Value with ledger data.
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:178
Keylet oracle(AccountID const &account, std::uint32_t const &documentID) noexcept
Definition Indexes.cpp:502
Keylet const & negativeUNL() noexcept
The (fixed) index of the object containing the ledger negativeUNL.
Definition Indexes.cpp:212
Keylet did(AccountID const &account) noexcept
Definition Indexes.cpp:496
Keylet unchecked(uint256 const &key) noexcept
Any ledger entry.
Definition Indexes.cpp:350
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition Indexes.cpp:324
Keylet loanbroker(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:552
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Definition Indexes.cpp:371
Keylet bridge(STXChainBridge const &bridge, STXChainBridge::ChainType chainType)
Definition Indexes.cpp:455
Keylet const & amendments() noexcept
The index of the amendment table.
Definition Indexes.cpp:196
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:356
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:508
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Definition Indexes.cpp:428
Keylet loan(uint256 const &loanBrokerID, std::uint32_t loanSeq) noexcept
Definition Indexes.cpp:558
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition Indexes.cpp:256
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:546
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:226
Keylet xChainCreateAccountClaimID(STXChainBridge const &bridge, std::uint64_t seq)
Definition Indexes.cpp:482
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:522
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Definition Indexes.cpp:447
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:166
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition Indexes.cpp:204
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Definition Indexes.cpp:564
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Definition Indexes.cpp:362
Keylet credential(AccountID const &subject, AccountID const &issuer, Slice const &credType) noexcept
Definition Indexes.cpp:535
Keylet xChainClaimID(STXChainBridge const &bridge, std::uint64_t seq)
Definition Indexes.cpp:468
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
static Expected< uint256, Json::Value > parseDirectoryNode(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseMPToken(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parsePermissionedDomain(Json::Value const &pd, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseAMM(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
auto const parseFeeSettings
static Expected< uint256, Json::Value > parseSignerList(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
static Expected< uint256, Json::Value > parseOracle(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseCheck(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
uint256 getTicketIndex(AccountID const &account, std::uint32_t uSequence)
Definition Indexes.cpp:138
static Expected< uint256, Json::Value > parseIndex(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseDID(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseLoan(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseXChainOwnedClaimID(Json::Value const &claim_id, Json::StaticString const fieldName, unsigned const apiVersion)
static bool authorized(Port const &port, std::map< std::string, std::string > const &h)
static FunctionType fixed(Keylet const &keylet)
static Expected< uint256, Json::Value > parseDelegate(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
auto const parseAmendments
static Expected< uint256, Json::Value > parseFixed(Keylet const &keylet, Json::Value const &params, Json::StaticString const &fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseLedgerHashes(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseEscrow(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseTicket(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseCredential(Json::Value const &cred, Json::StaticString const fieldName, unsigned const apiVersion)
std::size_t constexpr maxCredentialsArraySize
The maximum number of credentials can be passed in array.
Definition Protocol.h:225
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
auto const parseNegativeUNL
static Expected< uint256, Json::Value > parsePayChannel(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseObjectID(Json::Value const &params, Json::StaticString const fieldName, std::string const &expectedType="hex string or object")
static Expected< uint256, Json::Value > parseRippleState(Json::Value const &jvRippleState, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseNFTokenPage(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< STArray, Json::Value > parseAuthorizeCredentials(Json::Value const &jv)
static Expected< uint256, Json::Value > parseOffer(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseMPTokenIssuance(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseBridge(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseDepositPreauth(Json::Value const &dp, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseVault(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
LedgerEntryType
Identifiers for on-ledger objects.
@ ltANY
A special type, matching any ledger entry type.
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition UintTypes.cpp:65
static Expected< uint256, Json::Value > parseNFTokenOffer(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseLoanBroker(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
static Expected< uint256, Json::Value > parseAccountRoot(Json::Value const &params, Json::StaticString const fieldName, unsigned const apiVersion)
@ rpcUNEXPECTED_LEDGER_TYPE
Definition ErrorCodes.h:143
@ rpcENTRY_NOT_FOUND
Definition ErrorCodes.h:142
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:65
static Expected< uint256, Json::Value > parseXChainOwnedCreateAccountClaimID(Json::Value const &claim_id, Json::StaticString const fieldName, unsigned const apiVersion)
std::size_t constexpr maxCredentialTypeLength
The maximum length of a CredentialType inside a Credential.
Definition Protocol.h:222
Json::Value doLedgerEntry(RPC::JsonContext &)
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:20
uint256 key
Definition Keylet.h:21
Json::StaticString fieldName
FunctionType parseFunction
LedgerEntryType expectedType
unsigned int apiVersion
Definition Context.h:30
RequestType params
Definition Context.h:52
Json::Value params
Definition Context.h:44