Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
RPCHelpers.hpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2022, 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
21#pragma once
22
23/*
24 * This file contains a variety of utility functions used when executing the handlers.
25 */
26
27#include "data/BackendInterface.hpp"
28#include "data/Types.hpp"
29#include "rpc/Errors.hpp"
30#include "rpc/common/Types.hpp"
31#include "util/JsonUtils.hpp"
32#include "util/log/Logger.hpp"
33#include "web/Context.hpp"
34
35#include <boost/asio/spawn.hpp>
36#include <boost/json/array.hpp>
37#include <boost/json/object.hpp>
38#include <boost/json/value.hpp>
39#include <boost/regex.hpp>
40#include <boost/regex/v5/regex_fwd.hpp>
41#include <boost/regex/v5/regex_match.hpp>
42#include <fmt/core.h>
43#include <xrpl/basics/base_uint.h>
44#include <xrpl/json/json_value.h>
45#include <xrpl/protocol/AccountID.h>
46#include <xrpl/protocol/Book.h>
47#include <xrpl/protocol/Fees.h>
48#include <xrpl/protocol/Indexes.h>
49#include <xrpl/protocol/Issue.h>
50#include <xrpl/protocol/Keylet.h>
51#include <xrpl/protocol/LedgerHeader.h>
52#include <xrpl/protocol/PublicKey.h>
53#include <xrpl/protocol/Rate.h>
54#include <xrpl/protocol/STAmount.h>
55#include <xrpl/protocol/STBase.h>
56#include <xrpl/protocol/STLedgerEntry.h>
57#include <xrpl/protocol/STObject.h>
58#include <xrpl/protocol/STTx.h>
59#include <xrpl/protocol/SecretKey.h>
60#include <xrpl/protocol/Seed.h>
61#include <xrpl/protocol/TxMeta.h>
62#include <xrpl/protocol/UintTypes.h>
63#include <xrpl/protocol/XRPAmount.h>
64
65#include <chrono>
66#include <cstddef>
67#include <cstdint>
68#include <functional>
69#include <memory>
70#include <optional>
71#include <string>
72#include <tuple>
73#include <utility>
74#include <variant>
75#include <vector>
76
77namespace rpc {
78
80enum class NFTokenjson { ENABLE, DISABLE };
81
88std::optional<ripple::AccountID>
89accountFromStringStrict(std::string const& account);
90
98bool
99isOwnedByAccount(ripple::SLE const& sle, ripple::AccountID const& accountID);
100
108std::uint64_t
109getStartHint(ripple::SLE const& sle, ripple::AccountID const& accountID);
110
117std::optional<AccountCursor>
118parseAccountCursor(std::optional<std::string> jsonCursor);
119
120// TODO this function should probably be in a different file and namespace
127std::pair<std::shared_ptr<ripple::STTx const>, std::shared_ptr<ripple::STObject const>>
129
130// TODO this function should probably be in a different file and namespace
138std::pair<std::shared_ptr<ripple::STTx const>, std::shared_ptr<ripple::TxMeta const>>
139deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs, std::uint32_t seq);
140
150std::pair<boost::json::object, boost::json::object>
152 data::TransactionAndMetadata const& blobs,
153 std::uint32_t apiVersion,
154 NFTokenjson nftEnabled = NFTokenjson::DISABLE,
155 std::optional<uint16_t> networkId = std::nullopt
156);
157
165boost::json::object
166toJsonWithBinaryTx(data::TransactionAndMetadata const& txnPlusMeta, std::uint32_t apiVersion);
167
174void
175insertDeliverMaxAlias(boost::json::object& txJson, std::uint32_t apiVersion);
176
186bool
188 boost::json::object& metaJson,
189 std::shared_ptr<ripple::STTx const> const& txn,
190 std::shared_ptr<ripple::TxMeta const> const& meta,
191 uint32_t date
192);
193
202bool
204 boost::json::object& metaJson,
205 std::shared_ptr<ripple::STTx const> const& txn,
206 std::shared_ptr<ripple::TxMeta const> const& meta
207);
208
215boost::json::object
216toJson(ripple::STBase const& obj);
217
224boost::json::object
225toJson(ripple::SLE const& sle);
226
235boost::json::object
236toJson(ripple::LedgerHeader const& info, bool binary, std::uint32_t apiVersion);
237
244boost::json::object
245toJson(ripple::TxMeta const& meta);
246
247using RippledJson = Json::Value;
248
255boost::json::value
256toBoostJson(RippledJson const& value);
257
267boost::json::object
269 ripple::LedgerHeader const& lgrInfo,
270 ripple::Fees const& fees,
271 std::string const& ledgerRange,
272 std::uint32_t txnCount
273);
274
282std::variant<Status, ripple::LedgerHeader>
283ledgerHeaderFromRequest(std::shared_ptr<data::BackendInterface const> const& backend, web::Context const& ctx);
284
295std::variant<Status, ripple::LedgerHeader>
297 BackendInterface const& backend,
298 boost::asio::yield_context yield,
299 std::optional<std::string> ledgerHash,
300 std::optional<uint32_t> ledgerIndex,
301 uint32_t maxSeq
302);
303
317std::variant<Status, AccountCursor>
319 BackendInterface const& backend,
320 ripple::Keylet const& owner,
321 ripple::uint256 const& hexMarker,
322 std::uint32_t startHint,
323 std::uint32_t sequence,
324 std::uint32_t limit,
325 boost::asio::yield_context yield,
326 std::function<void(ripple::SLE)> atOwnedNode
327);
328
344std::variant<Status, AccountCursor>
346 BackendInterface const& backend,
347 ripple::AccountID const& accountID,
348 std::uint32_t sequence,
349 std::uint32_t limit,
350 std::optional<std::string> jsonCursor,
351 boost::asio::yield_context yield,
352 std::function<void(ripple::SLE)> atOwnedNode,
353 bool nftIncluded = false
354);
355
365std::shared_ptr<ripple::SLE const>
366read(
367 std::shared_ptr<data::BackendInterface const> const& backend,
368 ripple::Keylet const& keylet,
369 ripple::LedgerHeader const& lgrInfo,
370 web::Context const& context
371);
372
379std::vector<ripple::AccountID>
380getAccountsFromTransaction(boost::json::object const& transaction);
381
389std::vector<unsigned char>
390ledgerHeaderToBlob(ripple::LedgerHeader const& info, bool includeHash = false);
391
401bool
403 BackendInterface const& backend,
404 std::uint32_t seq,
405 ripple::AccountID const& issuer,
406 boost::asio::yield_context yield
407);
408
420bool
422 BackendInterface const& backend,
423 std::uint32_t sequence,
424 ripple::AccountID const& account,
425 ripple::Currency const& currency,
426 ripple::AccountID const& issuer,
427 boost::asio::yield_context yield
428);
429
440ripple::STAmount
442 BackendInterface const& backend,
443 std::uint32_t sequence,
444 ripple::STAmount const& amount,
445 ripple::AccountID const& id,
446 boost::asio::yield_context yield
447);
448
461ripple::STAmount
463 BackendInterface const& backend,
464 std::uint32_t sequence,
465 ripple::AccountID const& account,
466 ripple::Currency const& currency,
467 ripple::AccountID const& issuer,
468 bool zeroIfFrozen,
469 boost::asio::yield_context yield
470);
471
481ripple::Rate
483 BackendInterface const& backend,
484 std::uint32_t sequence,
485 ripple::AccountID const& issuer,
486 boost::asio::yield_context yield
487);
488
498ripple::XRPAmount
500 BackendInterface const& backend,
501 std::uint32_t sequence,
502 ripple::AccountID const& id,
503 boost::asio::yield_context yield
504);
505
517boost::json::array
519 std::vector<data::LedgerObject> const& offers,
520 ripple::Book const& book,
521 ripple::AccountID const& takerID,
522 data::BackendInterface const& backend,
523 std::uint32_t ledgerSequence,
524 boost::asio::yield_context yield
525);
526
536std::variant<Status, ripple::Book>
537parseBook(ripple::Currency pays, ripple::AccountID payIssuer, ripple::Currency gets, ripple::AccountID getIssuer);
538
545std::variant<Status, ripple::Book>
546parseBook(boost::json::object const& request);
547
554std::variant<Status, ripple::AccountID>
555parseTaker(boost::json::value const& taker);
556
564ripple::Issue
565parseIssue(boost::json::object const& issue);
566
572bool
573specifiesCurrentOrClosedLedger(boost::json::object const& request);
574
582bool
583isAdminCmd(std::string const& method, boost::json::object const& request);
584
591std::variant<ripple::uint256, Status>
592getNFTID(boost::json::object const& request);
593
602std::optional<std::string>
603encodeCTID(uint32_t ledgerSeq, uint16_t txnIndex, uint16_t networkId) noexcept;
604
612template <typename T>
613inline std::optional<std::tuple<uint32_t, uint16_t, uint16_t>>
614decodeCTID(T const ctid) noexcept
615{
616 auto const getCTID64 = [](T const ctid) noexcept -> std::optional<uint64_t> {
617 if constexpr (std::is_convertible_v<T, std::string>) {
618 std::string const ctidString(ctid);
619 static constexpr std::size_t kCTID_STRING_LENGTH = 16;
620 if (ctidString.length() != kCTID_STRING_LENGTH)
621 return {};
622
623 if (!boost::regex_match(ctidString, boost::regex("^[0-9A-F]+$")))
624 return {};
625
626 return std::stoull(ctidString, nullptr, 16);
627 }
628
629 if constexpr (std::is_same_v<T, uint64_t>)
630 return ctid;
631
632 return {};
633 };
634
635 auto const ctidValue = getCTID64(ctid).value_or(0);
636
637 static constexpr uint64_t kCTID_PREFIX = 0xC000'0000'0000'0000ULL;
638 static constexpr uint64_t kCTID_PREFIX_MASK = 0xF000'0000'0000'0000ULL;
639
640 if ((ctidValue & kCTID_PREFIX_MASK) != kCTID_PREFIX)
641 return {};
642
643 uint32_t const ledgerSeq = (ctidValue >> 32) & 0xFFFF'FFFUL;
644 uint16_t const txnIndex = (ctidValue >> 16) & 0xFFFFU;
645 uint16_t const networkId = ctidValue & 0xFFFFU;
646 return {{ledgerSeq, txnIndex, networkId}};
647}
648
656template <typename T>
657void
658logDuration(web::Context const& ctx, T const& dur)
659{
660 using boost::json::serialize;
661
662 static util::Logger const log{"RPC"}; // NOLINT(readability-identifier-naming)
663 static constexpr std::int64_t kDURATION_ERROR_THRESHOLD_SECONDS = 10;
664
665 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
666 auto const seconds = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
667 auto const msg = fmt::format(
668 "Request processing duration = {} milliseconds. request = {}", millis, serialize(util::removeSecret(ctx.params))
669 );
670
671 if (seconds > kDURATION_ERROR_THRESHOLD_SECONDS) {
672 LOG(log.error()) << ctx.tag() << msg;
673 } else if (seconds > 1) {
674 LOG(log.warn()) << ctx.tag() << msg;
675 } else
676 LOG(log.info()) << ctx.tag() << msg;
677}
678
685std::optional<ripple::Seed>
686parseRippleLibSeed(boost::json::value const& value);
687
700std::variant<Status, AccountCursor>
702 BackendInterface const& backend,
703 std::uint32_t sequence,
704 ripple::AccountID const& accountID,
705 ripple::uint256 nextPage,
706 std::uint32_t limit,
707 boost::asio::yield_context yield,
708 std::function<void(ripple::SLE)> atOwnedNode
709);
710
717std::optional<std::uint32_t>
718parseStringAsUInt(std::string const& value); // TODO: move to string utils or something?
719
727bool
729 std::shared_ptr<ripple::STTx const> const& txn,
730 std::shared_ptr<ripple::TxMeta const> const& meta
731);
732
742std::optional<ripple::STAmount>
744 std::shared_ptr<ripple::STTx const> const& txn,
745 std::shared_ptr<ripple::TxMeta const> const& meta,
746 std::uint32_t ledgerSequence,
747 uint32_t date
748);
749
750} // namespace rpc
The interface to the database used by Clio.
Definition BackendInterface.hpp:138
A simple thread-safe logger for the channel specified in the constructor.
Definition Logger.hpp:110
BaseTagDecorator const & tag() const
Getter for tag decorator.
Definition Taggable.hpp:267
This namespace contains all the RPC logic and handlers.
Definition AMMHelpers.cpp:36
std::pair< std::shared_ptr< ripple::STTx const >, std::shared_ptr< ripple::STObject const > > deserializeTxPlusMeta(data::TransactionAndMetadata const &blobs)
Deserialize a TransactionAndMetadata into a pair of STTx and STObject.
Definition RPCHelpers.cpp:207
std::uint64_t getStartHint(ripple::SLE const &sle, ripple::AccountID const &accountID)
Get the start hint for the account.
Definition RPCHelpers.cpp:567
ripple::Issue parseIssue(boost::json::object const &issue)
Parse the json object into a ripple::Issue object.
Definition RPCHelpers.cpp:1320
void logDuration(web::Context const &ctx, T const &dur)
Log the duration of the request processing.
Definition RPCHelpers.hpp:658
bool insertMPTIssuanceID(boost::json::object &metaJson, std::shared_ptr< ripple::STTx const > const &txn, std::shared_ptr< ripple::TxMeta const > const &meta)
Add "mpt_issuance_id" into MPTokenIssuanceCreate transaction json.
Definition RPCHelpers.cpp:362
bool isFrozen(BackendInterface const &backend, std::uint32_t sequence, ripple::AccountID const &account, ripple::Currency const &currency, ripple::AccountID const &issuer, boost::asio::yield_context yield)
Whether the account is frozen.
Definition RPCHelpers.cpp:903
boost::json::array postProcessOrderBook(std::vector< data::LedgerObject > const &offers, ripple::Book const &book, ripple::AccountID const &takerID, data::BackendInterface const &backend, std::uint32_t const ledgerSequence, boost::asio::yield_context yield)
Post process an order book.
Definition RPCHelpers.cpp:1062
bool insertDeliveredAmount(boost::json::object &metaJson, std::shared_ptr< ripple::STTx const > const &txn, std::shared_ptr< ripple::TxMeta const > const &meta, uint32_t date)
Add "DeliveredAmount" to the transaction json object.
Definition RPCHelpers.cpp:301
boost::json::object toJsonWithBinaryTx(data::TransactionAndMetadata const &txnPlusMeta, std::uint32_t const apiVersion)
Convert a TransactionAndMetadata to JSON object containing tx and metadata data in hex format....
Definition RPCHelpers.cpp:1386
std::optional< AccountCursor > parseAccountCursor(std::optional< std::string > jsonCursor)
Parse the account cursor from the JSON.
Definition RPCHelpers.cpp:110
std::variant< Status, ripple::Book > parseBook(ripple::Currency pays, ripple::AccountID payIssuer, ripple::Currency gets, ripple::AccountID getIssuer)
Parse the book from the request.
Definition RPCHelpers.cpp:1168
std::vector< ripple::AccountID > getAccountsFromTransaction(boost::json::object const &transaction)
Get the account associated with a transaction.
Definition RPCHelpers.cpp:861
std::variant< Status, ripple::AccountID > parseTaker(boost::json::value const &taker)
Parse the taker from the request.
Definition RPCHelpers.cpp:1306
ripple::STAmount accountFunds(BackendInterface const &backend, std::uint32_t const sequence, ripple::STAmount const &amount, ripple::AccountID const &id, boost::asio::yield_context yield)
Get the account funds.
Definition RPCHelpers.cpp:982
std::optional< std::string > encodeCTID(uint32_t ledgerSeq, uint16_t txnIndex, uint16_t networkId) noexcept
Encode CTID as string.
Definition RPCHelpers.cpp:287
boost::json::object generatePubLedgerMessage(ripple::LedgerHeader const &lgrInfo, ripple::Fees const &fees, std::string const &ledgerRange, std::uint32_t txnCount)
Generate a JSON object to publish ledger message.
std::optional< std::tuple< uint32_t, uint16_t, uint16_t > > decodeCTID(T const ctid) noexcept
Decode the CTID from a string or a uint64_t.
Definition RPCHelpers.hpp:614
std::variant< Status, ripple::LedgerHeader > getLedgerHeaderFromHashOrSeq(BackendInterface const &backend, boost::asio::yield_context yield, std::optional< std::string > ledgerHash, std::optional< uint32_t > ledgerIndex, uint32_t maxSeq)
Get ledger info from hash or sequence.
Definition RPCHelpers.cpp:516
bool isOwnedByAccount(ripple::SLE const &sle, ripple::AccountID const &accountID)
Check whether the SLE is owned by the account.
std::pair< boost::json::object, boost::json::object > toExpandedJson(data::TransactionAndMetadata const &blobs, std::uint32_t const apiVersion, NFTokenjson nftEnabled, std::optional< uint16_t > networkId)
Convert a TransactionAndMetadata to two JSON objects.
Definition RPCHelpers.cpp:251
std::optional< ripple::AccountID > accountFromStringStrict(std::string const &account)
Get a ripple::AccountID from its string representation.
Definition RPCHelpers.cpp:185
boost::json::object toJson(ripple::STBase const &obj)
Convert STBase object to JSON.
Definition RPCHelpers.cpp:243
std::variant< Status, ripple::LedgerHeader > ledgerHeaderFromRequest(std::shared_ptr< data::BackendInterface const > const &backend, web::Context const &ctx)
Get ledger info from the request.
Definition RPCHelpers.cpp:465
ripple::XRPAmount xrpLiquid(BackendInterface const &backend, std::uint32_t sequence, ripple::AccountID const &id, boost::asio::yield_context yield)
Get the XRP liquidity.
Definition RPCHelpers.cpp:947
std::variant< ripple::uint256, Status > getNFTID(boost::json::object const &request)
Get the NFTID from the request.
Definition RPCHelpers.cpp:1370
bool canHaveDeliveredAmount(std::shared_ptr< ripple::STTx const > const &txn, std::shared_ptr< ripple::TxMeta const > const &meta)
Whether the transaction can have a delivered amount.
Definition RPCHelpers.cpp:169
std::shared_ptr< ripple::SLE const > read(std::shared_ptr< data::BackendInterface const > const &backend, ripple::Keylet const &keylet, ripple::LedgerHeader const &lgrInfo, web::Context const &context)
Read SLE from the backend.
Definition RPCHelpers.cpp:826
NFTokenjson
Enum for NFT json manipulation.
Definition RPCHelpers.hpp:80
std::optional< ripple::Seed > parseRippleLibSeed(boost::json::value const &value)
Parse a ripple-lib seed.
Definition RPCHelpers.cpp:841
void insertDeliverMaxAlias(boost::json::object &txJson, std::uint32_t const apiVersion)
Add "DeliverMax" which is the alias of "Amount" for "Payment" transaction to transaction json....
Definition RPCHelpers.cpp:381
bool specifiesCurrentOrClosedLedger(boost::json::object const &request)
Check whethe the request specifies the current or closed ledger.
Definition RPCHelpers.cpp:1332
std::optional< ripple::STAmount > getDeliveredAmount(std::shared_ptr< ripple::STTx const > const &txn, std::shared_ptr< ripple::TxMeta const > const &meta, std::uint32_t const ledgerSequence, uint32_t date)
Get the delivered amount.
Definition RPCHelpers.cpp:141
ripple::Rate transferRate(BackendInterface const &backend, std::uint32_t sequence, ripple::AccountID const &issuer, boost::asio::yield_context yield)
Get the transfer rate.
Definition RPCHelpers.cpp:1040
ripple::STAmount accountHolds(BackendInterface const &backend, std::uint32_t sequence, ripple::AccountID const &account, ripple::Currency const &currency, ripple::AccountID const &issuer, bool const zeroIfFrozen, boost::asio::yield_context yield)
Get the amount that an account holds.
Definition RPCHelpers.cpp:998
bool isGlobalFrozen(BackendInterface const &backend, std::uint32_t sequence, ripple::AccountID const &issuer, boost::asio::yield_context yield)
Whether global frozen is set.
Definition RPCHelpers.cpp:880
boost::json::value toBoostJson(Json::Value const &value)
Convert a RippledJson to boost::json::value.
Definition RPCHelpers.cpp:400
std::variant< Status, AccountCursor > traverseOwnedNodes(BackendInterface const &backend, ripple::AccountID const &accountID, std::uint32_t sequence, std::uint32_t limit, std::optional< std::string > jsonCursor, boost::asio::yield_context yield, std::function< void(ripple::SLE)> atOwnedNode, bool nftIncluded)
Traverse nodes owned by an account.
Definition RPCHelpers.cpp:639
std::variant< Status, AccountCursor > traverseNFTObjects(BackendInterface const &backend, std::uint32_t sequence, ripple::AccountID const &accountID, ripple::uint256 nextPage, std::uint32_t limit, boost::asio::yield_context yield, std::function< void(ripple::SLE)> atOwnedNode)
Traverse NFT objects and call the callback for each owned node.
Definition RPCHelpers.cpp:587
std::optional< std::uint32_t > parseStringAsUInt(std::string const &value)
Parse the string as a uint32_t.
Definition RPCHelpers.cpp:452
bool isAdminCmd(std::string const &method, boost::json::object const &request)
Check whether a request requires administrative privileges on rippled side.
Definition RPCHelpers.cpp:1345
std::vector< unsigned char > ledgerHeaderToBlob(ripple::LedgerHeader const &info, bool includeHash)
Convert a ledger header to a blob.
Definition RPCHelpers.cpp:549
boost::json::object removeSecret(boost::json::object const &object)
Removes any detected secret information from a response JSON object.
Definition JsonUtils.hpp:67
Represents a transaction and its metadata bundled together.
Definition Types.hpp:68
Context that is used by the Webserver to pass around information about an incoming request.
Definition Context.hpp:40