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/LedgerCache.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 <xrpl/basics/base_uint.h>
35#include <xrpl/protocol/AccountID.h>
36#include <xrpl/protocol/Fees.h>
37#include <xrpl/protocol/LedgerHeader.h>
38
39#include <chrono>
40#include <cstddef>
41#include <cstdint>
42#include <exception>
43#include <optional>
44#include <shared_mutex>
45#include <string>
46#include <thread>
47#include <type_traits>
48#include <utility>
49#include <vector>
50
51namespace data {
52
56class DatabaseTimeout : public std::exception {
57public:
61 char const*
62 what() const throw() override
63 {
64 return "Database read timed out. Please retry the request";
65 }
66};
67
68static constexpr std::size_t kDEFAULT_WAIT_BETWEEN_RETRY = 500;
77template <typename FnType>
78auto
79retryOnTimeout(FnType func, size_t waitMs = kDEFAULT_WAIT_BETWEEN_RETRY)
80{
81 static util::Logger const log{"Backend"}; // NOLINT(readability-identifier-naming)
82
83 while (true) {
84 try {
85 return func();
86 } catch (DatabaseTimeout const&) {
87 LOG(log.error()) << "Database request timed out. Sleeping and retrying ... ";
88 std::this_thread::sleep_for(std::chrono::milliseconds(waitMs));
89 }
90 }
91}
92
100template <typename FnType>
101auto
102synchronous(FnType&& func)
103{
104 boost::asio::io_context ctx;
105
106 using R = typename boost::result_of<FnType(boost::asio::yield_context)>::type;
107 if constexpr (!std::is_same_v<R, void>) {
108 R res;
109 boost::asio::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func, &res](auto yield) {
110 res = func(yield);
111 });
112
113 ctx.run();
114 return res;
115 } else {
116 boost::asio::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) { func(yield); });
117 ctx.run();
118 }
119}
120
128template <typename FnType>
129auto
131{
132 return retryOnTimeout([&]() { return synchronous(func); });
133}
134
139protected:
140 mutable std::shared_mutex rngMtx_;
141 std::optional<LedgerRange> range_;
142 LedgerCache cache_;
143 std::optional<etl::CorruptionDetector<LedgerCache>> corruptionDetector_;
144
145public:
146 BackendInterface() = default;
147 virtual ~BackendInterface() = default;
148
149 // TODO: Remove this hack. Cache should not be exposed thru BackendInterface
153 LedgerCache const&
154 cache() const
155 {
156 return cache_;
157 }
158
164 {
165 return cache_;
166 }
167
173 void
175 {
176 corruptionDetector_ = std::move(detector);
177 }
178
186 virtual std::optional<ripple::LedgerHeader>
187 fetchLedgerBySequence(std::uint32_t sequence, boost::asio::yield_context yield) const = 0;
188
196 virtual std::optional<ripple::LedgerHeader>
197 fetchLedgerByHash(ripple::uint256 const& hash, boost::asio::yield_context yield) const = 0;
198
205 virtual std::optional<std::uint32_t>
206 fetchLatestLedgerSequence(boost::asio::yield_context yield) const = 0;
207
213 std::optional<LedgerRange>
214 fetchLedgerRange() const;
215
225 virtual std::vector<ripple::uint256>
226 fetchAccountRoots(std::uint32_t number, std::uint32_t pageSize, std::uint32_t seq, boost::asio::yield_context yield)
227 const = 0;
228
234 void
235 updateRange(uint32_t newMax);
236
244 void
245 setRange(uint32_t min, uint32_t max, bool force = false);
246
254 std::optional<ripple::Fees>
255 fetchFees(std::uint32_t seq, boost::asio::yield_context yield) const;
256
264 virtual std::optional<TransactionAndMetadata>
265 fetchTransaction(ripple::uint256 const& hash, boost::asio::yield_context yield) const = 0;
266
274 virtual std::vector<TransactionAndMetadata>
275 fetchTransactions(std::vector<ripple::uint256> const& hashes, boost::asio::yield_context yield) const = 0;
276
289 ripple::AccountID const& account,
290 std::uint32_t limit,
291 bool forward,
292 std::optional<TransactionsCursor> const& cursor,
293 boost::asio::yield_context yield
294 ) const = 0;
295
303 virtual std::vector<TransactionAndMetadata>
304 fetchAllTransactionsInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
305
313 virtual std::vector<ripple::uint256>
314 fetchAllTransactionHashesInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
315
324 virtual std::optional<NFT>
325 fetchNFT(ripple::uint256 const& tokenID, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
326
339 ripple::uint256 const& tokenID,
340 std::uint32_t limit,
341 bool forward,
342 std::optional<TransactionsCursor> const& cursorIn,
343 boost::asio::yield_context yield
344 ) const = 0;
345
357 virtual NFTsAndCursor
359 ripple::AccountID const& issuer,
360 std::optional<std::uint32_t> const& taxon,
361 std::uint32_t ledgerSequence,
362 std::uint32_t limit,
363 std::optional<ripple::uint256> const& cursorIn,
364 boost::asio::yield_context yield
365 ) const = 0;
366
377 virtual MPTHoldersAndCursor
379 ripple::uint192 const& mptID,
380 std::uint32_t const limit,
381 std::optional<ripple::AccountID> const& cursorIn,
382 std::uint32_t const ledgerSequence,
383 boost::asio::yield_context yield
384 ) const = 0;
385
397 std::optional<Blob>
398 fetchLedgerObject(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const;
399
410 std::optional<std::uint32_t>
411 fetchLedgerObjectSeq(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const;
412
424 std::vector<Blob>
426 std::vector<ripple::uint256> const& keys,
427 std::uint32_t sequence,
428 boost::asio::yield_context yield
429 ) const;
430
439 virtual std::optional<Blob>
440 doFetchLedgerObject(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const = 0;
441
450 virtual std::optional<std::uint32_t>
451 doFetchLedgerObjectSeq(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield)
452 const = 0;
453
462 virtual std::vector<Blob>
464 std::vector<ripple::uint256> const& keys,
465 std::uint32_t sequence,
466 boost::asio::yield_context yield
467 ) const = 0;
468
476 virtual std::vector<LedgerObject>
477 fetchLedgerDiff(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
478
491 std::optional<ripple::uint256> const& cursor,
492 std::uint32_t ledgerSequence,
493 std::uint32_t limit,
494 bool outOfOrder,
495 boost::asio::yield_context yield
496 );
497
506 std::optional<LedgerObject>
507 fetchSuccessorObject(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const;
508
520 std::optional<ripple::uint256>
521 fetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const;
522
531 virtual std::optional<ripple::uint256>
532 doFetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0;
533
545 ripple::uint256 const& book,
546 std::uint32_t ledgerSequence,
547 std::uint32_t limit,
548 boost::asio::yield_context yield
549 ) const;
550
558 virtual std::optional<std::string>
559 fetchMigratorStatus(std::string const& migratorName, boost::asio::yield_context yield) const = 0;
560
568 std::optional<LedgerRange>
569 hardFetchLedgerRange() const;
570
577 virtual std::optional<LedgerRange>
578 hardFetchLedgerRange(boost::asio::yield_context yield) const = 0;
579
585 std::optional<LedgerRange>
587
594 virtual void
595 writeLedger(ripple::LedgerHeader const& ledgerHeader, std::string&& blob) = 0;
596
604 virtual void
605 writeLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob);
606
616 virtual void
618 std::string&& hash,
619 std::uint32_t seq,
620 std::uint32_t date,
621 std::string&& transaction,
622 std::string&& metadata
623 ) = 0;
624
630 virtual void
631 writeNFTs(std::vector<NFTsData> const& data) = 0;
632
638 virtual void
639 writeAccountTransactions(std::vector<AccountTransactionsData> data) = 0;
640
646 virtual void
647 writeNFTTransactions(std::vector<NFTTransactionsData> const& data) = 0;
648
654 virtual void
655 writeMPTHolders(std::vector<MPTHolderData> const& data) = 0;
656
664 virtual void
665 writeSuccessor(std::string&& key, std::uint32_t seq, std::string&& successor) = 0;
666
672 virtual void
673 startWrites() const = 0;
674
683 bool
684 finishWrites(std::uint32_t ledgerSequence);
685
689 virtual void
691
698 virtual void
699 writeMigratorStatus(std::string const& migratorName, std::string const& status) = 0;
700
704 virtual bool
705 isTooBusy() const = 0;
706
710 virtual boost::json::object
711 stats() const = 0;
712
713private:
721 virtual void
722 doWriteLedgerObject(std::string&& key, std::uint32_t seq, std::string&& blob) = 0;
723
729 virtual bool
730 doFinishWrites() = 0;
731};
732
733} // namespace data
The interface to the database used by Clio.
Definition BackendInterface.hpp:138
void setCorruptionDetector(etl::CorruptionDetector< LedgerCache > detector)
Sets the corruption detector.
Definition BackendInterface.hpp:174
virtual std::vector< TransactionAndMetadata > fetchAllTransactionsInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const =0
Fetches all transactions from a specific ledger.
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
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
virtual std::vector< TransactionAndMetadata > fetchTransactions(std::vector< ripple::uint256 > const &hashes, boost::asio::yield_context yield) const =0
Fetches multiple transactions.
LedgerCache & cache()
Definition BackendInterface.hpp:163
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 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.
LedgerCache const & cache() const
Definition BackendInterface.hpp:154
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.
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:56
char const * what() const override
Definition BackendInterface.hpp:62
Cache for an entire ledger.
Definition LedgerCache.hpp:46
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:110
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:102
auto synchronousAndRetryOnTimeout(FnType &&func)
Synchronously execute the given function object and retry until no DatabaseTimeout is thrown.
Definition BackendInterface.hpp:130
auto retryOnTimeout(FnType func, size_t waitMs=kDEFAULT_WAIT_BETWEEN_RETRY)
A helper function that catches DatabaseTimout exceptions and retries indefinitely.
Definition BackendInterface.hpp:79
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