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/Spawn.hpp"
27#include "util/log/Logger.hpp"
28
29#include <boost/asio/executor_work_guard.hpp>
30#include <boost/asio/io_context.hpp>
31#include <boost/asio/spawn.hpp>
32#include <boost/json.hpp>
33#include <boost/json/object.hpp>
34#include <boost/utility/result_of.hpp>
35#include <boost/uuid/uuid.hpp>
36#include <xrpl/basics/base_uint.h>
37#include <xrpl/protocol/AccountID.h>
38#include <xrpl/protocol/Fees.h>
39#include <xrpl/protocol/LedgerHeader.h>
40
41#include <chrono>
42#include <cstddef>
43#include <cstdint>
44#include <exception>
45#include <functional>
46#include <optional>
47#include <shared_mutex>
48#include <string>
49#include <thread>
50#include <type_traits>
51#include <utility>
52#include <vector>
53
54namespace data {
55
59class DatabaseTimeout : public std::exception {
60public:
64 char const*
65 what() const throw() override
66 {
67 return "Database read timed out. Please retry the request";
68 }
69};
70
71static constexpr std::size_t kDEFAULT_WAIT_BETWEEN_RETRY = 500;
80template <typename FnType>
81auto
82retryOnTimeout(FnType func, size_t waitMs = kDEFAULT_WAIT_BETWEEN_RETRY)
83{
84 static util::Logger const log{"Backend"}; // NOLINT(readability-identifier-naming)
85
86 while (true) {
87 try {
88 return func();
89 } catch (DatabaseTimeout const&) {
90 LOG(log.error()) << "Database request timed out. Sleeping and retrying ... ";
91 std::this_thread::sleep_for(std::chrono::milliseconds(waitMs));
92 }
93 }
94}
95
103template <typename FnType>
104auto
105synchronous(FnType&& func)
106{
107 boost::asio::io_context ctx;
108
109 using R = typename boost::result_of<FnType(boost::asio::yield_context)>::type;
110 if constexpr (!std::is_same_v<R, void>) {
111 R res;
112 util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func, &res](auto yield) { res = func(yield); });
113
114 ctx.run();
115 return res;
116 } else {
117 util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) { func(yield); });
118 ctx.run();
119 }
120}
121
129template <typename FnType>
130auto
132{
133 return retryOnTimeout([&]() { return synchronous(func); });
134}
135
140protected:
141 mutable std::shared_mutex rngMtx_;
142 std::optional<LedgerRange> range_;
143 std::reference_wrapper<LedgerCacheInterface> cache_;
144 std::optional<etl::CorruptionDetector> corruptionDetector_;
145
146public:
155 virtual ~BackendInterface() = default;
156
157 // TODO https://github.com/XRPLF/clio/issues/1956: Remove this hack once old ETL is removed.
158 // Cache should not be exposed thru BackendInterface
159
164 cache() const
165 {
166 return cache_;
167 }
168
174 {
175 return cache_;
176 }
177
183 void
185 {
186 corruptionDetector_ = std::move(detector);
187 }
188
196 virtual std::optional<ripple::LedgerHeader>
197 fetchLedgerBySequence(std::uint32_t sequence, boost::asio::yield_context yield) const = 0;
198
206 virtual std::optional<ripple::LedgerHeader>
207 fetchLedgerByHash(ripple::uint256 const& hash, boost::asio::yield_context yield) const = 0;
208
215 virtual std::optional<std::uint32_t>
216 fetchLatestLedgerSequence(boost::asio::yield_context yield) const = 0;
217
223 std::optional<LedgerRange>
224 fetchLedgerRange() const;
225
235 virtual std::vector<ripple::uint256>
237 std::uint32_t number,
238 std::uint32_t pageSize,
239 std::uint32_t seq,
240 boost::asio::yield_context yield
241 ) const = 0;
242
248 void
249 updateRange(uint32_t newMax);
250
258 void
259 setRange(uint32_t min, uint32_t max, bool force = false);
260
268 std::optional<ripple::Fees>
269 fetchFees(std::uint32_t seq, boost::asio::yield_context yield) const;
270
278 virtual std::optional<TransactionAndMetadata>
279 fetchTransaction(ripple::uint256 const& hash, boost::asio::yield_context yield) const = 0;
280
288 virtual std::vector<TransactionAndMetadata>
289 fetchTransactions(std::vector<ripple::uint256> const& hashes, boost::asio::yield_context yield) const = 0;
290
303 ripple::AccountID const& account,
304 std::uint32_t limit,
305 bool forward,
306 std::optional<TransactionsCursor> const& cursor,
307 boost::asio::yield_context yield
308 ) const = 0;
309
317 virtual std::vector<TransactionAndMetadata>
318 fetchAllTransactionsInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
319
327 virtual std::vector<ripple::uint256>
328 fetchAllTransactionHashesInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
329
338 virtual std::optional<NFT>
339 fetchNFT(ripple::uint256 const& tokenID, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
340
353 ripple::uint256 const& tokenID,
354 std::uint32_t limit,
355 bool forward,
356 std::optional<TransactionsCursor> const& cursorIn,
357 boost::asio::yield_context yield
358 ) const = 0;
359
371 virtual NFTsAndCursor
373 ripple::AccountID const& issuer,
374 std::optional<std::uint32_t> const& taxon,
375 std::uint32_t ledgerSequence,
376 std::uint32_t limit,
377 std::optional<ripple::uint256> const& cursorIn,
378 boost::asio::yield_context yield
379 ) const = 0;
380
391 virtual MPTHoldersAndCursor
393 ripple::uint192 const& mptID,
394 std::uint32_t const limit,
395 std::optional<ripple::AccountID> const& cursorIn,
396 std::uint32_t const ledgerSequence,
397 boost::asio::yield_context yield
398 ) const = 0;
399
411 std::optional<Blob>
412 fetchLedgerObject(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const;
413
424 std::optional<std::uint32_t>
425 fetchLedgerObjectSeq(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const;
426
438 std::vector<Blob>
440 std::vector<ripple::uint256> const& keys,
441 std::uint32_t sequence,
442 boost::asio::yield_context yield
443 ) const;
444
453 virtual std::optional<Blob>
454 doFetchLedgerObject(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const = 0;
455
464 virtual std::optional<std::uint32_t>
466 ripple::uint256 const& key,
467 std::uint32_t sequence,
468 boost::asio::yield_context yield
469 ) const = 0;
470
479 virtual std::vector<Blob>
481 std::vector<ripple::uint256> const& keys,
482 std::uint32_t sequence,
483 boost::asio::yield_context yield
484 ) const = 0;
485
493 virtual std::vector<LedgerObject>
494 fetchLedgerDiff(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
495
508 std::optional<ripple::uint256> const& cursor,
509 std::uint32_t ledgerSequence,
510 std::uint32_t limit,
511 bool outOfOrder,
512 boost::asio::yield_context yield
513 );
514
523 std::optional<LedgerObject>
524 fetchSuccessorObject(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const;
525
537 std::optional<ripple::uint256>
538 fetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const;
539
548 virtual std::optional<ripple::uint256>
549 doFetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
550
562 ripple::uint256 const& book,
563 std::uint32_t ledgerSequence,
564 std::uint32_t limit,
565 boost::asio::yield_context yield
566 ) const;
567
575 virtual std::optional<std::string>
576 fetchMigratorStatus(std::string const& migratorName, boost::asio::yield_context yield) const = 0;
577
580 std::expected<std::vector<std::pair<boost::uuids::uuid, std::string>>, std::string>;
581
588 [[nodiscard]] virtual ClioNodesDataFetchResult
589 fetchClioNodesData(boost::asio::yield_context yield) const = 0;
590
598 std::optional<LedgerRange>
599 hardFetchLedgerRange() const;
600
607 virtual std::optional<LedgerRange>
608 hardFetchLedgerRange(boost::asio::yield_context yield) const = 0;
609
615 std::optional<LedgerRange>
617
624 virtual void
625 writeLedger(ripple::LedgerHeader const& ledgerHeader, std::string&& blob) = 0;
626
634 virtual void
635 writeLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob);
636
646 virtual void
648 std::string&& hash,
649 std::uint32_t seq,
650 std::uint32_t date,
651 std::string&& transaction,
652 std::string&& metadata
653 ) = 0;
654
660 virtual void
661 writeNFTs(std::vector<NFTsData> const& data) = 0;
662
668 virtual void
669 writeAccountTransactions(std::vector<AccountTransactionsData> data) = 0;
670
676 virtual void
678
684 virtual void
685 writeNFTTransactions(std::vector<NFTTransactionsData> const& data) = 0;
686
692 virtual void
693 writeMPTHolders(std::vector<MPTHolderData> const& data) = 0;
694
702 virtual void
703 writeSuccessor(std::string&& key, std::uint32_t seq, std::string&& successor) = 0;
704
711 virtual void
712 writeNodeMessage(boost::uuids::uuid const& uuid, std::string message) = 0;
713
719 virtual void
720 startWrites() const = 0;
721
730 bool
731 finishWrites(std::uint32_t ledgerSequence);
732
736 virtual void
738
745 virtual void
746 writeMigratorStatus(std::string const& migratorName, std::string const& status) = 0;
747
751 virtual bool
752 isTooBusy() const = 0;
753
757 virtual boost::json::object
758 stats() const = 0;
759
760private:
768 virtual void
769 doWriteLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob) = 0;
770
776 virtual bool
777 doFinishWrites() = 0;
778};
779
780} // namespace data
The interface to the database used by Clio.
Definition BackendInterface.hpp:139
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 ClioNodesDataFetchResult fetchClioNodesData(boost::asio::yield_context yield) const =0
Fetches the data of all nodes in the cluster.
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:173
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:152
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
void setCorruptionDetector(etl::CorruptionDetector detector)
Sets the corruption detector.
Definition BackendInterface.hpp:184
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.
std::expected< std::vector< std::pair< boost::uuids::uuid, std::string > >, std::string > ClioNodesDataFetchResult
Return type for fetchClioNodesData() method.
Definition BackendInterface.hpp:579
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:164
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:59
char const * what() const override
Definition BackendInterface.hpp:65
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:105
auto synchronousAndRetryOnTimeout(FnType &&func)
Synchronously execute the given function object and retry until no DatabaseTimeout is thrown.
Definition BackendInterface.hpp:131
auto retryOnTimeout(FnType func, size_t waitMs=kDEFAULT_WAIT_BETWEEN_RETRY)
A helper function that catches DatabaseTimeout exceptions and retries indefinitely.
Definition BackendInterface.hpp:82
void spawn(Ctx &&ctx, F &&func)
Spawns a coroutine using boost::asio::spawn
Definition Spawn.hpp:69
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