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