rippled
ShardArchiveHandler.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or 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 #include <ripple/app/misc/NetworkOPs.h>
21 #include <ripple/app/rdb/RelationalDBInterface_shards.h>
22 #include <ripple/basics/Archive.h>
23 #include <ripple/basics/BasicConfig.h>
24 #include <ripple/core/ConfigSections.h>
25 #include <ripple/nodestore/DatabaseShard.h>
26 #include <ripple/rpc/ShardArchiveHandler.h>
27 #include <ripple/rpc/impl/Handler.h>
28 
29 #include <memory>
30 
31 namespace ripple {
32 namespace RPC {
33 
34 using namespace boost::filesystem;
35 using namespace std::chrono_literals;
36 
37 boost::filesystem::path
39 {
40  return get(config.section(ConfigSection::shardDatabase()),
41  "download_path",
43  "path",
44  "")) /
45  "download";
46 }
47 
50 {
51  return std::make_unique<ShardArchiveHandler>(app);
52 }
53 
56 {
57  auto const downloadDir(getDownloadDirectory(app.config()));
58 
59  // Create the handler iff the database
60  // is present.
61  if (exists(downloadDir / stateDBName) &&
62  is_regular_file(downloadDir / stateDBName))
63  {
64  return std::make_unique<RecoveryHandler>(app);
65  }
66 
67  return nullptr;
68 }
69 
71  : process_(false)
72  , app_(app)
73  , j_(app.journal("ShardArchiveHandler"))
74  , downloadDir_(getDownloadDirectory(app.config()))
75  , timer_(app_.getIOService())
76  , verificationScheduler_(
77  std::chrono::seconds(get<std::uint32_t>(
78  app.config().section(ConfigSection::shardDatabase()),
79  "shard_verification_retry_interval")),
80 
81  get<std::uint32_t>(
82  app.config().section(ConfigSection::shardDatabase()),
83  "shard_verification_max_attempts"))
84 {
85  assert(app_.getShardStore());
86 }
87 
88 bool
90 {
91  std::lock_guard lock(m_);
92 
93  if (process_ || downloader_ != nullptr || sqlDB_ != nullptr)
94  {
95  JLOG(j_.warn()) << "Archives already being processed";
96  return false;
97  }
98 
99  // Initialize from pre-existing database
100  if (exists(downloadDir_ / stateDBName) &&
101  is_regular_file(downloadDir_ / stateDBName))
102  {
103  downloader_ =
105 
106  return initFromDB(lock);
107  }
108 
109  // Fresh initialization
110  else
111  {
112  try
113  {
114  create_directories(downloadDir_);
115 
117  }
118  catch (std::exception const& e)
119  {
120  JLOG(j_.error())
121  << "exception: " << e.what() << " in function: " << __func__;
122 
123  return false;
124  }
125  }
126 
127  return true;
128 }
129 
130 bool
132 {
133  try
134  {
135  using namespace boost::filesystem;
136 
137  assert(
138  exists(downloadDir_ / stateDBName) &&
139  is_regular_file(downloadDir_ / stateDBName));
140 
142 
143  readArchiveDB(*sqlDB_, [&](std::string const& url_, int state) {
144  parsedURL url;
145 
146  if (!parseUrl(url, url_))
147  {
148  JLOG(j_.error()) << "Failed to parse url: " << url_;
149 
150  return;
151  }
152 
153  add(state, std::move(url), lock);
154  });
155 
156  // Failed to load anything
157  // from the state database.
158  if (archives_.empty())
159  {
160  release();
161  return false;
162  }
163  }
164  catch (std::exception const& e)
165  {
166  JLOG(j_.error()) << "exception: " << e.what()
167  << " in function: " << __func__;
168 
169  return false;
170  }
171 
172  return true;
173 }
174 
175 void
177 {
178  stopping_ = true;
179  {
181 
182  if (downloader_)
183  {
184  downloader_->stop();
185  downloader_.reset();
186  }
187 
188  timer_.cancel();
189  }
190 
192  "ShardArchiveHandler", std::chrono::milliseconds(2000), j_);
193 
195  "ShardArchiveHandler", std::chrono::milliseconds(2000), j_);
196 }
197 
198 bool
200  std::uint32_t shardIndex,
202 {
204 
205  if (!add(shardIndex, std::forward<parsedURL>(url.first), lock))
206  return false;
207 
208  insertArchiveDB(*sqlDB_, shardIndex, url.second);
209 
210  return true;
211 }
212 
213 bool
215  std::uint32_t shardIndex,
216  parsedURL&& url,
218 {
219  if (process_)
220  {
221  JLOG(j_.error()) << "Download and import already in progress";
222  return false;
223  }
224 
225  auto const it{archives_.find(shardIndex)};
226  if (it != archives_.end())
227  return url == it->second;
228 
229  archives_.emplace(shardIndex, std::move(url));
230 
231  return true;
232 }
233 
234 bool
236 {
237  std::lock_guard lock(m_);
238  if (!app_.getShardStore())
239  {
240  JLOG(j_.error()) << "No shard store available";
241  return false;
242  }
243  if (process_)
244  {
245  JLOG(j_.warn()) << "Archives already being processed";
246  return false;
247  }
248  if (archives_.empty())
249  {
250  JLOG(j_.warn()) << "No archives to process";
251  return false;
252  }
253 
254  std::vector<std::uint32_t> shardIndexes(archives_.size());
256  archives_.begin(),
257  archives_.end(),
258  shardIndexes.begin(),
259  [](auto const& entry) { return entry.first; });
260 
261  if (!app_.getShardStore()->prepareShards(shardIndexes))
262  return false;
263 
264  try
265  {
266  // Create temp root download directory
267  create_directories(downloadDir_);
268 
269  if (!downloader_)
270  {
271  // will throw if can't initialize ssl context
272  downloader_ =
274  }
275  }
276  catch (std::exception const& e)
277  {
278  JLOG(j_.error()) << "exception: " << e.what();
279  return false;
280  }
281 
282  process_ = true;
283  return next(lock);
284 }
285 
286 void
288 {
290  doRelease(lock);
291 }
292 
293 bool
295 {
296  if (stopping_)
297  return false;
298 
299  if (archives_.empty())
300  {
301  doRelease(l);
302  return false;
303  }
304 
305  auto const shardIndex{archives_.begin()->first};
306 
307  // We use the sequence of the last validated ledger
308  // to determine whether or not we have stored a ledger
309  // that comes after the last ledger in this shard. A
310  // later ledger must be present in order to reliably
311  // retrieve the hash of the shard's last ledger.
312  std::optional<uint256> expectedHash;
313  bool shouldHaveHash = false;
314  if (auto const seq = app_.getShardStore()->lastLedgerSeq(shardIndex);
315  (shouldHaveHash = app_.getLedgerMaster().getValidLedgerIndex() > seq))
316  {
317  expectedHash = app_.getLedgerMaster().walkHashBySeq(
319  }
320 
321  if (!expectedHash)
322  {
323  auto wrapper =
324  timerCounter_.wrap([this](boost::system::error_code const& ec) {
325  if (ec != boost::asio::error::operation_aborted)
326  {
327  std::lock_guard lock(m_);
328  this->next(lock);
329  }
330  });
331 
332  if (!wrapper)
333  return onClosureFailed(
334  "failed to wrap closure for last ledger confirmation timer", l);
335 
336  if (!verificationScheduler_.retry(app_, shouldHaveHash, *wrapper))
337  {
338  JLOG(j_.error()) << "failed to find last ledger hash for shard "
339  << shardIndex << ", maximum attempts reached";
340 
341  return removeAndProceed(l);
342  }
343 
344  return true;
345  }
346 
347  // Create a temp archive directory at the root
348  auto const dstDir{downloadDir_ / std::to_string(shardIndex)};
349  try
350  {
351  create_directory(dstDir);
352  }
353  catch (std::exception const& e)
354  {
355  JLOG(j_.error()) << "exception: " << e.what();
356  return removeAndProceed(l);
357  }
358 
359  // Download the archive. Process in another thread
360  // to prevent holding up the lock if the downloader
361  // sleeps.
362  auto const& url{archives_.begin()->second};
363  auto wrapper = jobCounter_.wrap([this, url, dstDir](Job&) {
364  auto const ssl = (url.scheme == "https");
365  auto const defaultPort = ssl ? 443 : 80;
366 
367  if (!downloader_->download(
368  url.domain,
369  std::to_string(url.port.value_or(defaultPort)),
370  url.path,
371  11,
372  dstDir / "archive.tar.lz4",
373  [this](path dstPath) { complete(dstPath); },
374  ssl))
375  {
377  removeAndProceed(l);
378  }
379  });
380 
381  if (!wrapper)
382  return onClosureFailed(
383  "failed to wrap closure for starting download", l);
384 
385  app_.getJobQueue().addJob(jtCLIENT, "ShardArchiveHandler", *wrapper);
386 
387  return true;
388 }
389 
390 void
392 {
393  if (stopping_)
394  return;
395 
396  {
397  std::lock_guard lock(m_);
398  try
399  {
400  if (!is_regular_file(dstPath))
401  {
402  auto ar{archives_.begin()};
403  JLOG(j_.error())
404  << "Downloading shard id " << ar->first << " from URL "
405  << ar->second.domain << ar->second.path;
406  removeAndProceed(lock);
407  return;
408  }
409  }
410  catch (std::exception const& e)
411  {
412  JLOG(j_.error()) << "exception: " << e.what();
413  removeAndProceed(lock);
414  return;
415  }
416  }
417 
418  // Make lambdas mutable captured vars can be moved from
419  auto wrapper =
420  jobCounter_.wrap([=, dstPath = std::move(dstPath)](Job&) mutable {
421  if (stopping_)
422  return;
423 
424  // If not synced then defer and retry
425  auto const mode{app_.getOPs().getOperatingMode()};
426  if (mode != OperatingMode::FULL)
427  {
428  std::lock_guard lock(m_);
429  timer_.expires_from_now(static_cast<std::chrono::seconds>(
430  (static_cast<std::size_t>(OperatingMode::FULL) -
431  static_cast<std::size_t>(mode)) *
432  10));
433 
434  auto wrapper = timerCounter_.wrap(
435  [=, dstPath = std::move(dstPath)](
436  boost::system::error_code const& ec) mutable {
437  if (ec != boost::asio::error::operation_aborted)
438  complete(std::move(dstPath));
439  });
440 
441  if (!wrapper)
443  "failed to wrap closure for operating mode timer",
444  lock);
445  else
446  timer_.async_wait(*wrapper);
447  }
448  else
449  {
450  process(dstPath);
451  std::lock_guard lock(m_);
452  removeAndProceed(lock);
453  }
454  });
455 
456  if (!wrapper)
457  {
458  if (stopping_)
459  return;
460 
461  JLOG(j_.error()) << "failed to wrap closure for process()";
462 
463  std::lock_guard lock(m_);
464  removeAndProceed(lock);
465  }
466 
467  // Process in another thread to not hold up the IO service
468  app_.getJobQueue().addJob(jtCLIENT, "ShardArchiveHandler", *wrapper);
469 }
470 
471 void
472 ShardArchiveHandler::process(path const& dstPath)
473 {
474  std::uint32_t shardIndex;
475  {
476  std::lock_guard lock(m_);
477  shardIndex = archives_.begin()->first;
478  }
479 
480  auto const shardDir{dstPath.parent_path() / std::to_string(shardIndex)};
481  try
482  {
483  // Extract the downloaded archive
484  extractTarLz4(dstPath, dstPath.parent_path());
485 
486  // The extracted root directory name must match the shard index
487  if (!is_directory(shardDir))
488  {
489  JLOG(j_.error()) << "Shard " << shardIndex
490  << " mismatches archive shard directory";
491  return;
492  }
493  }
494  catch (std::exception const& e)
495  {
496  JLOG(j_.error()) << "exception: " << e.what();
497  return;
498  }
499 
500  // Import the shard into the shard store
501  if (!app_.getShardStore()->importShard(shardIndex, shardDir))
502  {
503  JLOG(j_.error()) << "Importing shard " << shardIndex;
504  return;
505  }
506 
507  JLOG(j_.debug()) << "Shard " << shardIndex << " downloaded and imported";
508 }
509 
510 void
512 {
514 
515  auto const shardIndex{archives_.begin()->first};
516  app_.getShardStore()->removePreShard(shardIndex);
517  archives_.erase(shardIndex);
518 
519  deleteFromArchiveDB(*sqlDB_, shardIndex);
520 
521  auto const dstDir{downloadDir_ / std::to_string(shardIndex)};
522  try
523  {
524  remove_all(dstDir);
525  }
526  catch (std::exception const& e)
527  {
528  JLOG(j_.error()) << "exception: " << e.what();
529  }
530 }
531 
532 void
534 {
535  timer_.cancel();
536  for (auto const& ar : archives_)
537  app_.getShardStore()->removePreShard(ar.first);
538  archives_.clear();
539 
541 
542  sqlDB_.reset();
543 
544  // Remove temp root download directory
545  try
546  {
547  remove_all(downloadDir_);
548  }
549  catch (std::exception const& e)
550  {
551  JLOG(j_.error()) << "exception: " << e.what()
552  << " in function: " << __func__;
553  }
554 
555  downloader_.reset();
556  process_ = false;
557 }
558 
559 bool
561  std::string const& errorMsg,
562  std::lock_guard<std::mutex> const& lock)
563 {
564  if (stopping_)
565  return false;
566 
567  JLOG(j_.error()) << errorMsg;
568 
569  return removeAndProceed(lock);
570 }
571 
572 bool
574 {
575  remove(lock);
576  return next(lock);
577 }
578 
580 {
581 }
582 
583 } // namespace RPC
584 } // namespace ripple
ripple::NodeStore::Database::lastLedgerSeq
std::uint32_t lastLedgerSeq(std::uint32_t shardIndex) const noexcept
Calculates the last ledger sequence for a given shard index.
Definition: Database.h:271
ripple::Application
Definition: Application.h:103
ripple::RPC::ShardArchiveHandler::getDownloadDirectory
static boost::filesystem::path getDownloadDirectory(Config const &config)
Definition: ShardArchiveHandler.cpp:38
ripple::RPC::ShardArchiveHandler::downloader_
std::shared_ptr< DatabaseDownloader > downloader_
Definition: ShardArchiveHandler.h:135
ripple::RPC::ShardArchiveHandler::downloadDir_
const boost::filesystem::path downloadDir_
Definition: ShardArchiveHandler.h:143
ripple::RPC::ShardArchiveHandler::remove
void remove(std::lock_guard< std::mutex > const &)
Definition: ShardArchiveHandler.cpp:511
ripple::RPC::ShardArchiveHandler::timerCounter_
TimerOpCounter timerCounter_
Definition: ShardArchiveHandler.h:146
ripple::RPC::ShardArchiveHandler::verificationScheduler_
ShardVerificationScheduler verificationScheduler_
Definition: ShardArchiveHandler.h:147
ripple::RPC::ShardArchiveHandler::stop
void stop()
Definition: ShardArchiveHandler.cpp:176
ripple::RPC::ShardArchiveHandler::makeShardArchiveHandler
static std::unique_ptr< ShardArchiveHandler > makeShardArchiveHandler(Application &app)
Definition: ShardArchiveHandler.cpp:49
std::string
STL class.
ripple::RPC::ShardArchiveHandler::removeAndProceed
bool removeAndProceed(std::lock_guard< std::mutex > const &lock)
Definition: ShardArchiveHandler.cpp:573
ripple::RPC::ShardArchiveHandler::start
bool start()
Starts downloading and importing archives.
Definition: ShardArchiveHandler.cpp:235
ripple::jtCLIENT
@ jtCLIENT
Definition: Job.h:51
std::exception
STL class.
ripple::RPC::ShardArchiveHandler::add
bool add(std::uint32_t shardIndex, std::pair< parsedURL, std::string > &&url)
Definition: ShardArchiveHandler.cpp:199
ripple::parsedURL
Definition: StringUtilities.h:100
std::pair
ripple::RPC::ShardVerificationScheduler::reset
void reset()
Definition: ShardVerificationScheduler.cpp:62
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:214
ripple::InboundLedger::Reason::GENERIC
@ GENERIC
std::vector
STL class.
ripple::ConfigSection::shardDatabase
static std::string shardDatabase()
Definition: ConfigSections.h:38
std::chrono::milliseconds
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::RPC::ShardArchiveHandler::doRelease
void doRelease(std::lock_guard< std::mutex > const &)
Definition: ShardArchiveHandler.cpp:533
std::lock_guard
STL class.
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
ripple::RPC::RecoveryHandler::RecoveryHandler
RecoveryHandler(Application &app)
Definition: ShardArchiveHandler.cpp:579
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:165
ripple::RPC::ShardArchiveHandler::initFromDB
bool initFromDB(std::lock_guard< std::mutex > const &)
Definition: ShardArchiveHandler.cpp:131
ripple::RPC::ShardArchiveHandler::onClosureFailed
bool onClosureFailed(std::string const &errorMsg, std::lock_guard< std::mutex > const &lock)
Definition: ShardArchiveHandler.cpp:560
ripple::extractTarLz4
void extractTarLz4(boost::filesystem::path const &src, boost::filesystem::path const &dst)
Extract a tar archive compressed with lz4.
Definition: Archive.cpp:29
ripple::LedgerMaster::walkHashBySeq
std::optional< LedgerHash > walkHashBySeq(std::uint32_t index, InboundLedger::Reason reason)
Walk to a ledger's hash using the skip list.
Definition: LedgerMaster.cpp:1703
ripple::RPC::ShardArchiveHandler::stopping_
std::atomic_bool stopping_
Definition: ShardArchiveHandler.h:134
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::RPC::ShardArchiveHandler::timer_
boost::asio::basic_waitable_timer< std::chrono::steady_clock > timer_
Definition: ShardArchiveHandler.h:144
ripple::RPC::ShardArchiveHandler::release
void release()
Definition: ShardArchiveHandler.cpp:287
ripple::RPC::ShardArchiveHandler::process
void process(boost::filesystem::path const &dstPath)
Definition: ShardArchiveHandler.cpp:472
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::Config
Definition: Config.h:68
ripple::deleteFromArchiveDB
void deleteFromArchiveDB(DatabaseCon &db, std::uint32_t shardIndex)
deleteFromArchiveDB Deletes entry from shard archive DB.
Definition: RelationalDBInterface_shards.cpp:482
ripple::Application::config
virtual Config & config()=0
std::to_string
T to_string(T... args)
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::dropArchiveDB
void dropArchiveDB(DatabaseCon &db)
dropArchiveDB Removes table in shard archive DB.
Definition: RelationalDBInterface_shards.cpp:489
ripple::parseUrl
bool parseUrl(parsedURL &pUrl, std::string const &strUrl)
Definition: StringUtilities.cpp:47
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::Job
Definition: Job.h:85
ripple::ConfigSection
Definition: ConfigSections.h:28
ripple::RPC::ShardArchiveHandler::complete
void complete(boost::filesystem::path dstPath)
Definition: ShardArchiveHandler.cpp:391
std::uint32_t
ripple::RPC::ShardVerificationScheduler::retry
bool retry(Application &app, bool shouldHaveHash, retryFunction f)
Definition: ShardVerificationScheduler.cpp:37
ripple::NodeStore::DatabaseShard::prepareShards
virtual bool prepareShards(std::vector< std::uint32_t > const &shardIndexes)=0
Prepare one or more shard indexes to be imported into the database.
std::transform
T transform(T... args)
ripple::RPC::ShardArchiveHandler::j_
const beast::Journal j_
Definition: ShardArchiveHandler.h:142
memory
ripple::Application::getIOService
virtual boost::asio::io_service & getIOService()=0
ripple::stateDBName
static constexpr auto stateDBName
Definition: DBInit.h:222
ripple::NodeStore::DatabaseShard::importShard
virtual bool importShard(std::uint32_t shardIndex, boost::filesystem::path const &srcDir)=0
Import a shard from the shard archive handler into the shard database.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::RPC::ShardArchiveHandler::next
bool next(std::lock_guard< std::mutex > const &l)
Definition: ShardArchiveHandler.cpp:294
ripple::readArchiveDB
void readArchiveDB(DatabaseCon &db, std::function< void(std::string const &, int)> const &func)
readArchiveDB Read entries from shard archive database and calls fiven callback for each entry.
Definition: RelationalDBInterface_shards.cpp:458
ripple::RPC::ShardArchiveHandler::tryMakeRecoveryHandler
static std::unique_ptr< ShardArchiveHandler > tryMakeRecoveryHandler(Application &app)
Definition: ShardArchiveHandler.cpp:55
ripple::RPC::ShardArchiveHandler::archives_
std::map< std::uint32_t, parsedURL > archives_
Definition: ShardArchiveHandler.h:136
std::vector::begin
T begin(T... args)
std
STL namespace.
ripple::RPC::ShardArchiveHandler::app_
Application & app_
Definition: ShardArchiveHandler.h:141
ripple::RPC::ShardArchiveHandler
Handles the download and import of one or more shard archives.
Definition: ShardArchiveHandler.h:40
ripple::RPC::ShardArchiveHandler::ShardArchiveHandler
ShardArchiveHandler()=delete
ripple::ClosureCounter::join
void join(char const *name, std::chrono::milliseconds wait, beast::Journal j)
Returns once all counted in-flight closures are destroyed.
Definition: ClosureCounter.h:166
std::optional
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
ripple::insertArchiveDB
void insertArchiveDB(DatabaseCon &db, std::uint32_t shardIndex, std::string const &url)
insertArchiveDB Adds entry to shard archive database.
Definition: RelationalDBInterface_shards.cpp:472
ripple::RPC::ShardArchiveHandler::m_
std::mutex m_
Definition: ShardArchiveHandler.h:133
ripple::RPC::ShardArchiveHandler::jobCounter_
JobCounter jobCounter_
Definition: ShardArchiveHandler.h:145
ripple::makeArchiveDB
std::unique_ptr< DatabaseCon > makeArchiveDB(boost::filesystem::path const &dir, std::string const &dbName)
makeArchiveDB Opens shard archive DB and returns its descriptor.
Definition: RelationalDBInterface_shards.cpp:451
ripple::NodeStore::DatabaseShard::removePreShard
virtual void removePreShard(std::uint32_t shardIndex)=0
Remove a previously prepared shard index for import.
std::unique_ptr
STL class.
ripple::RPC::ShardArchiveHandler::process_
bool process_
Definition: ShardArchiveHandler.h:137
ripple::RPC::ShardArchiveHandler::init
bool init()
Definition: ShardArchiveHandler.cpp:89
ripple::make_DatabaseDownloader
std::shared_ptr< DatabaseDownloader > make_DatabaseDownloader(boost::asio::io_service &io_service, Config const &config, beast::Journal j)
Definition: DatabaseDownloader.cpp:25
ripple::RPC::ShardArchiveHandler::sqlDB_
std::unique_ptr< DatabaseCon > sqlDB_
Definition: ShardArchiveHandler.h:138
std::exception::what
T what(T... args)
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:118
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:127
ripple::ClosureCounter::wrap
std::optional< Substitute< Closure > > wrap(Closure &&closure)
Wrap the passed closure with a reference counter.
Definition: ClosureCounter.h:192
ripple::OperatingMode::FULL
@ FULL
we have the ledger and can even validate