Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
LedgerEntry.hpp
1#pragma once
2
3#include "data/BackendInterface.hpp"
4#include "rpc/Errors.hpp"
5#include "rpc/JS.hpp"
6#include "rpc/common/Checkers.hpp"
7#include "rpc/common/MetaProcessors.hpp"
8#include "rpc/common/Modifiers.hpp"
9#include "rpc/common/Specs.hpp"
10#include "rpc/common/Types.hpp"
11#include "rpc/common/Validators.hpp"
12#include "util/AccountUtils.hpp"
13
14#include <boost/json/array.hpp>
15#include <boost/json/conversion.hpp>
16#include <boost/json/object.hpp>
17#include <boost/json/value.hpp>
18#include <boost/json/value_to.hpp>
19#include <xrpl/basics/base_uint.h>
20#include <xrpl/beast/core/LexicalCast.h>
21#include <xrpl/protocol/AccountID.h>
22#include <xrpl/protocol/ErrorCodes.h>
23#include <xrpl/protocol/Issue.h>
24#include <xrpl/protocol/LedgerFormats.h>
25#include <xrpl/protocol/SField.h>
26#include <xrpl/protocol/jss.h>
27#include <xrpl/protocol/tokens.h>
28
29#include <cstdint>
30#include <memory>
31#include <optional>
32#include <string>
33#include <string_view>
34#include <variant>
35
36namespace rpc {
37
45 std::shared_ptr<BackendInterface> sharedPtrBackend_;
46
47public:
51 struct Output {
52 std::string index;
53 uint32_t ledgerIndex;
54 std::string ledgerHash;
55 std::optional<boost::json::object> node;
56 std::optional<std::string> nodeBinary;
57 std::optional<uint32_t> deletedLedgerIndex;
58 bool validated = true;
59 };
60
64 struct Input {
65 std::optional<std::string> ledgerHash;
66 std::optional<uint32_t> ledgerIndex;
67 bool binary = false;
68 // id of this ledger entry: 256 bits hex string
69 std::optional<std::string> index;
70 // index can be extracted from payment_channel, check, escrow, offer
71 // etc, expectedType is used to save the type of index
72 ripple::LedgerEntryType expectedType = ripple::ltANY;
73 // account id to address account root object
74 std::optional<std::string> accountRoot;
75 // account id to address did object
76 std::optional<std::string> did;
77 // mpt issuance id to address mptIssuance object
78 std::optional<std::string> mptIssuance;
79 // TODO: extract into custom objects, remove json from Input
80 std::optional<boost::json::object> directory;
81 std::optional<boost::json::object> offer;
82 std::optional<boost::json::object> rippleStateAccount;
83 std::optional<boost::json::object> escrow;
84 std::optional<boost::json::object> depositPreauth;
85 std::optional<boost::json::object> ticket;
86 std::optional<boost::json::object> amm;
87 std::optional<boost::json::object> mptoken;
88 std::optional<boost::json::object> permissionedDomain;
89 std::optional<boost::json::object> vault;
90 std::optional<boost::json::object> loanBroker;
91 std::optional<boost::json::object> loan;
92 std::optional<ripple::STXChainBridge> bridge;
93 std::optional<std::string> bridgeAccount;
94 std::optional<uint32_t> chainClaimId;
95 std::optional<uint32_t> createAccountClaimId;
96 std::optional<ripple::uint256> oracleNode;
97 std::optional<ripple::uint256> credential;
98 std::optional<boost::json::object> delegate;
99 bool includeDeleted = false;
100 };
101
102 using Result = HandlerReturnType<Output>;
103
109 LedgerEntryHandler(std::shared_ptr<BackendInterface> sharedPtrBackend)
110 : sharedPtrBackend_(std::move(sharedPtrBackend))
111 {
112 }
113
120 static RpcSpecConstRef
121 spec([[maybe_unused]] uint32_t apiVersion)
122 {
123 // Validator only works in this handler
124 // The accounts array must have two different elements
125 // Each element must be a valid address
126 static auto const kRIPPLE_STATE_ACCOUNTS_CHECK = validation::CustomValidator{
127 [](boost::json::value const& value, std::string_view /* key */) -> MaybeError {
128 if (!value.is_array() || value.as_array().size() != 2 ||
129 !value.as_array()[0].is_string() || !value.as_array()[1].is_string() ||
130 value.as_array()[0].as_string() == value.as_array()[1].as_string()) {
131 return Error{Status{RippledError::rpcINVALID_PARAMS, "malformedAccounts"}};
132 }
133
135 boost::json::value_to<std::string>(value.as_array()[0])
136 );
138 boost::json::value_to<std::string>(value.as_array()[1])
139 );
140
141 if (!id1 || !id2)
142 return Error{Status{ClioError::RpcMalformedAddress, "malformedAddresses"}};
143
144 return MaybeError{};
145 }
146 };
147
148 static auto const kMALFORMED_REQUEST_HEX_STRING_VALIDATOR = meta::WithCustomError{
150 Status(ClioError::RpcMalformedRequest)
151 };
152
153 static auto const kMALFORMED_REQUEST_INT_VALIDATOR = meta::WithCustomError{
154 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
155 };
156
157 static auto const kBRIDGE_JSON_VALIDATOR = meta::WithCustomError{
159 {ripple::sfLockingChainDoor.getJsonName().c_str(),
162 {ripple::sfIssuingChainDoor.getJsonName().c_str(),
165 {ripple::sfLockingChainIssue.getJsonName().c_str(),
168 {ripple::sfIssuingChainIssue.getJsonName().c_str(),
171 }},
172 Status(ClioError::RpcMalformedRequest)
173 };
174
175 static auto const kRPC_SPEC = RpcSpec{
176 {JS(binary), validation::Type<bool>{}},
179 {JS(index), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
182 {JS(check), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
183 {JS(deposit_preauth),
185 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
188 {JS(owner),
192 Status(ClioError::RpcMalformedOwner)
193 }},
195 {JS(authorized_credentials),
197 },
198 }},
199 {JS(directory),
201 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
205 {JS(sub_index), kMALFORMED_REQUEST_INT_VALIDATOR}
206 }}},
207 {JS(escrow),
209 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
212 {JS(owner),
216 Status(ClioError::RpcMalformedOwner)
217 }},
218 {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
219 },
220 }},
221 {JS(offer),
223 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
226 {JS(account),
229 {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
230 },
231 }},
232 {JS(payment_channel), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
233 {JS(ripple_state),
236 {JS(accounts), validation::Required{}, kRIPPLE_STATE_ACCOUNTS_CHECK},
237 {JS(currency),
240 }},
241 {JS(ticket),
243 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
246 {JS(account),
249 {JS(ticket_seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
250 },
251 }},
252 {JS(nft_page), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
253 {JS(amm),
255 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
258 {JS(asset),
260 validation::Required{}, Status(ClioError::RpcMalformedRequest)
261 },
264 Status(ClioError::RpcMalformedRequest)
265 },
267 {JS(asset2),
269 validation::Required{}, Status(ClioError::RpcMalformedRequest)
270 },
273 Status(ClioError::RpcMalformedRequest)
274 },
276 },
277 }},
278 {JS(bridge),
280 validation::Type<boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
281 },
282 kBRIDGE_JSON_VALIDATOR},
283 {JS(bridge_account),
286 Status(ClioError::RpcMalformedRequest)
287 }},
288 {JS(xchain_owned_claim_id),
291 Status(ClioError::RpcMalformedRequest)
292 },
293 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
294 kBRIDGE_JSON_VALIDATOR,
297 {JS(xchain_owned_claim_id),
300 }},
301 Status(ClioError::RpcMalformedRequest)
302 }},
303 {JS(xchain_owned_create_account_claim_id),
306 Status(ClioError::RpcMalformedRequest)
307 },
308 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
309 kBRIDGE_JSON_VALIDATOR,
312 {JS(xchain_owned_create_account_claim_id),
315 }},
316 Status(ClioError::RpcMalformedRequest)
317 }},
318 {JS(oracle),
321 Status(ClioError::RpcMalformedRequest)
322 },
324 kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)
325 }},
327 {JS(account),
329 validation::Required{}, Status(ClioError::RpcMalformedRequest)
330 },
333 Status(ClioError::RpcMalformedAddress)
334 }},
335 // note: Unlike `rippled`, Clio only supports UInt as input, no string, no `null`,
336 // etc.:
337 {JS(oracle_document_id),
339 validation::Required{}, Status(ClioError::RpcMalformedRequest)
340 },
343 Status(ClioError::RpcMalformedOracleDocumentId)
344 },
346 modifiers::ToNumber{}, Status(ClioError::RpcMalformedOracleDocumentId)
347 }},
348 }}},
349 {JS(credential),
352 Status(ClioError::RpcMalformedRequest)
353 },
355 kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)
356 }},
358 {JS(subject),
360 validation::Required{}, Status(ClioError::RpcMalformedRequest)
361 },
364 Status(ClioError::RpcMalformedAddress)
365 }},
366 {JS(issuer),
368 validation::Required{}, Status(ClioError::RpcMalformedRequest)
369 },
372 Status(ClioError::RpcMalformedAddress)
373 }},
374 {
375 JS(credential_type),
377 validation::Required{}, Status(ClioError::RpcMalformedRequest)
378 },
380 validation::Type<std::string>{}, Status(ClioError::RpcMalformedRequest)
381 },
382 },
383 }}},
384 {JS(mpt_issuance),
387 Status(ClioError::RpcMalformedRequest)
388 }},
389 {JS(mptoken),
392 Status(ClioError::RpcMalformedRequest)
393 },
394 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
397 {
398 JS(account),
400 validation::Required{}, Status(ClioError::RpcMalformedRequest)
401 },
404 Status(ClioError::RpcMalformedAddress)
405 },
406 },
407 {
408 JS(mpt_issuance_id),
410 validation::Required{}, Status(ClioError::RpcMalformedRequest)
411 },
414 Status(ClioError::RpcMalformedRequest)
415 },
416 },
417 },
418 }},
419 {JS(permissioned_domain),
422 Status(ClioError::RpcMalformedRequest)
423 },
424 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
426 {JS(seq),
428 validation::Required{}, Status(ClioError::RpcMalformedRequest)
429 },
431 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
432 }},
433 {
434 JS(account),
436 validation::Required{}, Status(ClioError::RpcMalformedRequest)
437 },
440 Status(ClioError::RpcMalformedAddress)
441 },
442 },
443 }}},
444 {JS(vault),
447 Status(ClioError::RpcMalformedRequest)
448 },
449 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
451 {JS(seq),
453 validation::Required{}, Status(ClioError::RpcMalformedRequest)
454 },
456 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
457 }},
458 {
459 JS(owner),
461 validation::Required{}, Status(ClioError::RpcMalformedRequest)
462 },
465 Status(ClioError::RpcMalformedOwner)
466 },
467 },
468 }}},
469 {JS(loan_broker),
472 Status(ClioError::RpcMalformedRequest)
473 },
474 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
476 {JS(seq),
478 validation::Required{}, Status(ClioError::RpcMalformedRequest)
479 },
481 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
482 }},
483 {
484 JS(owner),
486 validation::Required{}, Status(ClioError::RpcMalformedRequest)
487 },
490 Status(ClioError::RpcMalformedOwner)
491 },
492 },
493 }}},
494 {JS(loan),
497 Status(ClioError::RpcMalformedRequest)
498 },
499 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
501 {JS(loan_seq),
503 validation::Required{}, Status(ClioError::RpcMalformedRequest)
504 },
506 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
507 }},
508 {
509 JS(loan_broker_id),
511 validation::Required{}, Status(ClioError::RpcMalformedRequest)
512 },
515 Status(ClioError::RpcMalformedRequest)
516 },
517 },
518 }}},
519 {JS(delegate),
522 Status(ClioError::RpcMalformedRequest)
523 },
524 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
526 {JS(account),
528 validation::Required{}, Status(ClioError::RpcMalformedRequest)
529 },
532 Status(ClioError::RpcMalformedAddress)
533 }},
534 {JS(authorize),
536 validation::Required{}, Status(ClioError::RpcMalformedRequest)
537 },
540 Status(ClioError::RpcMalformedAddress)
541 }}
542 }}},
543 {JS(amendments), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
544 {JS(fee), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
545 {JS(hashes), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
546 {JS(nft_offer), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
547 {JS(nunl), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
548 {JS(signer_list), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
549 {JS(ledger), check::Deprecated{}},
550 {"include_deleted", validation::Type<bool>{}},
551 };
552
553 return kRPC_SPEC;
554 }
555
563 Result
564 process(Input const& input, Context const& ctx) const;
565
566private:
567 // dir_root and owner can not be both empty or filled at the same time
568 // This function will return an error if this is the case
569 static std::expected<ripple::uint256, Status>
570 composeKeyFromDirectory(boost::json::object const& directory) noexcept;
571
578 friend void
579 tag_invoke(boost::json::value_from_tag, boost::json::value& jv, Output const& output);
580
587 friend Input
588 tag_invoke(boost::json::value_to_tag<Input>, boost::json::value const& jv);
589};
590
591} // namespace rpc
static RpcSpecConstRef spec(uint32_t apiVersion)
Returns the API specification for the command.
Definition LedgerEntry.hpp:121
LedgerEntryHandler(std::shared_ptr< BackendInterface > sharedPtrBackend)
Construct a new LedgerEntryHandler object.
Definition LedgerEntry.hpp:109
friend void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, Output const &output)
Convert the Output to a JSON object.
Definition LedgerEntry.cpp:308
Result process(Input const &input, Context const &ctx) const
Process the LedgerEntry command.
Definition LedgerEntry.cpp:43
Check for a deprecated fields.
Definition Checkers.hpp:44
A meta-processor that specifies a list of requirements to run against when the type matches the templ...
Definition MetaProcessors.hpp:85
A meta-processor that acts as a spec for a sub-object/section.
Definition MetaProcessors.hpp:24
A meta-processor that wraps a validator and produces a custom error in case the wrapped validator fai...
Definition MetaProcessors.hpp:152
A meta-validator that allows to specify a custom validation function.
Definition Validators.hpp:423
This namespace contains all the RPC logic and handlers.
Definition AMMHelpers.cpp:18
RpcSpec const & RpcSpecConstRef
An alias for a const reference to RpcSpec.
Definition Specs.hpp:130
std::expected< OutputType, Status > HandlerReturnType
Return type for each individual handler.
Definition Types.hpp:62
std::expected< void, Status > MaybeError
Return type used for Validators that can return error but don't have specific value to return.
Definition Types.hpp:36
std::unexpected< Status > Error
The type that represents just the error part of MaybeError.
Definition Types.hpp:56
std::optional< T > parseBase58Wrapper(std::string const &str)
A wrapper of parseBase58 function. It adds the check if all characters in the input string are alphan...
Definition AccountUtils.hpp:24
Context of an RPC call.
Definition Types.hpp:99
A struct to hold the input data for the command.
Definition LedgerEntry.hpp:64
A struct to hold the output data of the command.
Definition LedgerEntry.hpp:51
Result type used to return responses or error statuses to the Webserver subsystem.
Definition Types.hpp:110
Represents a Specification of an entire RPC command.
Definition Specs.hpp:82
A status returned from any RPC handler.
Definition Errors.hpp:65
Convert input string to integer.
Definition Modifiers.hpp:94
static CustomValidator currencyValidator
Provides a commonly used validator for currency, including standard currency code and token code.
Definition Validators.hpp:557
static CustomValidator ledgerIndexValidator
Provides a commonly used validator for ledger index.
Definition Validators.hpp:489
static CustomValidator currencyIssueValidator
Validates an asset (ripple::Issue).
Definition Validators.hpp:581
static CustomValidator authorizeCredentialValidator
Provides a validator for validating authorized_credentials json array.
Definition Validators.hpp:588
static CustomValidator uint192HexStringValidator
Provides a commonly used validator for uint192 hex string.
Definition Validators.hpp:543
static CustomValidator uint256HexStringValidator
Provides a commonly used validator for uint256 hex string.
Definition Validators.hpp:551
static CustomValidator accountBase58Validator
Provides a commonly used validator for accounts.
Definition Validators.hpp:511
A validator that simply requires a field to be present.
Definition Validators.hpp:28
Validates that the type of the value is one of the given types.
Definition Validators.hpp:128