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
63 std::shared_ptr<BackendInterface> sharedPtrBackend_;
64
65public:
69 struct Output {
70 std::string index;
71 uint32_t ledgerIndex;
72 std::string ledgerHash;
73 std::optional<boost::json::object> node;
74 std::optional<std::string> nodeBinary;
75 std::optional<uint32_t> deletedLedgerIndex;
76 bool validated = true;
77 };
78
82 struct Input {
83 std::optional<std::string> ledgerHash;
84 std::optional<uint32_t> ledgerIndex;
85 bool binary = false;
86 // id of this ledger entry: 256 bits hex string
87 std::optional<std::string> index;
88 // index can be extracted from payment_channel, check, escrow, offer
89 // etc, expectedType is used to save the type of index
90 ripple::LedgerEntryType expectedType = ripple::ltANY;
91 // account id to address account root object
92 std::optional<std::string> accountRoot;
93 // account id to address did object
94 std::optional<std::string> did;
95 // mpt issuance id to address mptIssuance object
96 std::optional<std::string> mptIssuance;
97 // TODO: extract into custom objects, remove json from Input
98 std::optional<boost::json::object> directory;
99 std::optional<boost::json::object> offer;
100 std::optional<boost::json::object> rippleStateAccount;
101 std::optional<boost::json::object> escrow;
102 std::optional<boost::json::object> depositPreauth;
103 std::optional<boost::json::object> ticket;
104 std::optional<boost::json::object> amm;
105 std::optional<boost::json::object> mptoken;
106 std::optional<boost::json::object> permissionedDomain;
107 std::optional<boost::json::object> vault;
108 std::optional<ripple::STXChainBridge> bridge;
109 std::optional<std::string> bridgeAccount;
110 std::optional<uint32_t> chainClaimId;
111 std::optional<uint32_t> createAccountClaimId;
112 std::optional<ripple::uint256> oracleNode;
113 std::optional<ripple::uint256> credential;
114 std::optional<boost::json::object> delegate;
115 bool includeDeleted = false;
116 };
117
118 using Result = HandlerReturnType<Output>;
119
125 LedgerEntryHandler(std::shared_ptr<BackendInterface> const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend)
126 {
127 }
128
135 static RpcSpecConstRef
136 spec([[maybe_unused]] uint32_t apiVersion)
137 {
138 // Validator only works in this handler
139 // The accounts array must have two different elements
140 // Each element must be a valid address
141 static auto const kRIPPLE_STATE_ACCOUNTS_CHECK =
142 validation::CustomValidator{[](boost::json::value const& value, std::string_view /* key */) -> MaybeError {
143 if (!value.is_array() || value.as_array().size() != 2 || !value.as_array()[0].is_string() ||
144 !value.as_array()[1].is_string() ||
145 value.as_array()[0].as_string() == value.as_array()[1].as_string()) {
146 return Error{Status{RippledError::rpcINVALID_PARAMS, "malformedAccounts"}};
147 }
148
150 boost::json::value_to<std::string>(value.as_array()[0])
151 );
153 boost::json::value_to<std::string>(value.as_array()[1])
154 );
155
156 if (!id1 || !id2)
157 return Error{Status{ClioError::RpcMalformedAddress, "malformedAddresses"}};
158
159 return MaybeError{};
160 }};
161
162 static auto const kMALFORMED_REQUEST_HEX_STRING_VALIDATOR = meta::WithCustomError{
164 };
165
166 static auto const kMALFORMED_REQUEST_INT_VALIDATOR =
167 meta::WithCustomError{validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)};
168
169 static auto const kBRIDGE_JSON_VALIDATOR = meta::WithCustomError{
171 {ripple::sfLockingChainDoor.getJsonName().c_str(),
174 {ripple::sfIssuingChainDoor.getJsonName().c_str(),
177 {ripple::sfLockingChainIssue.getJsonName().c_str(),
180 {ripple::sfIssuingChainIssue.getJsonName().c_str(),
183 }},
184 Status(ClioError::RpcMalformedRequest)
185 };
186
187 static auto const kRPC_SPEC = RpcSpec{
188 {JS(binary), validation::Type<bool>{}},
191 {JS(index), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
194 {JS(check), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
195 {JS(deposit_preauth),
197 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
200 {JS(owner),
204 }},
207 },
208 }},
209 {JS(directory),
211 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
215 {JS(sub_index), kMALFORMED_REQUEST_INT_VALIDATOR}
216 }}},
217 {JS(escrow),
219 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
222 {JS(owner),
226 }},
227 {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
228 },
229 }},
230 {JS(offer),
232 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
236 {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
237 },
238 }},
239 {JS(payment_channel), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
240 {JS(ripple_state),
243 {JS(accounts), validation::Required{}, kRIPPLE_STATE_ACCOUNTS_CHECK},
245 }},
246 {JS(ticket),
248 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
252 {JS(ticket_seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
253 },
254 }},
255 {JS(nft_page), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
256 {JS(amm),
258 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
261 {JS(asset),
262 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
264 validation::Type<boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
265 },
267 {JS(asset2),
268 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
270 validation::Type<boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
271 },
273 },
274 }},
275 {JS(bridge),
276 meta::WithCustomError{validation::Type<boost::json::object>{}, Status(ClioError::RpcMalformedRequest)},
277 kBRIDGE_JSON_VALIDATOR},
278 {JS(bridge_account),
280 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedRequest)
281 }},
282 {JS(xchain_owned_claim_id),
284 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
285 },
286 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
287 kBRIDGE_JSON_VALIDATOR,
290 meta::Section{{JS(xchain_owned_claim_id), validation::Required{}, validation::Type<uint32_t>{}}}
291 },
292 Status(ClioError::RpcMalformedRequest)
293 }},
294 {JS(xchain_owned_create_account_claim_id),
296 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
297 },
298 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
299 kBRIDGE_JSON_VALIDATOR,
302 {JS(xchain_owned_create_account_claim_id), validation::Required{}, validation::Type<uint32_t>{}}
303 }},
304 Status(ClioError::RpcMalformedRequest)
305 }},
306 {JS(oracle),
308 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
309 },
311 meta::WithCustomError{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)}
312 },
314 {JS(account),
315 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
317 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
318 }},
319 // note: Unlike `rippled`, Clio only supports UInt as input, no string, no `null`, etc.:
320 {JS(oracle_document_id),
321 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
323 validation::Type<uint32_t, std::string>{}, Status(ClioError::RpcMalformedOracleDocumentId)
324 },
325 meta::WithCustomError{modifiers::ToNumber{}, Status(ClioError::RpcMalformedOracleDocumentId)}},
326 }}},
327 {JS(credential),
329 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
330 },
332 meta::WithCustomError{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)}
333 },
335 {JS(subject),
336 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
338 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
339 }},
340 {JS(issuer),
341 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
343 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
344 }},
345 {
346 JS(credential_type),
347 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
348 meta::WithCustomError{validation::Type<std::string>{}, Status(ClioError::RpcMalformedRequest)},
349 },
350 }}},
351 {JS(mpt_issuance),
354 }},
355 {JS(mptoken),
357 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
358 },
359 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
362 {
363 JS(account),
364 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
367 Status(ClioError::RpcMalformedAddress)
368 },
369 },
370 {
371 JS(mpt_issuance_id),
372 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
375 Status(ClioError::RpcMalformedRequest)
376 },
377 },
378 },
379 }},
380 {JS(permissioned_domain),
382 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
383 },
384 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
386 {JS(seq),
387 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
388 meta::WithCustomError{validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)}},
389 {
390 JS(account),
391 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
393 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
394 },
395 },
396 }}},
397 {JS(vault),
399 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
400 },
401 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
403 {JS(seq),
404 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
405 meta::WithCustomError{validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)}},
406 {
407 JS(owner),
408 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
411 },
412 },
413 }}},
414 {JS(delegate),
416 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
417 },
418 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
420 {JS(account),
421 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
423 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
424 }},
425 {JS(authorize),
426 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
428 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
429 }}
430 }}},
431 {JS(ledger), check::Deprecated{}},
432 {"include_deleted", validation::Type<bool>{}},
433 };
434
435 return kRPC_SPEC;
436 }
437
445 Result
446 process(Input input, Context const& ctx) const;
447
448private:
449 // dir_root and owner can not be both empty or filled at the same time
450 // This function will return an error if this is the case
451 static std::expected<ripple::uint256, Status>
452 composeKeyFromDirectory(boost::json::object const& directory) noexcept;
453
460 friend void
461 tag_invoke(boost::json::value_from_tag, boost::json::value& jv, Output const& output);
462
469 friend Input
470 tag_invoke(boost::json::value_to_tag<Input>, boost::json::value const& jv);
471};
472
473} // namespace rpc
The ledger_entry method returns a single ledger object from the XRP Ledger in its raw format.
Definition LedgerEntry.hpp:62
static RpcSpecConstRef spec(uint32_t apiVersion)
Returns the API specification for the command.
Definition LedgerEntry.hpp:136
Result process(Input input, Context const &ctx) const
Process the LedgerEntry command.
Definition LedgerEntry.cpp:61
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:275
LedgerEntryHandler(std::shared_ptr< BackendInterface > const &sharedPtrBackend)
Construct a new LedgerEntryHandler object.
Definition LedgerEntry.hpp:125
Check for a deprecated fields.
Definition Checkers.hpp:62
A meta-processor that specifies a list of requirements to run against when the type matches the templ...
Definition MetaProcessors.hpp:101
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:166
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:37
RpcSpec const & RpcSpecConstRef
An alias for a const reference to RpcSpec.
Definition Specs.hpp:145
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:42
Context of an RPC call.
Definition Types.hpp:118
A struct to hold the input data for the command.
Definition LedgerEntry.hpp:82
A struct to hold the output data of the command.
Definition LedgerEntry.hpp:69
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:98
A status returned from any RPC handler.
Definition Errors.hpp:83
Convert input string to integer.
Definition Modifiers.hpp:112
static CustomValidator currencyValidator
Provides a commonly used validator for currency, including standard currency code and token code.
Definition Validators.hpp:538
static CustomValidator ledgerIndexValidator
Provides a commonly used validator for ledger index.
Definition Validators.hpp:487
static CustomValidator currencyIssueValidator
Validates an asset (ripple::Issue).
Definition Validators.hpp:562
static CustomValidator authorizeCredentialValidator
Provides a validator for validating authorized_credentials json array.
Definition Validators.hpp:569
static CustomValidator uint192HexStringValidator
Provides a commonly used validator for uint192 hex string.
Definition Validators.hpp:525
static CustomValidator uint256HexStringValidator
Provides a commonly used validator for uint256 hex string.
Definition Validators.hpp:533
static CustomValidator accountBase58Validator
Provides a commonly used validator for accounts.
Definition Validators.hpp:501
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:142