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