Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
BackendInterface.hpp
1#pragma once
2
3#include "data/DBHelpers.hpp"
4#include "data/LedgerCacheInterface.hpp"
5#include "data/Types.hpp"
6#include "etl/CorruptionDetector.hpp"
7#include "util/Spawn.hpp"
8#include "util/log/Logger.hpp"
9
10#include <boost/asio/executor_work_guard.hpp>
11#include <boost/asio/io_context.hpp>
12#include <boost/asio/spawn.hpp>
13#include <boost/json.hpp>
14#include <boost/json/object.hpp>
15#include <boost/utility/result_of.hpp>
16#include <boost/uuid/uuid.hpp>
17#include <xrpl/basics/base_uint.h>
18#include <xrpl/protocol/AccountID.h>
19#include <xrpl/protocol/Fees.h>
20#include <xrpl/protocol/LedgerHeader.h>
21
22#include <chrono>
23#include <cstddef>
24#include <cstdint>
25#include <exception>
26#include <functional>
27#include <optional>
28#include <shared_mutex>
29#include <string>
30#include <thread>
31#include <type_traits>
32#include <utility>
33#include <vector>
34
35namespace data {
36
40class DatabaseTimeout : public std::exception {
41public:
45 [[nodiscard]] char const*
46 what() const throw() override
47 {
48 return "Database read timed out. Please retry the request";
49 }
50};
51
52static constexpr std::size_t kDefaultWaitBetweenRetry = 500;
61template <typename FnType>
62auto
63retryOnTimeout(FnType func, size_t waitMs = kDefaultWaitBetweenRetry)
64{
65 static util::Logger const log{"Backend"}; // NOLINT(readability-identifier-naming)
66
67 while (true) {
68 try {
69 return func();
70 } catch (DatabaseTimeout const&) {
71 LOG(log.error()) << "Database request timed out. Sleeping and retrying ... ";
72 std::this_thread::sleep_for(std::chrono::milliseconds(waitMs));
73 }
74 }
75}
76
84template <typename FnType>
85auto
86synchronous(FnType&& func)
87{
88 boost::asio::io_context ctx;
89
90 using R = boost::result_of<FnType(boost::asio::yield_context)>::type;
91 if constexpr (!std::is_same_v<R, void>) {
92 R res;
93 util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func, &res](auto yield) {
94 res = func(yield);
95 });
96
97 ctx.run();
98 return res;
99 } else {
100 util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) {
101 func(yield);
102 });
103 ctx.run();
104 }
105}
106
115template <typename FnType>
116auto
118{
119 return retryOnTimeout([&]() { return synchronous(func); });
120}
121
126protected:
127 util::Logger log_{"Backend"};
128 mutable std::shared_mutex rngMtx_;
129 std::optional<LedgerRange> range_;
130 std::reference_wrapper<LedgerCacheInterface> cache_;
131 std::optional<etl::CorruptionDetector> corruptionDetector_;
132
133public:
142 virtual ~BackendInterface() = default;
143
144 // TODO https://github.com/XRPLF/clio/issues/1956: Remove this hack once old ETL is removed.
145 // Cache should not be exposed thru BackendInterface
146
151 cache() const
152 {
153 return cache_;
154 }
155
161 {
162 return cache_;
163 }
164
170 void
172 {
173 corruptionDetector_ = std::move(detector);
174 }
175
183 virtual std::optional<xrpl::LedgerHeader>
184 fetchLedgerBySequence(std::uint32_t sequence, boost::asio::yield_context yield) const = 0;
185
193 virtual std::optional<xrpl::LedgerHeader>
194 fetchLedgerByHash(xrpl::uint256 const& hash, boost::asio::yield_context yield) const = 0;
195
202 virtual std::optional<std::uint32_t>
203 fetchLatestLedgerSequence(boost::asio::yield_context yield) const = 0;
204
210 std::optional<LedgerRange>
211 fetchLedgerRange() const;
212
223 virtual std::vector<xrpl::uint256>
225 std::uint32_t number,
226 std::uint32_t pageSize,
227 std::uint32_t seq,
228 boost::asio::yield_context yield
229 ) const = 0;
230
236 void
237 updateRange(uint32_t newMax);
238
245 void
246 forceUpdateRange(uint32_t newMax);
247
255 void
256 setRange(uint32_t min, uint32_t max, bool force = false);
257
265 std::optional<xrpl::Fees>
266 fetchFees(std::uint32_t seq, boost::asio::yield_context yield) const;
267
275 virtual std::optional<TransactionAndMetadata>
276 fetchTransaction(xrpl::uint256 const& hash, boost::asio::yield_context yield) const = 0;
277
285 virtual std::vector<TransactionAndMetadata>
287 std::vector<xrpl::uint256> const& hashes,
288 boost::asio::yield_context yield
289 ) const = 0;
290
303 xrpl::AccountID const& account,
304 std::uint32_t limit,
305 bool forward,
306 std::optional<TransactionsCursor> const& txnCursor,
307 boost::asio::yield_context yield
308 ) const = 0;
309
317 virtual std::vector<TransactionAndMetadata>
319 std::uint32_t ledgerSequence,
320 boost::asio::yield_context yield
321 ) const = 0;
322
330 virtual std::vector<xrpl::uint256>
332 std::uint32_t ledgerSequence,
333 boost::asio::yield_context yield
334 ) const = 0;
335
344 virtual std::optional<NFT>
346 xrpl::uint256 const& tokenID,
347 std::uint32_t ledgerSequence,
348 boost::asio::yield_context yield
349 ) const = 0;
350
363 xrpl::uint256 const& tokenID,
364 std::uint32_t limit,
365 bool forward,
366 std::optional<TransactionsCursor> const& cursorIn,
367 boost::asio::yield_context yield
368 ) const = 0;
369
382 virtual NFTsAndCursor
384 xrpl::AccountID const& issuer,
385 std::optional<std::uint32_t> const& taxon,
386 std::uint32_t ledgerSequence,
387 std::uint32_t limit,
388 std::optional<xrpl::uint256> const& cursorIn,
389 boost::asio::yield_context yield
390 ) const = 0;
391
402 virtual MPTHoldersAndCursor
404 xrpl::uint192 const& mptID,
405 std::uint32_t const limit,
406 std::optional<xrpl::AccountID> const& cursorIn,
407 std::uint32_t const ledgerSequence,
408 boost::asio::yield_context yield
409 ) const = 0;
410
429 xrpl::uint192 const& mptIssuanceID,
430 std::uint32_t limit,
431 bool forward,
432 std::optional<TransactionsCursor> const& cursorIn,
433 boost::asio::yield_context yield
434 ) const = 0;
435
457 xrpl::uint192 const& mptIssuanceID,
458 xrpl::AccountID const& account,
459 std::uint32_t limit,
460 bool forward,
461 std::optional<TransactionsCursor> const& cursorIn,
462 boost::asio::yield_context yield
463 ) const = 0;
464
476 std::optional<Blob>
478 xrpl::uint256 const& key,
479 std::uint32_t sequence,
480 boost::asio::yield_context yield
481 ) const;
482
493 std::optional<std::uint32_t>
495 xrpl::uint256 const& key,
496 std::uint32_t sequence,
497 boost::asio::yield_context yield
498 ) const;
499
512 std::vector<Blob>
514 std::vector<xrpl::uint256> const& keys,
515 std::uint32_t sequence,
516 boost::asio::yield_context yield
517 ) const;
518
527 virtual std::optional<Blob>
529 xrpl::uint256 const& key,
530 std::uint32_t sequence,
531 boost::asio::yield_context yield
532 ) const = 0;
533
542 virtual std::optional<std::uint32_t>
544 xrpl::uint256 const& key,
545 std::uint32_t sequence,
546 boost::asio::yield_context yield
547 ) const = 0;
548
557 virtual std::vector<Blob>
559 std::vector<xrpl::uint256> const& keys,
560 std::uint32_t sequence,
561 boost::asio::yield_context yield
562 ) const = 0;
563
571 virtual std::vector<LedgerObject>
572 fetchLedgerDiff(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
573
586 std::optional<xrpl::uint256> const& cursor,
587 std::uint32_t ledgerSequence,
588 std::uint32_t limit,
589 bool outOfOrder,
590 boost::asio::yield_context yield
591 );
592
601 std::optional<LedgerObject>
603 xrpl::uint256 key,
604 std::uint32_t ledgerSequence,
605 boost::asio::yield_context yield
606 ) const;
607
620 std::optional<xrpl::uint256>
622 xrpl::uint256 key,
623 std::uint32_t ledgerSequence,
624 boost::asio::yield_context yield
625 ) const;
626
635 virtual std::optional<xrpl::uint256>
637 xrpl::uint256 key,
638 std::uint32_t ledgerSequence,
639 boost::asio::yield_context yield
640 ) const = 0;
641
653 xrpl::uint256 const& book,
654 std::uint32_t ledgerSequence,
655 std::uint32_t limit,
656 boost::asio::yield_context yield
657 ) const;
658
666 virtual std::optional<std::string>
668 std::string const& migratorName,
669 boost::asio::yield_context yield
670 ) const = 0;
671
676 std::expected<std::vector<std::pair<boost::uuids::uuid, std::string>>, std::string>;
677
684 [[nodiscard]] virtual ClioNodesDataFetchResult
685 fetchClioNodesData(boost::asio::yield_context yield) const = 0;
686
695 std::optional<LedgerRange>
696 hardFetchLedgerRange() const;
697
704 virtual std::optional<LedgerRange>
705 hardFetchLedgerRange(boost::asio::yield_context yield) const = 0;
706
712 std::optional<LedgerRange>
714
721 virtual void
722 writeLedger(xrpl::LedgerHeader const& ledgerHeader, std::string&& blob) = 0;
723
731 virtual void
732 writeLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob);
733
743 virtual void
745 std::string&& hash,
746 std::uint32_t seq,
747 std::uint32_t date,
748 std::string&& transaction,
749 std::string&& metadata
750 ) = 0;
751
757 virtual void
758 writeNFTs(std::vector<NFTsData> const& data) = 0;
759
765 virtual void
766 writeAccountTransactions(std::vector<AccountTransactionsData> data) = 0;
767
773 virtual void
775
781 virtual void
782 writeNFTTransactions(std::vector<NFTTransactionsData> const& data) = 0;
783
790 virtual void
791 writeMPTokenIssuanceTransactions(std::vector<MPTokenIssuanceTransactionsData> const& data) = 0;
792
801 virtual void
803 std::vector<MPTokenIssuanceTransactionsData> const& data
804 ) = 0;
805
811 virtual void
812 writeMPTHolders(std::vector<MPTHolderData> const& data) = 0;
813
821 virtual void
822 writeSuccessor(std::string&& key, std::uint32_t seq, std::string&& successor) = 0;
823
830 virtual void
831 writeNodeMessage(boost::uuids::uuid const& uuid, std::string message) = 0;
832
838 virtual void
839 startWrites() const = 0;
840
849 bool
850 finishWrites(std::uint32_t ledgerSequence);
851
855 virtual void
857
864 virtual void
865 writeMigratorStatus(std::string const& migratorName, std::string const& status) = 0;
866
870 virtual bool
871 isTooBusy() const = 0;
872
876 virtual boost::json::object
877 stats() const = 0;
878
879private:
887 virtual void
888 doWriteLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob) = 0;
889
895 virtual bool
896 doFinishWrites() = 0;
897
898 void
899 updateRangeImpl(uint32_t newMax);
900};
901
902} // namespace data
903using BackendInterface = data::BackendInterface;
The interface to the database used by Clio.
Definition BackendInterface.hpp:125
virtual MPTHoldersAndCursor fetchMPTHolders(xrpl::uint192 const &mptID, std::uint32_t const limit, std::optional< xrpl::AccountID > const &cursorIn, std::uint32_t const ledgerSequence, boost::asio::yield_context yield) const =0
Fetches all holders' balances for a MPTIssuanceID.
virtual std::vector< TransactionAndMetadata > fetchTransactions(std::vector< xrpl::uint256 > const &hashes, boost::asio::yield_context yield) const =0
Fetches multiple transactions.
std::optional< LedgerObject > fetchSuccessorObject(xrpl::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const
Fetches the successor object.
Definition BackendInterface.cpp:146
std::optional< std::uint32_t > fetchLedgerObjectSeq(xrpl::uint256 const &key, std::uint32_t sequence, boost::asio::yield_context yield) const
Fetches a specific ledger object sequence.
Definition BackendInterface.cpp:82
virtual std::vector< TransactionAndMetadata > fetchAllTransactionsInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Fetches all transactions from a specific ledger.
virtual void writeNodeMessage(boost::uuids::uuid const &uuid, std::string message)=0
Write a node message. Used by ClusterCommunicationService.
virtual bool isTooBusy() const =0
virtual ClioNodesDataFetchResult fetchClioNodesData(boost::asio::yield_context yield) const =0
Fetches the data of all nodes in the cluster.
void forceUpdateRange(uint32_t newMax)
Updates the range of sequences that are stored in the DB without any checks.
Definition BackendInterface.cpp:277
virtual std::optional< xrpl::LedgerHeader > fetchLedgerByHash(xrpl::uint256 const &hash, boost::asio::yield_context yield) const =0
Fetches a specific ledger by hash.
std::expected< std::vector< std::pair< boost::uuids::uuid, std::string > >, std::string > ClioNodesDataFetchResult
Return type for fetchClioNodesData() method.
Definition BackendInterface.hpp:675
virtual void writeNFTs(std::vector< NFTsData > const &data)=0
Writes NFTs to the database.
virtual std::optional< std::uint32_t > doFetchLedgerObjectSeq(xrpl::uint256 const &key, std::uint32_t sequence, boost::asio::yield_context yield) const =0
The database-specific implementation for fetching a ledger object sequence.
void setRange(uint32_t min, uint32_t max, bool force=false)
Sets the range of sequences that are stored in the DB.
Definition BackendInterface.cpp:284
LedgerCacheInterface & cache()
Definition BackendInterface.hpp:160
virtual std::optional< xrpl::LedgerHeader > fetchLedgerBySequence(std::uint32_t sequence, boost::asio::yield_context yield) const =0
Fetches a specific ledger by sequence number.
virtual std::optional< NFT > fetchNFT(xrpl::uint256 const &tokenID, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Fetches a specific NFT.
virtual void startWrites() const =0
Starts a write transaction with the DB. No-op for cassandra.
virtual TransactionsAndCursor fetchNFTTransactions(xrpl::uint256 const &tokenID, std::uint32_t limit, bool forward, std::optional< TransactionsCursor > const &cursorIn, boost::asio::yield_context yield) const =0
Fetches all transactions for a specific NFT.
std::optional< xrpl::uint256 > fetchSuccessorKey(xrpl::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const
Fetches the successor key.
Definition BackendInterface.cpp:130
virtual void writeLedger(xrpl::LedgerHeader const &ledgerHeader, std::string &&blob)=0
Writes to a specific ledger.
std::optional< Blob > fetchLedgerObject(xrpl::uint256 const &key, std::uint32_t sequence, boost::asio::yield_context yield) const
Fetches a specific ledger object.
Definition BackendInterface.cpp:60
virtual TransactionsAndCursor fetchMPTokenIssuanceTransactions(xrpl::uint192 const &mptIssuanceID, std::uint32_t limit, bool forward, std::optional< TransactionsCursor > const &cursorIn, boost::asio::yield_context yield) const =0
Fetches transactions for a particular MPTokenIssuance ID.
std::optional< xrpl::Fees > fetchFees(std::uint32_t seq, boost::asio::yield_context yield) const
Fetch the fees from a specific ledger sequence.
Definition BackendInterface.cpp:352
virtual std::optional< LedgerRange > hardFetchLedgerRange(boost::asio::yield_context yield) const =0
Fetches the ledger range from DB.
virtual void writeLedgerObject(std::string &&key, std::uint32_t seq, std::string &&blob)
Writes a new ledger object.
Definition BackendInterface.cpp:46
virtual void writeSuccessor(std::string &&key, std::uint32_t seq, std::string &&successor)=0
Write a new successor.
virtual TransactionsAndCursor fetchAccountTransactions(xrpl::AccountID const &account, std::uint32_t limit, bool forward, std::optional< TransactionsCursor > const &txnCursor, boost::asio::yield_context yield) const =0
Fetches all transactions for a specific account.
virtual std::optional< std::string > fetchMigratorStatus(std::string const &migratorName, boost::asio::yield_context yield) const =0
Fetches the status of migrator by name.
virtual void waitForWritesToFinish()=0
Wait for all pending writes to finish.
std::optional< LedgerRange > hardFetchLedgerRange() const
Synchronously fetches the ledger range from DB.
Definition BackendInterface.cpp:245
BackendInterface(LedgerCacheInterface &cache)
Construct a new backend interface instance.
Definition BackendInterface.hpp:139
virtual void writeAccountTransaction(AccountTransactionsData record)=0
Write a new account transaction.
std::optional< LedgerRange > hardFetchLedgerRangeNoThrow() const
Fetches the ledger range from DB retrying until no DatabaseTimeout is thrown.
Definition BackendInterface.cpp:53
virtual void writeNFTTransactions(std::vector< NFTTransactionsData > const &data)=0
Write NFTs transactions.
std::optional< LedgerRange > fetchLedgerRange() const
Fetch the current ledger range.
Definition BackendInterface.cpp:251
virtual void writeTransaction(std::string &&hash, std::uint32_t seq, std::uint32_t date, std::string &&transaction, std::string &&metadata)=0
Writes a new transaction.
bool finishWrites(std::uint32_t ledgerSequence)
Tells database we finished writing all data for a specific ledger.
Definition BackendInterface.cpp:35
virtual boost::json::object stats() const =0
virtual TransactionsAndCursor fetchAccountMPTokenIssuanceTransactions(xrpl::uint192 const &mptIssuanceID, xrpl::AccountID const &account, std::uint32_t limit, bool forward, std::optional< TransactionsCursor > const &cursorIn, boost::asio::yield_context yield) const =0
Fetches transactions for a particular MPTokenIssuance ID involving a particular account.
void setCorruptionDetector(etl::CorruptionDetector detector)
Sets the corruption detector.
Definition BackendInterface.hpp:171
virtual std::optional< std::uint32_t > fetchLatestLedgerSequence(boost::asio::yield_context yield) const =0
Fetches the latest ledger sequence.
virtual std::vector< xrpl::uint256 > fetchAccountRoots(std::uint32_t number, std::uint32_t pageSize, std::uint32_t seq, boost::asio::yield_context yield) const =0
Fetch the specified number of account root object indexes by page, the accounts need to exist for seq...
virtual void writeAccountTransactions(std::vector< AccountTransactionsData > data)=0
Write a new set of account transactions.
virtual std::vector< Blob > doFetchLedgerObjects(std::vector< xrpl::uint256 > const &keys, std::uint32_t sequence, boost::asio::yield_context yield) const =0
The database-specific implementation for fetching ledger objects.
virtual void writeMigratorStatus(std::string const &migratorName, std::string const &status)=0
Mark the migration status of a migrator as Migrated in the database.
virtual void writeMPTHolders(std::vector< MPTHolderData > const &data)=0
Write accounts that started holding onto a MPT.
virtual std::vector< LedgerObject > fetchLedgerDiff(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Returns the difference between ledgers.
virtual void writeAccountMPTokenIssuanceTransactions(std::vector< MPTokenIssuanceTransactionsData > const &data)=0
Write MPTokenIssuance transaction index rows to the account_mptoken_issuance_transactions table.
BookOffersPage fetchBookOffers(xrpl::uint256 const &book, std::uint32_t ledgerSequence, std::uint32_t limit, boost::asio::yield_context yield) const
Fetches book offers.
Definition BackendInterface.cpp:164
virtual std::optional< Blob > doFetchLedgerObject(xrpl::uint256 const &key, std::uint32_t sequence, boost::asio::yield_context yield) const =0
The database-specific implementation for fetching a ledger object.
virtual std::vector< xrpl::uint256 > fetchAllTransactionHashesInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Fetches all transaction hashes from a specific ledger.
virtual NFTsAndCursor fetchNFTsByIssuer(xrpl::AccountID const &issuer, std::optional< std::uint32_t > const &taxon, std::uint32_t ledgerSequence, std::uint32_t limit, std::optional< xrpl::uint256 > const &cursorIn, boost::asio::yield_context yield) const =0
Fetches all NFTs issued by a given address.
std::vector< Blob > fetchLedgerObjects(std::vector< xrpl::uint256 > const &keys, std::uint32_t sequence, boost::asio::yield_context yield) const
Fetches all ledger objects by their keys.
Definition BackendInterface.cpp:95
virtual std::optional< TransactionAndMetadata > fetchTransaction(xrpl::uint256 const &hash, boost::asio::yield_context yield) const =0
Fetches a specific transaction.
void updateRange(uint32_t newMax)
Updates the range of sequences that are stored in the DB.
Definition BackendInterface.cpp:258
virtual std::optional< xrpl::uint256 > doFetchSuccessorKey(xrpl::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Database-specific implementation of fetching the successor key.
virtual void writeMPTokenIssuanceTransactions(std::vector< MPTokenIssuanceTransactionsData > const &data)=0
Write MPTokenIssuance transaction index rows to the mptoken_issuance_transactions table.
LedgerCacheInterface const & cache() const
Definition BackendInterface.hpp:151
LedgerPage fetchLedgerPage(std::optional< xrpl::uint256 > const &cursor, std::uint32_t ledgerSequence, std::uint32_t limit, bool outOfOrder, boost::asio::yield_context yield)
Fetches a page of ledger objects, ordered by key/index.
Definition BackendInterface.cpp:297
Represents a database timeout error.
Definition BackendInterface.hpp:40
char const * what() const override
Definition BackendInterface.hpp:46
Cache for an entire ledger.
Definition LedgerCacheInterface.hpp:21
A helper to notify Clio operator about a corruption in the DB.
Definition CorruptionDetector.hpp:16
A simple thread-safe logger for the channel specified in the constructor.
Definition Logger.hpp:78
Pump error(std::source_location const &loc=std::source_location::current()) const
Interface for logging at Severity::ERR severity.
Definition Logger.cpp:512
This namespace implements the data access layer and related components.
Definition AmendmentCenter.cpp:56
auto synchronous(FnType &&func)
Synchronously executes the given function object inside a coroutine.
Definition BackendInterface.hpp:86
auto synchronousAndRetryOnTimeout(FnType &&func)
Synchronously execute the given function object and retry until no DatabaseTimeout is thrown.
Definition BackendInterface.hpp:117
auto retryOnTimeout(FnType func, size_t waitMs=kDefaultWaitBetweenRetry)
A helper function that catches DatabaseTimeout exceptions and retries indefinitely.
Definition BackendInterface.hpp:63
void spawn(Ctx &&ctx, F &&func)
Spawns a coroutine using boost::asio::spawn.
Definition Spawn.hpp:53
Struct used to keep track of what to write to account_transactions/account_tx tables.
Definition DBHelpers.hpp:26
Represents a page of book offer objects.
Definition Types.hpp:41
Represents a page of LedgerObjects.
Definition Types.hpp:33
Represents an array of MPTokens.
Definition Types.hpp:235
Represents a bundle of NFTs with a cursor to the next page.
Definition Types.hpp:227
Represests a bundle of transactions with metadata and a cursor to the next page.
Definition Types.hpp:153