Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
BackendInterface.hpp
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
20#pragma once
21
22#include "data/DBHelpers.hpp"
23#include "data/LedgerCacheInterface.hpp"
24#include "data/Types.hpp"
25#include "etl/CorruptionDetector.hpp"
26#include "util/log/Logger.hpp"
27
28#include <boost/asio/executor_work_guard.hpp>
29#include <boost/asio/io_context.hpp>
30#include <boost/asio/spawn.hpp>
31#include <boost/json.hpp>
32#include <boost/json/object.hpp>
33#include <boost/utility/result_of.hpp>
34#include <boost/uuid/uuid.hpp>
35#include <xrpl/basics/base_uint.h>
36#include <xrpl/protocol/AccountID.h>
37#include <xrpl/protocol/Fees.h>
38#include <xrpl/protocol/LedgerHeader.h>
39
40#include <chrono>
41#include <cstddef>
42#include <cstdint>
43#include <exception>
44#include <functional>
45#include <optional>
46#include <shared_mutex>
47#include <string>
48#include <thread>
49#include <type_traits>
50#include <utility>
51#include <vector>
52
53namespace data {
54
58class DatabaseTimeout : public std::exception {
59public:
63 char const*
64 what() const throw() override
65 {
66 return "Database read timed out. Please retry the request";
67 }
68};
69
70static constexpr std::size_t kDEFAULT_WAIT_BETWEEN_RETRY = 500;
79template <typename FnType>
80auto
81retryOnTimeout(FnType func, size_t waitMs = kDEFAULT_WAIT_BETWEEN_RETRY)
82{
83 static util::Logger const log{"Backend"}; // NOLINT(readability-identifier-naming)
84
85 while (true) {
86 try {
87 return func();
88 } catch (DatabaseTimeout const&) {
89 LOG(log.error()) << "Database request timed out. Sleeping and retrying ... ";
90 std::this_thread::sleep_for(std::chrono::milliseconds(waitMs));
91 }
92 }
93}
94
102template <typename FnType>
103auto
104synchronous(FnType&& func)
105{
106 boost::asio::io_context ctx;
107
108 using R = typename boost::result_of<FnType(boost::asio::yield_context)>::type;
109 if constexpr (!std::is_same_v<R, void>) {
110 R res;
111 boost::asio::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func, &res](auto yield) {
112 res = func(yield);
113 });
114
115 ctx.run();
116 return res;
117 } else {
118 boost::asio::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) { func(yield); });
119 ctx.run();
120 }
121}
122
130template <typename FnType>
131auto
133{
134 return retryOnTimeout([&]() { return synchronous(func); });
135}
136
141protected:
142 mutable std::shared_mutex rngMtx_;
143 std::optional<LedgerRange> range_;
144 std::reference_wrapper<LedgerCacheInterface> cache_;
145 std::optional<etl::CorruptionDetector> corruptionDetector_;
146
147public:
156 virtual ~BackendInterface() = default;
157
158 // TODO https://github.com/XRPLF/clio/issues/1956: Remove this hack once old ETL is removed.
159 // Cache should not be exposed thru BackendInterface
160
165 cache() const
166 {
167 return cache_;
168 }
169
175 {
176 return cache_;
177 }
178
184 void
186 {
187 corruptionDetector_ = std::move(detector);
188 }
189
197 virtual std::optional<ripple::LedgerHeader>
198 fetchLedgerBySequence(std::uint32_t sequence, boost::asio::yield_context yield) const = 0;
199
207 virtual std::optional<ripple::LedgerHeader>
208 fetchLedgerByHash(ripple::uint256 const& hash, boost::asio::yield_context yield) const = 0;
209
216 virtual std::optional<std::uint32_t>
217 fetchLatestLedgerSequence(boost::asio::yield_context yield) const = 0;
218
224 std::optional<LedgerRange>
225 fetchLedgerRange() const;
226
236 virtual std::vector<ripple::uint256>
237 fetchAccountRoots(std::uint32_t number, std::uint32_t pageSize, std::uint32_t seq, boost::asio::yield_context yield)
238 const = 0;
239
245 void
246 updateRange(uint32_t newMax);
247
255 void
256 setRange(uint32_t min, uint32_t max, bool force = false);
257
265 std::optional<ripple::Fees>
266 fetchFees(std::uint32_t seq, boost::asio::yield_context yield) const;
267
275 virtual std::optional<TransactionAndMetadata>
276 fetchTransaction(ripple::uint256 const& hash, boost::asio::yield_context yield) const = 0;
277
285 virtual std::vector<TransactionAndMetadata>
286 fetchTransactions(std::vector<ripple::uint256> const& hashes, boost::asio::yield_context yield) const = 0;
287
300 ripple::AccountID const& account,
301 std::uint32_t limit,
302 bool forward,
303 std::optional<TransactionsCursor> const& cursor,
304 boost::asio::yield_context yield
305 ) const = 0;
306
314 virtual std::vector<TransactionAndMetadata>
315 fetchAllTransactionsInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
316
324 virtual std::vector<ripple::uint256>
325 fetchAllTransactionHashesInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
326
335 virtual std::optional<NFT>
336 fetchNFT(ripple::uint256 const& tokenID, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
337
350 ripple::uint256 const& tokenID,
351 std::uint32_t limit,
352 bool forward,
353 std::optional<TransactionsCursor> const& cursorIn,
354 boost::asio::yield_context yield
355 ) const = 0;
356
368 virtual NFTsAndCursor
370 ripple::AccountID const& issuer,
371 std::optional<std::uint32_t> const& taxon,
372 std::uint32_t ledgerSequence,
373 std::uint32_t limit,
374 std::optional<ripple::uint256> const& cursorIn,
375 boost::asio::yield_context yield
376 ) const = 0;
377
388 virtual MPTHoldersAndCursor
390 ripple::uint192 const& mptID,
391 std::uint32_t const limit,
392 std::optional<ripple::AccountID> const& cursorIn,
393 std::uint32_t const ledgerSequence,
394 boost::asio::yield_context yield
395 ) const = 0;
396
408 std::optional<Blob>
409 fetchLedgerObject(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const;
410
421 std::optional<std::uint32_t>
422 fetchLedgerObjectSeq(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const;
423
435 std::vector<Blob>
437 std::vector<ripple::uint256> const& keys,
438 std::uint32_t sequence,
439 boost::asio::yield_context yield
440 ) const;
441
450 virtual std::optional<Blob>
451 doFetchLedgerObject(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const = 0;
452
461 virtual std::optional<std::uint32_t>
462 doFetchLedgerObjectSeq(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield)
463 const = 0;
464
473 virtual std::vector<Blob>
475 std::vector<ripple::uint256> const& keys,
476 std::uint32_t sequence,
477 boost::asio::yield_context yield
478 ) const = 0;
479
487 virtual std::vector<LedgerObject>
488 fetchLedgerDiff(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
489
502 std::optional<ripple::uint256> const& cursor,
503 std::uint32_t ledgerSequence,
504 std::uint32_t limit,
505 bool outOfOrder,
506 boost::asio::yield_context yield
507 );
508
517 std::optional<LedgerObject>
518 fetchSuccessorObject(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const;
519
531 std::optional<ripple::uint256>
532 fetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const;
533
542 virtual std::optional<ripple::uint256>
543 doFetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
544
556 ripple::uint256 const& book,
557 std::uint32_t ledgerSequence,
558 std::uint32_t limit,
559 boost::asio::yield_context yield
560 ) const;
561
569 virtual std::optional<std::string>
570 fetchMigratorStatus(std::string const& migratorName, boost::asio::yield_context yield) const = 0;
571
578 [[nodiscard]] virtual std::expected<std::vector<std::pair<boost::uuids::uuid, std::string>>, std::string>
579 fetchClioNodesData(boost::asio::yield_context yield) const = 0;
580
588 std::optional<LedgerRange>
589 hardFetchLedgerRange() const;
590
597 virtual std::optional<LedgerRange>
598 hardFetchLedgerRange(boost::asio::yield_context yield) const = 0;
599
605 std::optional<LedgerRange>
607
614 virtual void
615 writeLedger(ripple::LedgerHeader const& ledgerHeader, std::string&& blob) = 0;
616
624 virtual void
625 writeLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob);
626
636 virtual void
638 std::string&& hash,
639 std::uint32_t seq,
640 std::uint32_t date,
641 std::string&& transaction,
642 std::string&& metadata
643 ) = 0;
644
650 virtual void
651 writeNFTs(std::vector<NFTsData> const& data) = 0;
652
658 virtual void
659 writeAccountTransactions(std::vector<AccountTransactionsData> data) = 0;
660
666 virtual void
668
674 virtual void
675 writeNFTTransactions(std::vector<NFTTransactionsData> const& data) = 0;
676
682 virtual void
683 writeMPTHolders(std::vector<MPTHolderData> const& data) = 0;
684
692 virtual void
693 writeSuccessor(std::string&& key, std::uint32_t seq, std::string&& successor) = 0;
694
701 virtual void
702 writeNodeMessage(boost::uuids::uuid const& uuid, std::string message) = 0;
703
709 virtual void
710 startWrites() const = 0;
711
720 bool
721 finishWrites(std::uint32_t ledgerSequence);
722
726 virtual void
728
735 virtual void
736 writeMigratorStatus(std::string const& migratorName, std::string const& status) = 0;
737
741 virtual bool
742 isTooBusy() const = 0;
743
747 virtual boost::json::object
748 stats() const = 0;
749
750private:
758 virtual void
759 doWriteLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob) = 0;
760
766 virtual bool
767 doFinishWrites() = 0;
768};
769
770} // namespace data
The interface to the database used by Clio.
Definition BackendInterface.hpp:140
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.
std::optional< ripple::Fees > fetchFees(std::uint32_t seq, boost::asio::yield_context yield) const
Fetch the fees from a specific ledger sequence.
Definition BackendInterface.cpp:360
virtual std::vector< ripple::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 bool isTooBusy() const =0
virtual void writeNFTs(std::vector< NFTsData > const &data)=0
Writes NFTs to the database.
std::vector< Blob > fetchLedgerObjects(std::vector< ripple::uint256 > const &keys, std::uint32_t sequence, boost::asio::yield_context yield) const
Fetches all ledger objects by their keys.
Definition BackendInterface.cpp:119
virtual std::optional< TransactionAndMetadata > fetchTransaction(ripple::uint256 const &hash, boost::asio::yield_context yield) const =0
Fetches a specific transaction.
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:293
LedgerCacheInterface & cache()
Definition BackendInterface.hpp:174
std::optional< LedgerObject > fetchSuccessorObject(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const
Fetches the successor object.
Definition BackendInterface.cpp:169
virtual std::vector< Blob > doFetchLedgerObjects(std::vector< ripple::uint256 > const &keys, std::uint32_t sequence, boost::asio::yield_context yield) const =0
The database-specific implementation for fetching ledger objects.
virtual void startWrites() const =0
Starts a write transaction with the DB. No-op for cassandra.
virtual std::vector< ripple::uint256 > fetchAllTransactionHashesInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Fetches all transaction hashes from a specific ledger.
std::optional< std::uint32_t > fetchLedgerObjectSeq(ripple::uint256 const &key, std::uint32_t sequence, boost::asio::yield_context yield) const
Fetches a specific ledger object sequence.
Definition BackendInterface.cpp:106
BookOffersPage fetchBookOffers(ripple::uint256 const &book, std::uint32_t ledgerSequence, std::uint32_t limit, boost::asio::yield_context yield) const
Fetches book offers.
Definition BackendInterface.cpp:187
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:70
virtual void writeSuccessor(std::string &&key, std::uint32_t seq, std::string &&successor)=0
Write a new successor.
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:261
BackendInterface(LedgerCacheInterface &cache)
Construct a new backend interface instance.
Definition BackendInterface.hpp:153
virtual std::vector< TransactionAndMetadata > fetchTransactions(std::vector< ripple::uint256 > const &hashes, boost::asio::yield_context yield) const =0
Fetches multiple transactions.
virtual void writeAccountTransaction(AccountTransactionsData record)=0
Write a new account transaction.
virtual NFTsAndCursor fetchNFTsByIssuer(ripple::AccountID const &issuer, std::optional< std::uint32_t > const &taxon, std::uint32_t ledgerSequence, std::uint32_t limit, std::optional< ripple::uint256 > const &cursorIn, boost::asio::yield_context yield) const =0
Fetches all NFTs issued by a given address.
virtual std::optional< ripple::LedgerHeader > fetchLedgerBySequence(std::uint32_t sequence, boost::asio::yield_context yield) const =0
Fetches a specific ledger by sequence number.
virtual std::optional< Blob > doFetchLedgerObject(ripple::uint256 const &key, std::uint32_t sequence, boost::asio::yield_context yield) const =0
The database-specific implementation for fetching a ledger object.
std::optional< ripple::uint256 > fetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const
Fetches the successor key.
Definition BackendInterface.cpp:153
std::optional< LedgerRange > hardFetchLedgerRangeNoThrow() const
Fetches the ledger range from DB retrying until no DatabaseTimeout is thrown.
Definition BackendInterface.cpp:77
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:267
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:59
virtual boost::json::object stats() const =0
virtual std::expected< std::vector< std::pair< boost::uuids::uuid, std::string > >, std::string > fetchClioNodesData(boost::asio::yield_context yield) const =0
Fetches the data of all nodes in the cluster.
void setCorruptionDetector(etl::CorruptionDetector detector)
Sets the corruption detector.
Definition BackendInterface.hpp:185
virtual TransactionsAndCursor fetchNFTTransactions(ripple::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.
virtual std::optional< std::uint32_t > fetchLatestLedgerSequence(boost::asio::yield_context yield) const =0
Fetches the latest ledger sequence.
virtual std::optional< NFT > fetchNFT(ripple::uint256 const &tokenID, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Fetches a specific NFT.
virtual void writeAccountTransactions(std::vector< AccountTransactionsData > data)=0
Write a new set of account transactions.
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.
std::optional< Blob > fetchLedgerObject(ripple::uint256 const &key, std::uint32_t sequence, boost::asio::yield_context yield) const
Fetches a specific ledger object.
Definition BackendInterface.cpp:84
LedgerPage fetchLedgerPage(std::optional< ripple::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:306
virtual TransactionsAndCursor fetchAccountTransactions(ripple::AccountID const &account, std::uint32_t limit, bool forward, std::optional< TransactionsCursor > const &cursor, boost::asio::yield_context yield) const =0
Fetches all transactions for a specific account.
virtual std::optional< ripple::uint256 > doFetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Database-specific implementation of fetching the successor key.
virtual std::optional< std::uint32_t > doFetchLedgerObjectSeq(ripple::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 updateRange(uint32_t newMax)
Updates the range of sequences that are stored in the DB.
Definition BackendInterface.cpp:274
virtual void writeLedger(ripple::LedgerHeader const &ledgerHeader, std::string &&blob)=0
Writes to a specific ledger.
virtual MPTHoldersAndCursor fetchMPTHolders(ripple::uint192 const &mptID, std::uint32_t const limit, std::optional< ripple::AccountID > const &cursorIn, std::uint32_t const ledgerSequence, boost::asio::yield_context yield) const =0
Fetches all holders' balances for a MPTIssuanceID.
LedgerCacheInterface const & cache() const
Definition BackendInterface.hpp:165
virtual std::optional< ripple::LedgerHeader > fetchLedgerByHash(ripple::uint256 const &hash, boost::asio::yield_context yield) const =0
Fetches a specific ledger by hash.
Represents a database timeout error.
Definition BackendInterface.hpp:58
char const * what() const override
Definition BackendInterface.hpp:64
Cache for an entire ledger.
Definition LedgerCacheInterface.hpp:38
A helper to notify Clio operator about a corruption in the DB.
Definition CorruptionDetector.hpp:35
A simple thread-safe logger for the channel specified in the constructor.
Definition Logger.hpp:111
This namespace implements the data access layer and related components.
Definition AmendmentCenter.cpp:70
auto synchronous(FnType &&func)
Synchronously executes the given function object inside a coroutine.
Definition BackendInterface.hpp:104
auto synchronousAndRetryOnTimeout(FnType &&func)
Synchronously execute the given function object and retry until no DatabaseTimeout is thrown.
Definition BackendInterface.hpp:132
auto retryOnTimeout(FnType func, size_t waitMs=kDEFAULT_WAIT_BETWEEN_RETRY)
A helper function that catches DatabaseTimout exceptions and retries indefinitely.
Definition BackendInterface.hpp:81
Struct used to keep track of what to write to account_transactions/account_tx tables.
Definition DBHelpers.hpp:45
Represents a page of book offer objects.
Definition Types.hpp:60
Represents a page of LedgerObjects.
Definition Types.hpp:52
Represents an array of MPTokens.
Definition Types.hpp:239
Represents a bundle of NFTs with a cursor to the next page.
Definition Types.hpp:231
Represests a bundle of transactions with metadata and a cursor to the next page.
Definition Types.hpp:164