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) {
113 res = func(yield);
114 });
115
116 ctx.run();
117 return res;
118 } else {
119 util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) {
120 func(yield);
121 });
122 ctx.run();
123 }
124}
125
134template <typename FnType>
135auto
137{
138 return retryOnTimeout([&]() { return synchronous(func); });
139}
140
145protected:
146 util::Logger log_{"Backend"};
147 mutable std::shared_mutex rngMtx_;
148 std::optional<LedgerRange> range_;
149 std::reference_wrapper<LedgerCacheInterface> cache_;
150 std::optional<etl::CorruptionDetector> corruptionDetector_;
151
152public:
161 virtual ~BackendInterface() = default;
162
163 // TODO https://github.com/XRPLF/clio/issues/1956: Remove this hack once old ETL is removed.
164 // Cache should not be exposed thru BackendInterface
165
170 cache() const
171 {
172 return cache_;
173 }
174
180 {
181 return cache_;
182 }
183
189 void
191 {
192 corruptionDetector_ = std::move(detector);
193 }
194
202 virtual std::optional<ripple::LedgerHeader>
203 fetchLedgerBySequence(std::uint32_t sequence, boost::asio::yield_context yield) const = 0;
204
212 virtual std::optional<ripple::LedgerHeader>
213 fetchLedgerByHash(ripple::uint256 const& hash, boost::asio::yield_context yield) const = 0;
214
221 virtual std::optional<std::uint32_t>
222 fetchLatestLedgerSequence(boost::asio::yield_context yield) const = 0;
223
229 std::optional<LedgerRange>
230 fetchLedgerRange() const;
231
242 virtual std::vector<ripple::uint256>
244 std::uint32_t number,
245 std::uint32_t pageSize,
246 std::uint32_t seq,
247 boost::asio::yield_context yield
248 ) const = 0;
249
255 void
256 updateRange(uint32_t newMax);
257
264 void
265 forceUpdateRange(uint32_t newMax);
266
274 void
275 setRange(uint32_t min, uint32_t max, bool force = false);
276
284 std::optional<ripple::Fees>
285 fetchFees(std::uint32_t seq, boost::asio::yield_context yield) const;
286
294 virtual std::optional<TransactionAndMetadata>
295 fetchTransaction(ripple::uint256 const& hash, boost::asio::yield_context yield) const = 0;
296
304 virtual std::vector<TransactionAndMetadata>
306 std::vector<ripple::uint256> const& hashes,
307 boost::asio::yield_context yield
308 ) const = 0;
309
322 ripple::AccountID const& account,
323 std::uint32_t limit,
324 bool forward,
325 std::optional<TransactionsCursor> const& txnCursor,
326 boost::asio::yield_context yield
327 ) const = 0;
328
336 virtual std::vector<TransactionAndMetadata>
338 std::uint32_t ledgerSequence,
339 boost::asio::yield_context yield
340 ) const = 0;
341
349 virtual std::vector<ripple::uint256>
351 std::uint32_t ledgerSequence,
352 boost::asio::yield_context yield
353 ) const = 0;
354
363 virtual std::optional<NFT>
365 ripple::uint256 const& tokenID,
366 std::uint32_t ledgerSequence,
367 boost::asio::yield_context yield
368 ) const = 0;
369
382 ripple::uint256 const& tokenID,
383 std::uint32_t limit,
384 bool forward,
385 std::optional<TransactionsCursor> const& cursorIn,
386 boost::asio::yield_context yield
387 ) const = 0;
388
401 virtual NFTsAndCursor
403 ripple::AccountID const& issuer,
404 std::optional<std::uint32_t> const& taxon,
405 std::uint32_t ledgerSequence,
406 std::uint32_t limit,
407 std::optional<ripple::uint256> const& cursorIn,
408 boost::asio::yield_context yield
409 ) const = 0;
410
421 virtual MPTHoldersAndCursor
423 ripple::uint192 const& mptID,
424 std::uint32_t const limit,
425 std::optional<ripple::AccountID> const& cursorIn,
426 std::uint32_t const ledgerSequence,
427 boost::asio::yield_context yield
428 ) const = 0;
429
441 std::optional<Blob>
443 ripple::uint256 const& key,
444 std::uint32_t sequence,
445 boost::asio::yield_context yield
446 ) const;
447
458 std::optional<std::uint32_t>
460 ripple::uint256 const& key,
461 std::uint32_t sequence,
462 boost::asio::yield_context yield
463 ) const;
464
477 std::vector<Blob>
479 std::vector<ripple::uint256> const& keys,
480 std::uint32_t sequence,
481 boost::asio::yield_context yield
482 ) const;
483
492 virtual std::optional<Blob>
494 ripple::uint256 const& key,
495 std::uint32_t sequence,
496 boost::asio::yield_context yield
497 ) const = 0;
498
507 virtual std::optional<std::uint32_t>
509 ripple::uint256 const& key,
510 std::uint32_t sequence,
511 boost::asio::yield_context yield
512 ) const = 0;
513
522 virtual std::vector<Blob>
524 std::vector<ripple::uint256> const& keys,
525 std::uint32_t sequence,
526 boost::asio::yield_context yield
527 ) const = 0;
528
536 virtual std::vector<LedgerObject>
537 fetchLedgerDiff(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
538
551 std::optional<ripple::uint256> const& cursor,
552 std::uint32_t ledgerSequence,
553 std::uint32_t limit,
554 bool outOfOrder,
555 boost::asio::yield_context yield
556 );
557
566 std::optional<LedgerObject>
568 ripple::uint256 key,
569 std::uint32_t ledgerSequence,
570 boost::asio::yield_context yield
571 ) const;
572
585 std::optional<ripple::uint256>
587 ripple::uint256 key,
588 std::uint32_t ledgerSequence,
589 boost::asio::yield_context yield
590 ) const;
591
600 virtual std::optional<ripple::uint256>
602 ripple::uint256 key,
603 std::uint32_t ledgerSequence,
604 boost::asio::yield_context yield
605 ) const = 0;
606
618 ripple::uint256 const& book,
619 std::uint32_t ledgerSequence,
620 std::uint32_t limit,
621 boost::asio::yield_context yield
622 ) const;
623
631 virtual std::optional<std::string>
633 std::string const& migratorName,
634 boost::asio::yield_context yield
635 ) const = 0;
636
639 std::expected<std::vector<std::pair<boost::uuids::uuid, std::string>>, std::string>;
640
647 [[nodiscard]] virtual ClioNodesDataFetchResult
648 fetchClioNodesData(boost::asio::yield_context yield) const = 0;
649
658 std::optional<LedgerRange>
659 hardFetchLedgerRange() const;
660
667 virtual std::optional<LedgerRange>
668 hardFetchLedgerRange(boost::asio::yield_context yield) const = 0;
669
675 std::optional<LedgerRange>
677
684 virtual void
685 writeLedger(ripple::LedgerHeader const& ledgerHeader, std::string&& blob) = 0;
686
694 virtual void
695 writeLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob);
696
706 virtual void
708 std::string&& hash,
709 std::uint32_t seq,
710 std::uint32_t date,
711 std::string&& transaction,
712 std::string&& metadata
713 ) = 0;
714
720 virtual void
721 writeNFTs(std::vector<NFTsData> const& data) = 0;
722
728 virtual void
729 writeAccountTransactions(std::vector<AccountTransactionsData> data) = 0;
730
736 virtual void
738
744 virtual void
745 writeNFTTransactions(std::vector<NFTTransactionsData> const& data) = 0;
746
752 virtual void
753 writeMPTHolders(std::vector<MPTHolderData> const& data) = 0;
754
762 virtual void
763 writeSuccessor(std::string&& key, std::uint32_t seq, std::string&& successor) = 0;
764
771 virtual void
772 writeNodeMessage(boost::uuids::uuid const& uuid, std::string message) = 0;
773
779 virtual void
780 startWrites() const = 0;
781
790 bool
791 finishWrites(std::uint32_t ledgerSequence);
792
796 virtual void
798
805 virtual void
806 writeMigratorStatus(std::string const& migratorName, std::string const& status) = 0;
807
811 virtual bool
812 isTooBusy() const = 0;
813
817 virtual boost::json::object
818 stats() const = 0;
819
820private:
828 virtual void
829 doWriteLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob) = 0;
830
836 virtual bool
837 doFinishWrites() = 0;
838
839 void
840 updateRangeImpl(uint32_t newMax);
841};
842
843} // namespace data
844using BackendInterface = data::BackendInterface;
The interface to the database used by Clio.
Definition BackendInterface.hpp:144
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:368
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.
void forceUpdateRange(uint32_t newMax)
Updates the range of sequences that are stored in the DB without any checks.
Definition BackendInterface.cpp:294
virtual TransactionsAndCursor fetchAccountTransactions(ripple::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.
std::expected< std::vector< std::pair< boost::uuids::uuid, std::string > >, std::string > ClioNodesDataFetchResult
Return type for fetchClioNodesData() method.
Definition BackendInterface.hpp:638
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:114
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:301
LedgerCacheInterface & cache()
Definition BackendInterface.hpp:179
std::optional< LedgerObject > fetchSuccessorObject(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const
Fetches the successor object.
Definition BackendInterface.cpp:165
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:101
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:183
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:65
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:262
BackendInterface(LedgerCacheInterface &cache)
Construct a new backend interface instance.
Definition BackendInterface.hpp:158
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:149
std::optional< LedgerRange > hardFetchLedgerRangeNoThrow() const
Fetches the ledger range from DB retrying until no DatabaseTimeout is thrown.
Definition BackendInterface.cpp:72
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:268
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:54
virtual boost::json::object stats() const =0
void setCorruptionDetector(etl::CorruptionDetector detector)
Sets the corruption detector.
Definition BackendInterface.hpp:190
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:79
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:314
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:275
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:170
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:40
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:96
Pump error(SourceLocationType const &loc=CURRENT_SRC_LOCATION) const
Interface for logging at Severity::ERR severity.
Definition Logger.cpp:517
This namespace implements the data access layer and related components.
Definition AmendmentCenter.cpp:75
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:136
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:72
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:254
Represents a bundle of NFTs with a cursor to the next page.
Definition Types.hpp:246
Represests a bundle of transactions with metadata and a cursor to the next page.
Definition Types.hpp:172