Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
LedgerEntry.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2023, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "data/BackendInterface.hpp"
23#include "rpc/Errors.hpp"
24#include "rpc/JS.hpp"
25#include "rpc/common/Checkers.hpp"
26#include "rpc/common/MetaProcessors.hpp"
27#include "rpc/common/Modifiers.hpp"
28#include "rpc/common/Specs.hpp"
29#include "rpc/common/Types.hpp"
30#include "rpc/common/Validators.hpp"
31#include "util/AccountUtils.hpp"
32
33#include <boost/json/array.hpp>
34#include <boost/json/conversion.hpp>
35#include <boost/json/object.hpp>
36#include <boost/json/value.hpp>
37#include <boost/json/value_to.hpp>
38#include <xrpl/basics/base_uint.h>
39#include <xrpl/beast/core/LexicalCast.h>
40#include <xrpl/protocol/AccountID.h>
41#include <xrpl/protocol/ErrorCodes.h>
42#include <xrpl/protocol/Issue.h>
43#include <xrpl/protocol/LedgerFormats.h>
44#include <xrpl/protocol/SField.h>
45#include <xrpl/protocol/jss.h>
46#include <xrpl/protocol/tokens.h>
47
48#include <cstdint>
49#include <memory>
50#include <optional>
51#include <string>
52#include <string_view>
53#include <variant>
54
55namespace rpc {
56
64 std::shared_ptr<BackendInterface> sharedPtrBackend_;
65
66public:
70 struct Output {
71 std::string index;
72 uint32_t ledgerIndex;
73 std::string ledgerHash;
74 std::optional<boost::json::object> node;
75 std::optional<std::string> nodeBinary;
76 std::optional<uint32_t> deletedLedgerIndex;
77 bool validated = true;
78 };
79
83 struct Input {
84 std::optional<std::string> ledgerHash;
85 std::optional<uint32_t> ledgerIndex;
86 bool binary = false;
87 // id of this ledger entry: 256 bits hex string
88 std::optional<std::string> index;
89 // index can be extracted from payment_channel, check, escrow, offer
90 // etc, expectedType is used to save the type of index
91 ripple::LedgerEntryType expectedType = ripple::ltANY;
92 // account id to address account root object
93 std::optional<std::string> accountRoot;
94 // account id to address did object
95 std::optional<std::string> did;
96 // mpt issuance id to address mptIssuance object
97 std::optional<std::string> mptIssuance;
98 // TODO: extract into custom objects, remove json from Input
99 std::optional<boost::json::object> directory;
100 std::optional<boost::json::object> offer;
101 std::optional<boost::json::object> rippleStateAccount;
102 std::optional<boost::json::object> escrow;
103 std::optional<boost::json::object> depositPreauth;
104 std::optional<boost::json::object> ticket;
105 std::optional<boost::json::object> amm;
106 std::optional<boost::json::object> mptoken;
107 std::optional<boost::json::object> permissionedDomain;
108 std::optional<boost::json::object> vault;
109 std::optional<boost::json::object> loanBroker;
110 std::optional<boost::json::object> loan;
111 std::optional<ripple::STXChainBridge> bridge;
112 std::optional<std::string> bridgeAccount;
113 std::optional<uint32_t> chainClaimId;
114 std::optional<uint32_t> createAccountClaimId;
115 std::optional<ripple::uint256> oracleNode;
116 std::optional<ripple::uint256> credential;
117 std::optional<boost::json::object> delegate;
118 bool includeDeleted = false;
119 };
120
121 using Result = HandlerReturnType<Output>;
122
128 LedgerEntryHandler(std::shared_ptr<BackendInterface> const& sharedPtrBackend)
129 : sharedPtrBackend_(sharedPtrBackend)
130 {
131 }
132
139 static RpcSpecConstRef
140 spec([[maybe_unused]] uint32_t apiVersion)
141 {
142 // Validator only works in this handler
143 // The accounts array must have two different elements
144 // Each element must be a valid address
145 static auto const kRIPPLE_STATE_ACCOUNTS_CHECK = validation::CustomValidator{
146 [](boost::json::value const& value, std::string_view /* key */) -> MaybeError {
147 if (!value.is_array() || value.as_array().size() != 2 ||
148 !value.as_array()[0].is_string() || !value.as_array()[1].is_string() ||
149 value.as_array()[0].as_string() == value.as_array()[1].as_string()) {
150 return Error{Status{RippledError::rpcINVALID_PARAMS, "malformedAccounts"}};
151 }
152
154 boost::json::value_to<std::string>(value.as_array()[0])
155 );
157 boost::json::value_to<std::string>(value.as_array()[1])
158 );
159
160 if (!id1 || !id2)
161 return Error{Status{ClioError::RpcMalformedAddress, "malformedAddresses"}};
162
163 return MaybeError{};
164 }
165 };
166
167 static auto const kMALFORMED_REQUEST_HEX_STRING_VALIDATOR = meta::WithCustomError{
169 Status(ClioError::RpcMalformedRequest)
170 };
171
172 static auto const kMALFORMED_REQUEST_INT_VALIDATOR = meta::WithCustomError{
173 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
174 };
175
176 static auto const kBRIDGE_JSON_VALIDATOR = meta::WithCustomError{
178 {ripple::sfLockingChainDoor.getJsonName().c_str(),
181 {ripple::sfIssuingChainDoor.getJsonName().c_str(),
184 {ripple::sfLockingChainIssue.getJsonName().c_str(),
187 {ripple::sfIssuingChainIssue.getJsonName().c_str(),
190 }},
191 Status(ClioError::RpcMalformedRequest)
192 };
193
194 static auto const kRPC_SPEC = RpcSpec{
195 {JS(binary), validation::Type<bool>{}},
198 {JS(index), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
201 {JS(check), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
202 {JS(deposit_preauth),
204 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
207 {JS(owner),
211 Status(ClioError::RpcMalformedOwner)
212 }},
214 {JS(authorized_credentials),
216 },
217 }},
218 {JS(directory),
220 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
224 {JS(sub_index), kMALFORMED_REQUEST_INT_VALIDATOR}
225 }}},
226 {JS(escrow),
228 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
231 {JS(owner),
235 Status(ClioError::RpcMalformedOwner)
236 }},
237 {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
238 },
239 }},
240 {JS(offer),
242 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
245 {JS(account),
248 {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
249 },
250 }},
251 {JS(payment_channel), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
252 {JS(ripple_state),
255 {JS(accounts), validation::Required{}, kRIPPLE_STATE_ACCOUNTS_CHECK},
256 {JS(currency),
259 }},
260 {JS(ticket),
262 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
265 {JS(account),
268 {JS(ticket_seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
269 },
270 }},
271 {JS(nft_page), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
272 {JS(amm),
274 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
277 {JS(asset),
279 validation::Required{}, Status(ClioError::RpcMalformedRequest)
280 },
283 Status(ClioError::RpcMalformedRequest)
284 },
286 {JS(asset2),
288 validation::Required{}, Status(ClioError::RpcMalformedRequest)
289 },
292 Status(ClioError::RpcMalformedRequest)
293 },
295 },
296 }},
297 {JS(bridge),
299 validation::Type<boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
300 },
301 kBRIDGE_JSON_VALIDATOR},
302 {JS(bridge_account),
305 Status(ClioError::RpcMalformedRequest)
306 }},
307 {JS(xchain_owned_claim_id),
310 Status(ClioError::RpcMalformedRequest)
311 },
312 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
313 kBRIDGE_JSON_VALIDATOR,
316 {JS(xchain_owned_claim_id),
319 }},
320 Status(ClioError::RpcMalformedRequest)
321 }},
322 {JS(xchain_owned_create_account_claim_id),
325 Status(ClioError::RpcMalformedRequest)
326 },
327 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
328 kBRIDGE_JSON_VALIDATOR,
331 {JS(xchain_owned_create_account_claim_id),
334 }},
335 Status(ClioError::RpcMalformedRequest)
336 }},
337 {JS(oracle),
340 Status(ClioError::RpcMalformedRequest)
341 },
343 kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)
344 }},
346 {JS(account),
348 validation::Required{}, Status(ClioError::RpcMalformedRequest)
349 },
352 Status(ClioError::RpcMalformedAddress)
353 }},
354 // note: Unlike `rippled`, Clio only supports UInt as input, no string, no `null`,
355 // etc.:
356 {JS(oracle_document_id),
358 validation::Required{}, Status(ClioError::RpcMalformedRequest)
359 },
362 Status(ClioError::RpcMalformedOracleDocumentId)
363 },
365 modifiers::ToNumber{}, Status(ClioError::RpcMalformedOracleDocumentId)
366 }},
367 }}},
368 {JS(credential),
371 Status(ClioError::RpcMalformedRequest)
372 },
374 kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)
375 }},
377 {JS(subject),
379 validation::Required{}, Status(ClioError::RpcMalformedRequest)
380 },
383 Status(ClioError::RpcMalformedAddress)
384 }},
385 {JS(issuer),
387 validation::Required{}, Status(ClioError::RpcMalformedRequest)
388 },
391 Status(ClioError::RpcMalformedAddress)
392 }},
393 {
394 JS(credential_type),
396 validation::Required{}, Status(ClioError::RpcMalformedRequest)
397 },
399 validation::Type<std::string>{}, Status(ClioError::RpcMalformedRequest)
400 },
401 },
402 }}},
403 {JS(mpt_issuance),
406 Status(ClioError::RpcMalformedRequest)
407 }},
408 {JS(mptoken),
411 Status(ClioError::RpcMalformedRequest)
412 },
413 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
416 {
417 JS(account),
419 validation::Required{}, Status(ClioError::RpcMalformedRequest)
420 },
423 Status(ClioError::RpcMalformedAddress)
424 },
425 },
426 {
427 JS(mpt_issuance_id),
429 validation::Required{}, Status(ClioError::RpcMalformedRequest)
430 },
433 Status(ClioError::RpcMalformedRequest)
434 },
435 },
436 },
437 }},
438 {JS(permissioned_domain),
441 Status(ClioError::RpcMalformedRequest)
442 },
443 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
445 {JS(seq),
447 validation::Required{}, Status(ClioError::RpcMalformedRequest)
448 },
450 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
451 }},
452 {
453 JS(account),
455 validation::Required{}, Status(ClioError::RpcMalformedRequest)
456 },
459 Status(ClioError::RpcMalformedAddress)
460 },
461 },
462 }}},
463 {JS(vault),
466 Status(ClioError::RpcMalformedRequest)
467 },
468 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
470 {JS(seq),
472 validation::Required{}, Status(ClioError::RpcMalformedRequest)
473 },
475 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
476 }},
477 {
478 JS(owner),
480 validation::Required{}, Status(ClioError::RpcMalformedRequest)
481 },
484 Status(ClioError::RpcMalformedOwner)
485 },
486 },
487 }}},
488 {JS(loan_broker),
491 Status(ClioError::RpcMalformedRequest)
492 },
493 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
495 {JS(seq),
497 validation::Required{}, Status(ClioError::RpcMalformedRequest)
498 },
500 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
501 }},
502 {
503 JS(owner),
505 validation::Required{}, Status(ClioError::RpcMalformedRequest)
506 },
509 Status(ClioError::RpcMalformedOwner)
510 },
511 },
512 }}},
513 {JS(loan),
516 Status(ClioError::RpcMalformedRequest)
517 },
518 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
520 {JS(loan_seq),
522 validation::Required{}, Status(ClioError::RpcMalformedRequest)
523 },
525 validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)
526 }},
527 {
528 JS(loan_broker_id),
530 validation::Required{}, Status(ClioError::RpcMalformedRequest)
531 },
534 Status(ClioError::RpcMalformedRequest)
535 },
536 },
537 }}},
538 {JS(delegate),
541 Status(ClioError::RpcMalformedRequest)
542 },
543 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
545 {JS(account),
547 validation::Required{}, Status(ClioError::RpcMalformedRequest)
548 },
551 Status(ClioError::RpcMalformedAddress)
552 }},
553 {JS(authorize),
555 validation::Required{}, Status(ClioError::RpcMalformedRequest)
556 },
559 Status(ClioError::RpcMalformedAddress)
560 }}
561 }}},
562 {JS(amendments), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
563 {JS(fee), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
564 {JS(hashes), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
565 {JS(nft_offer), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
566 {JS(nunl), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
567 {JS(signer_list), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
568 {JS(ledger), check::Deprecated{}},
569 {"include_deleted", validation::Type<bool>{}},
570 };
571
572 return kRPC_SPEC;
573 }
574
582 Result
583 process(Input const& input, Context const& ctx) const;
584
585private:
586 // dir_root and owner can not be both empty or filled at the same time
587 // This function will return an error if this is the case
588 static std::expected<ripple::uint256, Status>
589 composeKeyFromDirectory(boost::json::object const& directory) noexcept;
590
597 friend void
598 tag_invoke(boost::json::value_from_tag, boost::json::value& jv, Output const& output);
599
606 friend Input
607 tag_invoke(boost::json::value_to_tag<Input>, boost::json::value const& jv);
608};
609
610} // namespace rpc
static RpcSpecConstRef spec(uint32_t apiVersion)
Returns the API specification for the command.
Definition LedgerEntry.hpp:140
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:325
Result process(Input const &input, Context const &ctx) const
Process the LedgerEntry command.
Definition LedgerEntry.cpp:62
LedgerEntryHandler(std::shared_ptr< BackendInterface > const &sharedPtrBackend)
Construct a new LedgerEntryHandler object.
Definition LedgerEntry.hpp:128
Check for a deprecated fields.
Definition Checkers.hpp:63
A meta-processor that specifies a list of requirements to run against when the type matches the templ...
Definition MetaProcessors.hpp:104
A meta-processor that acts as a spec for a sub-object/section.
Definition MetaProcessors.hpp:43
A meta-processor that wraps a validator and produces a custom error in case the wrapped validator fai...
Definition MetaProcessors.hpp:172
A meta-validator that allows to specify a custom validation function.
Definition Validators.hpp:440
This namespace contains all the RPC logic and handlers.
Definition AMMHelpers.cpp:37
RpcSpec const & RpcSpecConstRef
An alias for a const reference to RpcSpec.
Definition Specs.hpp:150
std::expected< OutputType, Status > HandlerReturnType
Return type for each individual handler.
Definition Types.hpp:81
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:55
std::unexpected< Status > Error
The type that represents just the error part of MaybeError.
Definition Types.hpp:75
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:43
Context of an RPC call.
Definition Types.hpp:118
A struct to hold the input data for the command.
Definition LedgerEntry.hpp:83
A struct to hold the output data of the command.
Definition LedgerEntry.hpp:70
Result type used to return responses or error statuses to the Webserver subsystem.
Definition Types.hpp:129
Represents a Specification of an entire RPC command.
Definition Specs.hpp:102
A status returned from any RPC handler.
Definition Errors.hpp:84
Convert input string to integer.
Definition Modifiers.hpp:113
static CustomValidator currencyValidator
Provides a commonly used validator for currency, including standard currency code and token code.
Definition Validators.hpp:574
static CustomValidator ledgerIndexValidator
Provides a commonly used validator for ledger index.
Definition Validators.hpp:506
static CustomValidator currencyIssueValidator
Validates an asset (ripple::Issue).
Definition Validators.hpp:598
static CustomValidator authorizeCredentialValidator
Provides a validator for validating authorized_credentials json array.
Definition Validators.hpp:605
static CustomValidator uint192HexStringValidator
Provides a commonly used validator for uint192 hex string.
Definition Validators.hpp:560
static CustomValidator uint256HexStringValidator
Provides a commonly used validator for uint256 hex string.
Definition Validators.hpp:568
static CustomValidator accountBase58Validator
Provides a commonly used validator for accounts.
Definition Validators.hpp:528
A validator that simply requires a field to be present.
Definition Validators.hpp:47
Validates that the type of the value is one of the given types.
Definition Validators.hpp:146