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<ripple::STXChainBridge> bridge;
108 std::optional<std::string> bridgeAccount;
109 std::optional<uint32_t> chainClaimId;
110 std::optional<uint32_t> createAccountClaimId;
111 std::optional<ripple::uint256> oracleNode;
112 std::optional<ripple::uint256> credential;
113 std::optional<boost::json::object> delegate;
114 bool includeDeleted = false;
115 };
116
117 using Result = HandlerReturnType<Output>;
118
124 LedgerEntryHandler(std::shared_ptr<BackendInterface> const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend)
125 {
126 }
127
134 static RpcSpecConstRef
135 spec([[maybe_unused]] uint32_t apiVersion)
136 {
137 // Validator only works in this handler
138 // The accounts array must have two different elements
139 // Each element must be a valid address
140 static auto const kRIPPLE_STATE_ACCOUNTS_CHECK =
141 validation::CustomValidator{[](boost::json::value const& value, std::string_view /* key */) -> MaybeError {
142 if (!value.is_array() || value.as_array().size() != 2 || !value.as_array()[0].is_string() ||
143 !value.as_array()[1].is_string() ||
144 value.as_array()[0].as_string() == value.as_array()[1].as_string()) {
145 return Error{Status{RippledError::rpcINVALID_PARAMS, "malformedAccounts"}};
146 }
147
148 auto const id1 =
149 util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[0])
150 );
151 auto const id2 =
152 util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[1])
153 );
154
155 if (!id1 || !id2)
156 return Error{Status{ClioError::RpcMalformedAddress, "malformedAddresses"}};
157
158 return MaybeError{};
159 }};
160
161 static auto const kMALFORMED_REQUEST_HEX_STRING_VALIDATOR = meta::WithCustomError{
163 };
164
165 static auto const kMALFORMED_REQUEST_INT_VALIDATOR =
166 meta::WithCustomError{validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)};
167
168 static auto const kBRIDGE_JSON_VALIDATOR = meta::WithCustomError{
170 {ripple::sfLockingChainDoor.getJsonName().c_str(),
173 {ripple::sfIssuingChainDoor.getJsonName().c_str(),
176 {ripple::sfLockingChainIssue.getJsonName().c_str(),
179 {ripple::sfIssuingChainIssue.getJsonName().c_str(),
182 }},
183 Status(ClioError::RpcMalformedRequest)
184 };
185
186 static auto const kRPC_SPEC = RpcSpec{
187 {JS(binary), validation::Type<bool>{}},
190 {JS(index), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
193 {JS(check), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
194 {JS(deposit_preauth),
196 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
199 {JS(owner),
203 }},
206 },
207 }},
208 {JS(directory),
210 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
214 {JS(sub_index), kMALFORMED_REQUEST_INT_VALIDATOR}
215 }}},
216 {JS(escrow),
218 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
221 {JS(owner),
225 }},
226 {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
227 },
228 }},
229 {JS(offer),
231 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
235 {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
236 },
237 }},
238 {JS(payment_channel), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
239 {JS(ripple_state),
242 {JS(accounts), validation::Required{}, kRIPPLE_STATE_ACCOUNTS_CHECK},
244 }},
245 {JS(ticket),
247 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
251 {JS(ticket_seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR},
252 },
253 }},
254 {JS(nft_page), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
255 {JS(amm),
257 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
260 {JS(asset),
261 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
263 validation::Type<boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
264 },
266 {JS(asset2),
267 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
269 validation::Type<boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
270 },
272 },
273 }},
274 {JS(bridge),
275 meta::WithCustomError{validation::Type<boost::json::object>{}, Status(ClioError::RpcMalformedRequest)},
276 kBRIDGE_JSON_VALIDATOR},
277 {JS(bridge_account),
279 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedRequest)
280 }},
281 {JS(xchain_owned_claim_id),
283 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
284 },
285 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
286 kBRIDGE_JSON_VALIDATOR,
289 meta::Section{{JS(xchain_owned_claim_id), validation::Required{}, validation::Type<uint32_t>{}}}
290 },
291 Status(ClioError::RpcMalformedRequest)
292 }},
293 {JS(xchain_owned_create_account_claim_id),
295 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
296 },
297 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
298 kBRIDGE_JSON_VALIDATOR,
301 {JS(xchain_owned_create_account_claim_id), validation::Required{}, validation::Type<uint32_t>{}}
302 }},
303 Status(ClioError::RpcMalformedRequest)
304 }},
305 {JS(oracle),
307 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
308 },
310 meta::WithCustomError{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)}
311 },
313 {JS(account),
314 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
316 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
317 }},
318 // note: Unlike `rippled`, Clio only supports UInt as input, no string, no `null`, etc.:
319 {JS(oracle_document_id),
320 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
322 validation::Type<uint32_t, std::string>{}, Status(ClioError::RpcMalformedOracleDocumentId)
323 },
324 meta::WithCustomError{modifiers::ToNumber{}, Status(ClioError::RpcMalformedOracleDocumentId)}},
325 }}},
326 {JS(credential),
328 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
329 },
331 meta::WithCustomError{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)}
332 },
334 {JS(subject),
335 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
337 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
338 }},
339 {JS(issuer),
340 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
342 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
343 }},
344 {
345 JS(credential_type),
346 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
347 meta::WithCustomError{validation::Type<std::string>{}, Status(ClioError::RpcMalformedRequest)},
348 },
349 }}},
350 {JS(mpt_issuance),
353 }},
354 {JS(mptoken),
356 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
357 },
358 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
361 {
362 JS(account),
363 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
366 Status(ClioError::RpcMalformedAddress)
367 },
368 },
369 {
370 JS(mpt_issuance_id),
371 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
374 Status(ClioError::RpcMalformedRequest)
375 },
376 },
377 },
378 }},
379 {JS(permissioned_domain),
381 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
382 },
383 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
385 {JS(seq),
386 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
387 meta::WithCustomError{validation::Type<uint32_t>{}, Status(ClioError::RpcMalformedRequest)}},
388 {
389 JS(account),
390 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
392 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
393 },
394 },
395 }}},
396 {JS(delegate),
398 validation::Type<std::string, boost::json::object>{}, Status(ClioError::RpcMalformedRequest)
399 },
400 meta::IfType<std::string>{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR},
402 {JS(account),
403 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
405 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
406 }},
407 {JS(authorize),
408 meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)},
410 validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress)
411 }}
412 }}},
413 {JS(ledger), check::Deprecated{}},
414 {"include_deleted", validation::Type<bool>{}},
415 };
416
417 return kRPC_SPEC;
418 }
419
427 Result
428 process(Input input, Context const& ctx) const;
429
430private:
431 // dir_root and owner can not be both empty or filled at the same time
432 // This function will return an error if this is the case
433 static std::variant<ripple::uint256, Status>
434 composeKeyFromDirectory(boost::json::object const& directory) noexcept;
435
442 friend void
443 tag_invoke(boost::json::value_from_tag, boost::json::value& jv, Output const& output);
444
451 friend Input
452 tag_invoke(boost::json::value_to_tag<Input>, boost::json::value const& jv);
453};
454
455} // 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:135
Result process(Input input, Context const &ctx) const
Process the LedgerEntry command.
Definition LedgerEntry.cpp:62
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:271
LedgerEntryHandler(std::shared_ptr< BackendInterface > const &sharedPtrBackend)
Construct a new LedgerEntryHandler object.
Definition LedgerEntry.hpp:124
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:82
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:535
static CustomValidator ledgerIndexValidator
Provides a commonly used validator for ledger index.
Definition Validators.hpp:484
static CustomValidator currencyIssueValidator
Validates an asset (ripple::Issue).
Definition Validators.hpp:559
static CustomValidator authorizeCredentialValidator
Provides a validator for validating authorized_credentials json array.
Definition Validators.hpp:566
static CustomValidator uint192HexStringValidator
Provides a commonly used validator for uint192 hex string.
Definition Validators.hpp:522
static CustomValidator uint256HexStringValidator
Provides a commonly used validator for uint256 hex string.
Definition Validators.hpp:530
static CustomValidator accountBase58Validator
Provides a commonly used validator for accounts.
Definition Validators.hpp:498
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