rippled
LedgerMaster.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 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/consensus/RCLValidations.h>
21 #include <ripple/app/ledger/Ledger.h>
22 #include <ripple/app/ledger/LedgerMaster.h>
23 #include <ripple/app/ledger/OpenLedger.h>
24 #include <ripple/app/ledger/OrderBookDB.h>
25 #include <ripple/app/ledger/PendingSaves.h>
26 #include <ripple/app/main/Application.h>
27 #include <ripple/app/misc/AmendmentTable.h>
28 #include <ripple/app/misc/HashRouter.h>
29 #include <ripple/app/misc/LoadFeeTrack.h>
30 #include <ripple/app/misc/NetworkOPs.h>
31 #include <ripple/app/misc/SHAMapStore.h>
32 #include <ripple/app/misc/Transaction.h>
33 #include <ripple/app/misc/TxQ.h>
34 #include <ripple/app/misc/ValidatorList.h>
35 #include <ripple/app/paths/PathRequests.h>
36 #include <ripple/app/tx/apply.h>
37 #include <ripple/basics/Log.h>
38 #include <ripple/basics/MathUtilities.h>
39 #include <ripple/basics/TaggedCache.h>
40 #include <ripple/basics/UptimeClock.h>
41 #include <ripple/basics/contract.h>
42 #include <ripple/basics/safe_cast.h>
43 #include <ripple/core/DatabaseCon.h>
44 #include <ripple/core/TimeKeeper.h>
45 #include <ripple/nodestore/DatabaseShard.h>
46 #include <ripple/overlay/Overlay.h>
47 #include <ripple/overlay/Peer.h>
48 #include <ripple/protocol/BuildInfo.h>
49 #include <ripple/protocol/HashPrefix.h>
50 #include <ripple/protocol/digest.h>
51 #include <ripple/resource/Fees.h>
52 #include <algorithm>
53 #include <cassert>
54 #include <limits>
55 #include <memory>
56 #include <vector>
57 
58 namespace ripple {
59 
60 namespace {
61 
62 //==============================================================================
99 template <class MutexType>
100 class ScopedUnlock
101 {
103 
104 public:
115  explicit ScopedUnlock(std::unique_lock<MutexType>& lock) : lock_(lock)
116  {
117  assert(lock_.owns_lock());
118  lock_.unlock();
119  }
120 
121  ScopedUnlock(ScopedUnlock const&) = delete;
122  ScopedUnlock&
123  operator=(ScopedUnlock const&) = delete;
124 
132  ~ScopedUnlock() noexcept(false)
133  {
134  lock_.lock();
135  }
136 };
137 
138 } // namespace
139 
140 // Don't catch up more than 100 ledgers (cannot exceed 256)
141 static constexpr int MAX_LEDGER_GAP{100};
142 
143 // Don't acquire history if ledger is too old
145 
146 // Don't acquire history if write load is too high
147 static constexpr int MAX_WRITE_LOAD_ACQUIRE{8192};
148 
149 // Helper function for LedgerMaster::doAdvance()
150 // Return true if candidateLedger should be fetched from the network.
151 static bool
153  std::uint32_t const currentLedger,
154  std::uint32_t const ledgerHistory,
155  boost::optional<LedgerIndex> const minimumOnline,
156  std::uint32_t const candidateLedger,
157  beast::Journal j)
158 {
159  bool const ret = [&]() {
160  // Fetch ledger if it may be the current ledger
161  if (candidateLedger >= currentLedger)
162  return true;
163 
164  // Or if it is within our configured history range:
165  if (currentLedger - candidateLedger <= ledgerHistory)
166  return true;
167 
168  // Or if greater than or equal to a specific minimum ledger.
169  // Do nothing if the minimum ledger to keep online is unknown.
170  return minimumOnline.has_value() && candidateLedger >= *minimumOnline;
171  }();
172 
173  JLOG(j.trace()) << "Missing ledger " << candidateLedger
174  << (ret ? " should" : " should NOT") << " be acquired";
175  return ret;
176 }
177 
179  Application& app,
181  Stoppable& parent,
182  beast::insight::Collector::ptr const& collector,
183  beast::Journal journal)
184  : Stoppable("LedgerMaster", parent)
185  , app_(app)
186  , m_journal(journal)
187  , mLedgerHistory(collector, app)
188  , mLedgerCleaner(
189  detail::make_LedgerCleaner(app, *this, app_.journal("LedgerCleaner")))
190  , standalone_(app_.config().standalone())
191  , fetch_depth_(
192  app_.getSHAMapStore().clampFetchDepth(app_.config().FETCH_DEPTH))
193  , ledger_history_(app_.config().LEDGER_HISTORY)
194  , ledger_fetch_size_(app_.config().getValueFor(SizedItem::ledgerFetch))
195  , fetch_packs_(
196  "FetchPack",
197  65536,
198  std::chrono::seconds{45},
199  stopwatch,
200  app_.journal("TaggedCache"))
201  , m_stats(std::bind(&LedgerMaster::collect_metrics, this), collector)
202 {
203 }
204 
207 {
208  return app_.openLedger().current()->info().seq;
209 }
210 
213 {
214  return mValidLedgerSeq;
215 }
216 
217 bool
219  ReadView const& view,
221  char const* reason)
222 {
223  auto validLedger = getValidatedLedger();
224 
225  if (validLedger && !areCompatible(*validLedger, view, s, reason))
226  {
227  return false;
228  }
229 
230  {
232 
233  if ((mLastValidLedger.second != 0) &&
234  !areCompatible(
235  mLastValidLedger.first,
236  mLastValidLedger.second,
237  view,
238  s,
239  reason))
240  {
241  return false;
242  }
243  }
244 
245  return true;
246 }
247 
250 {
251  using namespace std::chrono_literals;
253  if (pubClose == 0s)
254  {
255  JLOG(m_journal.debug()) << "No published ledger";
256  return weeks{2};
257  }
258 
259  std::chrono::seconds ret = app_.timeKeeper().closeTime().time_since_epoch();
260  ret -= pubClose;
261  ret = (ret > 0s) ? ret : 0s;
262 
263  JLOG(m_journal.trace()) << "Published ledger age is " << ret.count();
264  return ret;
265 }
266 
269 {
270  using namespace std::chrono_literals;
272  if (valClose == 0s)
273  {
274  JLOG(m_journal.debug()) << "No validated ledger";
276  }
277 
278  std::chrono::seconds ret = app_.timeKeeper().closeTime().time_since_epoch();
279  ret -= valClose;
280  ret = (ret > 0s) ? ret : 0s;
281 
282  JLOG(m_journal.trace()) << "Validated ledger age is " << ret.count();
283  return ret;
284 }
285 
286 bool
288 {
289  using namespace std::chrono_literals;
290  if (getPublishedLedgerAge() > 3min)
291  {
292  reason = "No recently-published ledger";
293  return false;
294  }
295  std::uint32_t validClose = mValidLedgerSign.load();
296  std::uint32_t pubClose = mPubLedgerClose.load();
297  if (!validClose || !pubClose)
298  {
299  reason = "No published ledger";
300  return false;
301  }
302  if (validClose > (pubClose + 90))
303  {
304  reason = "Published ledger lags validated ledger";
305  return false;
306  }
307  return true;
308 }
309 
310 void
312 {
314  boost::optional<uint256> consensusHash;
315 
316  if (!standalone_)
317  {
318  auto validations = app_.validators().negativeUNLFilter(
319  app_.getValidations().getTrustedForLedger(l->info().hash));
320  times.reserve(validations.size());
321  for (auto const& val : validations)
322  times.push_back(val->getSignTime());
323 
324  if (!validations.empty())
325  consensusHash = validations.front()->getConsensusHash();
326  }
327 
328  NetClock::time_point signTime;
329 
330  if (!times.empty() && times.size() >= app_.validators().quorum())
331  {
332  // Calculate the sample median
333  std::sort(times.begin(), times.end());
334  auto const t0 = times[(times.size() - 1) / 2];
335  auto const t1 = times[times.size() / 2];
336  signTime = t0 + (t1 - t0) / 2;
337  }
338  else
339  {
340  signTime = l->info().closeTime;
341  }
342 
343  mValidLedger.set(l);
344  mValidLedgerSign = signTime.time_since_epoch().count();
345  assert(
349  mValidLedgerSeq = l->info().seq;
350 
351  app_.getOPs().updateLocalTx(*l);
353  mLedgerHistory.validatedLedger(l, consensusHash);
355  if (!app_.getOPs().isAmendmentBlocked())
356  {
358  {
359  JLOG(m_journal.error()) << "One or more unsupported amendments "
360  "activated: server blocked.";
362  }
363  else if (!app_.getOPs().isAmendmentWarned() || l->isFlagLedger())
364  {
365  // Amendments can lose majority, so re-check periodically (every
366  // flag ledger), and clear the flag if appropriate. If an unknown
367  // amendment gains majority log a warning as soon as it's
368  // discovered, then again every flag ledger until the operator
369  // upgrades, the amendment loses majority, or the amendment goes
370  // live and the node gets blocked. Unlike being amendment blocked,
371  // this message may be logged more than once per session, because
372  // the node will otherwise function normally, and this gives
373  // operators an opportunity to see and resolve the warning.
374  if (auto const first =
376  {
377  JLOG(m_journal.error()) << "One or more unsupported amendments "
378  "reached majority. Upgrade before "
379  << to_string(*first)
380  << " to prevent your server from "
381  "becoming amendment blocked.";
383  }
384  else
386  }
387  }
388 }
389 
390 void
392 {
393  mPubLedger = l;
394  mPubLedgerClose = l->info().closeTime.time_since_epoch().count();
395  mPubLedgerSeq = l->info().seq;
396 }
397 
398 void
400  std::shared_ptr<Transaction> const& transaction)
401 {
403  mHeldTransactions.insert(transaction->getSTransaction());
404 }
405 
406 // Validate a ledger's close time and sequence number if we're considering
407 // jumping to that ledger. This helps defend agains some rare hostile or
408 // insane majority scenarios.
409 bool
411 {
412  assert(ledger);
413 
414  // Never jump to a candidate ledger that precedes our
415  // last validated ledger
416 
417  auto validLedger = getValidatedLedger();
418  if (validLedger && (ledger->info().seq < validLedger->info().seq))
419  {
420  JLOG(m_journal.trace())
421  << "Candidate for current ledger has low seq " << ledger->info().seq
422  << " < " << validLedger->info().seq;
423  return false;
424  }
425 
426  // Ensure this ledger's parent close time is within five minutes of
427  // our current time. If we already have a known fully-valid ledger
428  // we perform this check. Otherwise, we only do it if we've built a
429  // few ledgers as our clock can be off when we first start up
430 
431  auto closeTime = app_.timeKeeper().closeTime();
432  auto ledgerClose = ledger->info().parentCloseTime;
433 
434  using namespace std::chrono_literals;
435  if ((validLedger || (ledger->info().seq > 10)) &&
436  ((std::max(closeTime, ledgerClose) - std::min(closeTime, ledgerClose)) >
437  5min))
438  {
439  JLOG(m_journal.warn())
440  << "Candidate for current ledger has close time "
441  << to_string(ledgerClose) << " at network time "
442  << to_string(closeTime) << " seq " << ledger->info().seq;
443  return false;
444  }
445 
446  if (validLedger)
447  {
448  // Sequence number must not be too high. We allow ten ledgers
449  // for time inaccuracies plus a maximum run rate of one ledger
450  // every two seconds. The goal is to prevent a malicious ledger
451  // from increasing our sequence unreasonably high
452 
453  LedgerIndex maxSeq = validLedger->info().seq + 10;
454 
455  if (closeTime > validLedger->info().parentCloseTime)
456  maxSeq += std::chrono::duration_cast<std::chrono::seconds>(
457  closeTime - validLedger->info().parentCloseTime)
458  .count() /
459  2;
460 
461  if (ledger->info().seq > maxSeq)
462  {
463  JLOG(m_journal.warn())
464  << "Candidate for current ledger has high seq "
465  << ledger->info().seq << " > " << maxSeq;
466  return false;
467  }
468 
469  JLOG(m_journal.trace())
470  << "Acceptable seq range: " << validLedger->info().seq
471  << " <= " << ledger->info().seq << " <= " << maxSeq;
472  }
473 
474  return true;
475 }
476 
477 void
479 {
480  assert(lastClosed);
481  if (!lastClosed->isImmutable())
482  LogicError("mutable ledger in switchLCL");
483 
484  if (lastClosed->open())
485  LogicError("The new last closed ledger is open!");
486 
487  {
489  mClosedLedger.set(lastClosed);
490  }
491 
492  if (standalone_)
493  {
494  setFullLedger(lastClosed, true, false);
495  tryAdvance();
496  }
497  else
498  {
499  checkAccept(lastClosed);
500  }
501 }
502 
503 bool
504 LedgerMaster::fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash)
505 {
506  return mLedgerHistory.fixIndex(ledgerIndex, ledgerHash);
507 }
508 
509 bool
511 {
512  // Returns true if we already had the ledger
513  return mLedgerHistory.insert(std::move(ledger), false);
514 }
515 
521 void
523 {
525 
526  app_.openLedger().modify([&](OpenView& view, beast::Journal j) {
527  bool any = false;
528  for (auto const& it : mHeldTransactions)
529  {
530  ApplyFlags flags = tapNONE;
531  auto const result =
532  app_.getTxQ().apply(app_, view, it.second, flags, j);
533  if (result.second)
534  any = true;
535  }
536  return any;
537  });
538 
539  // VFALCO TODO recreate the CanonicalTxSet object instead of resetting
540  // it.
541  // VFALCO NOTE The hash for an open ledger is undefined so we use
542  // something that is a reasonable substitute.
543  mHeldTransactions.reset(app_.openLedger().current()->info().parentHash);
544 }
545 
548  AccountID const& account,
549  std::uint32_t const seq)
550 {
552 
553  return mHeldTransactions.prune(account, seq);
554 }
555 
558 {
559  // The ledger we are currently building, 0 of none
560  return mBuildingLedgerSeq.load();
561 }
562 
563 void
565 {
566  mBuildingLedgerSeq.store(i);
567 }
568 
569 bool
571 {
573  return boost::icl::contains(mCompleteLedgers, seq);
574 }
575 
576 void
578 {
580  mCompleteLedgers.erase(seq);
581 }
582 
583 // returns Ledgers we have all the nodes for
584 bool
586  std::uint32_t& minVal,
587  std::uint32_t& maxVal)
588 {
589  // Validated ledger is likely not stored in the DB yet so we use the
590  // published ledger which is.
591  maxVal = mPubLedgerSeq.load();
592 
593  if (!maxVal)
594  return false;
595 
596  boost::optional<std::uint32_t> maybeMin;
597  {
599  maybeMin = prevMissing(mCompleteLedgers, maxVal);
600  }
601 
602  if (maybeMin == boost::none)
603  minVal = maxVal;
604  else
605  minVal = 1 + *maybeMin;
606 
607  return true;
608 }
609 
610 // Returns Ledgers we have all the nodes for and are indexed
611 bool
613 {
614  if (!getFullValidatedRange(minVal, maxVal))
615  return false;
616 
617  // Remove from the validated range any ledger sequences that may not be
618  // fully updated in the database yet
619 
620  auto const pendingSaves = app_.pendingSaves().getSnapshot();
621 
622  if (!pendingSaves.empty() && ((minVal != 0) || (maxVal != 0)))
623  {
624  // Ensure we shrink the tips as much as possible. If we have 7-9 and
625  // 8,9 are invalid, we don't want to see the 8 and shrink to just 9
626  // because then we'll have nothing when we could have 7.
627  while (pendingSaves.count(maxVal) > 0)
628  --maxVal;
629  while (pendingSaves.count(minVal) > 0)
630  ++minVal;
631 
632  // Best effort for remaining exclusions
633  for (auto v : pendingSaves)
634  {
635  if ((v.first >= minVal) && (v.first <= maxVal))
636  {
637  if (v.first > ((minVal + maxVal) / 2))
638  maxVal = v.first - 1;
639  else
640  minVal = v.first + 1;
641  }
642  }
643 
644  if (minVal > maxVal)
645  minVal = maxVal = 0;
646  }
647 
648  return true;
649 }
650 
651 // Get the earliest ledger we will let peers fetch
654 {
655  // The earliest ledger we will let people fetch is ledger zero,
656  // unless that creates a larger range than allowed
657  std::uint32_t e = getClosedLedger()->info().seq;
658 
659  if (e > fetch_depth_)
660  e -= fetch_depth_;
661  else
662  e = 0;
663  return e;
664 }
665 
666 void
668 {
669  std::uint32_t seq = ledger->info().seq;
670  uint256 prevHash = ledger->info().parentHash;
671 
673 
674  std::uint32_t minHas = seq;
675  std::uint32_t maxHas = seq;
676 
677  NodeStore::Database& nodeStore{app_.getNodeStore()};
678  while (!job.shouldCancel() && seq > 0)
679  {
680  {
682  minHas = seq;
683  --seq;
684 
685  if (haveLedger(seq))
686  break;
687  }
688 
689  auto it(ledgerHashes.find(seq));
690 
691  if (it == ledgerHashes.end())
692  {
693  if (app_.isShutdown())
694  return;
695 
696  {
698  mCompleteLedgers.insert(range(minHas, maxHas));
699  }
700  maxHas = minHas;
701  ledgerHashes =
702  getHashesByIndex((seq < 500) ? 0 : (seq - 499), seq, app_);
703  it = ledgerHashes.find(seq);
704 
705  if (it == ledgerHashes.end())
706  break;
707 
708  if (!nodeStore.fetch(
709  ledgerHashes.begin()->second.first,
710  ledgerHashes.begin()->first))
711  {
712  // The ledger is not backed by the node store
713  JLOG(m_journal.warn()) << "SQL DB ledger sequence " << seq
714  << " mismatches node store";
715  break;
716  }
717  }
718 
719  if (it->second.first != prevHash)
720  break;
721 
722  prevHash = it->second.second;
723  }
724 
725  {
727  mCompleteLedgers.insert(range(minHas, maxHas));
728  }
729  {
731  mFillInProgress = 0;
732  tryAdvance();
733  }
734 }
735 
738 void
740 {
741  LedgerIndex const ledgerIndex([&]() {
742  if (reason == InboundLedger::Reason::SHARD)
743  {
744  // Do not acquire a ledger sequence greater
745  // than the last ledger in the shard
746  auto const shardStore{app_.getShardStore()};
747  auto const shardIndex{shardStore->seqToShardIndex(missing)};
748  return std::min(missing + 1, shardStore->lastLedgerSeq(shardIndex));
749  }
750  return missing + 1;
751  }());
752 
753  auto const haveHash{getLedgerHashForHistory(ledgerIndex, reason)};
754  if (!haveHash || haveHash->isZero())
755  {
756  if (reason == InboundLedger::Reason::SHARD)
757  {
758  auto const shardStore{app_.getShardStore()};
759  auto const shardIndex{shardStore->seqToShardIndex(missing)};
760  if (missing < shardStore->lastLedgerSeq(shardIndex))
761  {
762  JLOG(m_journal.error())
763  << "No hash for fetch pack. "
764  << "Missing ledger sequence " << missing
765  << " while acquiring shard " << shardIndex;
766  }
767  }
768  else
769  {
770  JLOG(m_journal.error())
771  << "No hash for fetch pack. Missing Index " << missing;
772  }
773  return;
774  }
775 
776  // Select target Peer based on highest score. The score is randomized
777  // but biased in favor of Peers with low latency.
778  std::shared_ptr<Peer> target;
779  {
780  int maxScore = 0;
781  auto peerList = app_.overlay().getActivePeers();
782  for (auto const& peer : peerList)
783  {
784  if (peer->hasRange(missing, missing + 1))
785  {
786  int score = peer->getScore(true);
787  if (!target || (score > maxScore))
788  {
789  target = peer;
790  maxScore = score;
791  }
792  }
793  }
794  }
795 
796  if (target)
797  {
798  protocol::TMGetObjectByHash tmBH;
799  tmBH.set_query(true);
800  tmBH.set_type(protocol::TMGetObjectByHash::otFETCH_PACK);
801  tmBH.set_ledgerhash(haveHash->begin(), 32);
802  auto packet = std::make_shared<Message>(tmBH, protocol::mtGET_OBJECTS);
803 
804  target->send(packet);
805  JLOG(m_journal.trace()) << "Requested fetch pack for " << missing;
806  }
807  else
808  JLOG(m_journal.debug()) << "No peer for fetch pack";
809 }
810 
811 void
813 {
814  int invalidate = 0;
815  boost::optional<uint256> hash;
816 
817  for (std::uint32_t lSeq = ledger.info().seq - 1; lSeq > 0; --lSeq)
818  {
819  if (haveLedger(lSeq))
820  {
821  try
822  {
823  hash = hashOfSeq(ledger, lSeq, m_journal);
824  }
825  catch (std::exception const&)
826  {
827  JLOG(m_journal.warn())
828  << "fixMismatch encounters partial ledger";
829  clearLedger(lSeq);
830  return;
831  }
832 
833  if (hash)
834  {
835  // try to close the seam
836  auto otherLedger = getLedgerBySeq(lSeq);
837 
838  if (otherLedger && (otherLedger->info().hash == *hash))
839  {
840  // we closed the seam
841  if (invalidate != 0)
842  {
843  JLOG(m_journal.warn())
844  << "Match at " << lSeq << ", " << invalidate
845  << " prior ledgers invalidated";
846  }
847 
848  return;
849  }
850  }
851 
852  clearLedger(lSeq);
853  ++invalidate;
854  }
855  }
856 
857  // all prior ledgers invalidated
858  if (invalidate != 0)
859  {
860  JLOG(m_journal.warn())
861  << "All " << invalidate << " prior ledgers invalidated";
862  }
863 }
864 
865 void
867  std::shared_ptr<Ledger const> const& ledger,
868  bool isSynchronous,
869  bool isCurrent)
870 {
871  // A new ledger has been accepted as part of the trusted chain
872  JLOG(m_journal.debug()) << "Ledger " << ledger->info().seq
873  << " accepted :" << ledger->info().hash;
874  assert(ledger->stateMap().getHash().isNonZero());
875 
876  ledger->setValidated();
877  ledger->setFull();
878 
879  if (isCurrent)
880  mLedgerHistory.insert(ledger, true);
881 
882  {
883  // Check the SQL database's entry for the sequence before this
884  // ledger, if it's not this ledger's parent, invalidate it
885  uint256 prevHash = getHashByIndex(ledger->info().seq - 1, app_);
886  if (prevHash.isNonZero() && prevHash != ledger->info().parentHash)
887  clearLedger(ledger->info().seq - 1);
888  }
889 
890  pendSaveValidated(app_, ledger, isSynchronous, isCurrent);
891 
892  {
894  mCompleteLedgers.insert(ledger->info().seq);
895  }
896 
897  {
899 
900  if (ledger->info().seq > mValidLedgerSeq)
901  setValidLedger(ledger);
902  if (!mPubLedger)
903  {
904  setPubLedger(ledger);
905  app_.getOrderBookDB().setup(ledger);
906  }
907 
908  if (ledger->info().seq != 0 && haveLedger(ledger->info().seq - 1))
909  {
910  // we think we have the previous ledger, double check
911  auto prevLedger = getLedgerBySeq(ledger->info().seq - 1);
912 
913  if (!prevLedger ||
914  (prevLedger->info().hash != ledger->info().parentHash))
915  {
916  JLOG(m_journal.warn())
917  << "Acquired ledger invalidates previous ledger: "
918  << (prevLedger ? "hashMismatch" : "missingLedger");
919  fixMismatch(*ledger);
920  }
921  }
922  }
923 }
924 
925 void
927 {
928  clearLedger(seq);
930 }
931 
932 // Check if the specified ledger can become the new last fully-validated
933 // ledger.
934 void
936 {
937  std::size_t valCount = 0;
938 
939  if (seq != 0)
940  {
941  // Ledger is too old
942  if (seq < mValidLedgerSeq)
943  return;
944 
945  auto validations = app_.validators().negativeUNLFilter(
947  valCount = validations.size();
948  if (valCount >= app_.validators().quorum())
949  {
951  if (seq > mLastValidLedger.second)
952  mLastValidLedger = std::make_pair(hash, seq);
953  }
954 
955  if (seq == mValidLedgerSeq)
956  return;
957 
958  // Ledger could match the ledger we're already building
959  if (seq == mBuildingLedgerSeq)
960  return;
961  }
962 
963  auto ledger = mLedgerHistory.getLedgerByHash(hash);
964 
965  if (!ledger)
966  {
967  if ((seq != 0) && (getValidLedgerIndex() == 0))
968  {
969  // Set peers sane early if we can
970  if (valCount >= app_.validators().quorum())
971  app_.overlay().checkSanity(seq);
972  }
973 
974  // FIXME: We may not want to fetch a ledger with just one
975  // trusted validation
976  ledger = app_.getInboundLedgers().acquire(
977  hash, seq, InboundLedger::Reason::GENERIC);
978  }
979 
980  if (ledger)
981  checkAccept(ledger);
982 }
983 
991 {
992  return standalone_ ? 0 : app_.validators().quorum();
993 }
994 
995 void
997 {
998  // Can we accept this ledger as our new last fully-validated ledger
999 
1000  if (!canBeCurrent(ledger))
1001  return;
1002 
1003  // Can we advance the last fully-validated ledger? If so, can we
1004  // publish?
1006 
1007  if (ledger->info().seq <= mValidLedgerSeq)
1008  return;
1009 
1010  auto const minVal = getNeededValidations();
1011  auto validations = app_.validators().negativeUNLFilter(
1012  app_.getValidations().getTrustedForLedger(ledger->info().hash));
1013  auto const tvc = validations.size();
1014  if (tvc < minVal) // nothing we can do
1015  {
1016  JLOG(m_journal.trace())
1017  << "Only " << tvc << " validations for " << ledger->info().hash;
1018  return;
1019  }
1020 
1021  JLOG(m_journal.info()) << "Advancing accepted ledger to "
1022  << ledger->info().seq << " with >= " << minVal
1023  << " validations";
1024 
1025  ledger->setValidated();
1026  ledger->setFull();
1027  setValidLedger(ledger);
1028  if (!mPubLedger)
1029  {
1030  pendSaveValidated(app_, ledger, true, true);
1031  setPubLedger(ledger);
1032  app_.getOrderBookDB().setup(ledger);
1033  }
1034 
1035  std::uint32_t const base = app_.getFeeTrack().getLoadBase();
1036  auto fees = app_.getValidations().fees(ledger->info().hash, base);
1037  {
1038  auto fees2 =
1039  app_.getValidations().fees(ledger->info().parentHash, base);
1040  fees.reserve(fees.size() + fees2.size());
1041  std::copy(fees2.begin(), fees2.end(), std::back_inserter(fees));
1042  }
1043  std::uint32_t fee;
1044  if (!fees.empty())
1045  {
1046  std::sort(fees.begin(), fees.end());
1047  fee = fees[fees.size() / 2]; // median
1048  }
1049  else
1050  {
1051  fee = base;
1052  }
1053 
1054  app_.getFeeTrack().setRemoteFee(fee);
1055 
1056  tryAdvance();
1057 
1058  if (ledger->seq() % 256 == 0)
1059  {
1060  // Check if the majority of validators run a higher version rippled
1061  // software. If so print a warning.
1062  //
1063  // Once the HardenedValidations amendment is enabled, validators include
1064  // their rippled software version in the validation messages of every
1065  // (flag - 1) ledger. We wait for one ledger time before checking the
1066  // version information to accumulate more validation messages.
1067 
1068  auto currentTime = app_.timeKeeper().now();
1069  bool needPrint = false;
1070 
1071  // The variable upgradeWarningPrevTime_ will be set when and only when
1072  // the warning is printed.
1074  {
1075  // Have not printed the warning before, check if need to print.
1076  auto const vals = app_.getValidations().getTrustedForLedger(
1077  ledger->info().parentHash);
1078  std::size_t higherVersionCount = 0;
1079  std::size_t rippledCount = 0;
1080  for (auto const& v : vals)
1081  {
1082  if (v->isFieldPresent(sfServerVersion))
1083  {
1084  auto version = v->getFieldU64(sfServerVersion);
1085  higherVersionCount +=
1086  BuildInfo::isNewerVersion(version) ? 1 : 0;
1087  rippledCount +=
1088  BuildInfo::isRippledVersion(version) ? 1 : 0;
1089  }
1090  }
1091  // We report only if (1) we have accumulated validation messages
1092  // from 90% validators from the UNL, (2) 60% of validators
1093  // running the rippled implementation have higher version numbers,
1094  // and (3) the calculation won't cause divide-by-zero.
1095  if (higherVersionCount > 0 && rippledCount > 0)
1096  {
1097  constexpr std::size_t reportingPercent = 90;
1098  constexpr std::size_t cutoffPercent = 60;
1099  auto const unlSize{
1100  app_.validators().getQuorumKeys().second.size()};
1101  needPrint = unlSize > 0 &&
1102  calculatePercent(vals.size(), unlSize) >=
1103  reportingPercent &&
1104  calculatePercent(higherVersionCount, rippledCount) >=
1105  cutoffPercent;
1106  }
1107  }
1108  // To throttle the warning messages, instead of printing a warning
1109  // every flag ledger, we print every week.
1110  else if (currentTime - upgradeWarningPrevTime_ >= weeks{1})
1111  {
1112  // Printed the warning before, and assuming most validators
1113  // do not downgrade, we keep printing the warning
1114  // until the local server is restarted.
1115  needPrint = true;
1116  }
1117 
1118  if (needPrint)
1119  {
1120  upgradeWarningPrevTime_ = currentTime;
1121  auto const upgradeMsg =
1122  "Check for upgrade: "
1123  "A majority of trusted validators are "
1124  "running a newer version.";
1125  std::cerr << upgradeMsg << std::endl;
1126  JLOG(m_journal.error()) << upgradeMsg;
1127  }
1128  }
1129 }
1130 
1132 void
1134  std::shared_ptr<Ledger const> const& ledger,
1135  uint256 const& consensusHash,
1136  Json::Value consensus)
1137 {
1138  // Because we just built a ledger, we are no longer building one
1139  setBuildingLedger(0);
1140 
1141  // No need to process validations in standalone mode
1142  if (standalone_)
1143  return;
1144 
1145  mLedgerHistory.builtLedger(ledger, consensusHash, std::move(consensus));
1146 
1147  if (ledger->info().seq <= mValidLedgerSeq)
1148  {
1149  auto stream = app_.journal("LedgerConsensus").info();
1150  JLOG(stream) << "Consensus built old ledger: " << ledger->info().seq
1151  << " <= " << mValidLedgerSeq;
1152  return;
1153  }
1154 
1155  // See if this ledger can be the new fully-validated ledger
1156  checkAccept(ledger);
1157 
1158  if (ledger->info().seq <= mValidLedgerSeq)
1159  {
1160  auto stream = app_.journal("LedgerConsensus").debug();
1161  JLOG(stream) << "Consensus ledger fully validated";
1162  return;
1163  }
1164 
1165  // This ledger cannot be the new fully-validated ledger, but
1166  // maybe we saved up validations for some other ledger that can be
1167 
1168  auto validations = app_.validators().negativeUNLFilter(
1170 
1171  // Track validation counts with sequence numbers
1172  class valSeq
1173  {
1174  public:
1175  valSeq() : valCount_(0), ledgerSeq_(0)
1176  {
1177  ;
1178  }
1179 
1180  void
1181  mergeValidation(LedgerIndex seq)
1182  {
1183  valCount_++;
1184 
1185  // If we didn't already know the sequence, now we do
1186  if (ledgerSeq_ == 0)
1187  ledgerSeq_ = seq;
1188  }
1189 
1190  std::size_t valCount_;
1191  LedgerIndex ledgerSeq_;
1192  };
1193 
1194  // Count the number of current, trusted validations
1196  for (auto const& v : validations)
1197  {
1198  valSeq& vs = count[v->getLedgerHash()];
1199  vs.mergeValidation(v->getFieldU32(sfLedgerSequence));
1200  }
1201 
1202  auto const neededValidations = getNeededValidations();
1203  auto maxSeq = mValidLedgerSeq.load();
1204  auto maxLedger = ledger->info().hash;
1205 
1206  // Of the ledgers with sufficient validations,
1207  // find the one with the highest sequence
1208  for (auto& v : count)
1209  if (v.second.valCount_ > neededValidations)
1210  {
1211  // If we still don't know the sequence, get it
1212  if (v.second.ledgerSeq_ == 0)
1213  {
1214  if (auto l = getLedgerByHash(v.first))
1215  v.second.ledgerSeq_ = l->info().seq;
1216  }
1217 
1218  if (v.second.ledgerSeq_ > maxSeq)
1219  {
1220  maxSeq = v.second.ledgerSeq_;
1221  maxLedger = v.first;
1222  }
1223  }
1224 
1225  if (maxSeq > mValidLedgerSeq)
1226  {
1227  auto stream = app_.journal("LedgerConsensus").debug();
1228  JLOG(stream) << "Consensus triggered check of ledger";
1229  checkAccept(maxLedger, maxSeq);
1230  }
1231 }
1232 
1233 void
1235 {
1237  assert(!mValidLedger.empty() && mAdvanceThread);
1238 
1239  JLOG(m_journal.trace()) << "advanceThread<";
1240 
1241  try
1242  {
1243  doAdvance(sl);
1244  }
1245  catch (std::exception const&)
1246  {
1247  JLOG(m_journal.fatal()) << "doAdvance throws an exception";
1248  }
1249 
1250  mAdvanceThread = false;
1251  JLOG(m_journal.trace()) << "advanceThread>";
1252 }
1253 
1254 boost::optional<LedgerHash>
1256  LedgerIndex index,
1257  InboundLedger::Reason reason)
1258 {
1259  // Try to get the hash of a ledger we need to fetch for history
1260  boost::optional<LedgerHash> ret;
1261  auto const& l{
1263 
1264  if (l && l->info().seq >= index)
1265  {
1266  ret = hashOfSeq(*l, index, m_journal);
1267  if (!ret)
1268  ret = walkHashBySeq(index, l, reason);
1269  }
1270 
1271  if (!ret)
1272  ret = walkHashBySeq(index, reason);
1273 
1274  return ret;
1275 }
1276 
1280 {
1282 
1283  JLOG(m_journal.trace()) << "findNewLedgersToPublish<";
1284 
1285  // No valid ledger, nothing to do
1286  if (mValidLedger.empty())
1287  {
1288  JLOG(m_journal.trace()) << "No valid journal, nothing to publish.";
1289  return {};
1290  }
1291 
1292  if (!mPubLedger)
1293  {
1294  JLOG(m_journal.info())
1295  << "First published ledger will be " << mValidLedgerSeq;
1296  return {mValidLedger.get()};
1297  }
1298 
1300  {
1301  JLOG(m_journal.warn()) << "Gap in validated ledger stream "
1302  << mPubLedgerSeq << " - " << mValidLedgerSeq - 1;
1303 
1304  auto valLedger = mValidLedger.get();
1305  ret.push_back(valLedger);
1306  setPubLedger(valLedger);
1307  app_.getOrderBookDB().setup(valLedger);
1308 
1309  return {valLedger};
1310  }
1311 
1313  {
1314  JLOG(m_journal.trace()) << "No valid journal, nothing to publish.";
1315  return {};
1316  }
1317 
1318  int acqCount = 0;
1319 
1320  auto pubSeq = mPubLedgerSeq + 1; // Next sequence to publish
1321  auto valLedger = mValidLedger.get();
1322  std::uint32_t valSeq = valLedger->info().seq;
1323 
1324  ScopedUnlock sul{sl};
1325  try
1326  {
1327  for (std::uint32_t seq = pubSeq; seq <= valSeq; ++seq)
1328  {
1329  JLOG(m_journal.trace())
1330  << "Trying to fetch/publish valid ledger " << seq;
1331 
1333  // This can throw
1334  auto hash = hashOfSeq(*valLedger, seq, m_journal);
1335  // VFALCO TODO Restructure this code so that zero is not
1336  // used.
1337  if (!hash)
1338  hash = beast::zero; // kludge
1339  if (seq == valSeq)
1340  {
1341  // We need to publish the ledger we just fully validated
1342  ledger = valLedger;
1343  }
1344  else if (hash->isZero())
1345  {
1346  JLOG(m_journal.fatal()) << "Ledger: " << valSeq
1347  << " does not have hash for " << seq;
1348  assert(false);
1349  }
1350  else
1351  {
1352  ledger = mLedgerHistory.getLedgerByHash(*hash);
1353  }
1354 
1355  // Can we try to acquire the ledger we need?
1356  if (!ledger && (++acqCount < ledger_fetch_size_))
1357  ledger = app_.getInboundLedgers().acquire(
1358  *hash, seq, InboundLedger::Reason::GENERIC);
1359 
1360  // Did we acquire the next ledger we need to publish?
1361  if (ledger && (ledger->info().seq == pubSeq))
1362  {
1363  ledger->setValidated();
1364  ret.push_back(ledger);
1365  ++pubSeq;
1366  }
1367  }
1368 
1369  JLOG(m_journal.trace())
1370  << "ready to publish " << ret.size() << " ledgers.";
1371  }
1372  catch (std::exception const&)
1373  {
1374  JLOG(m_journal.error())
1375  << "Exception while trying to find ledgers to publish.";
1376  }
1377 
1378  return ret;
1379 }
1380 
1381 void
1383 {
1385 
1386  // Can't advance without at least one fully-valid ledger
1387  mAdvanceWork = true;
1388  if (!mAdvanceThread && !mValidLedger.empty())
1389  {
1390  mAdvanceThread = true;
1392  jtADVANCE, "advanceLedger", [this](Job&) { advanceThread(); });
1393  }
1394 }
1395 
1396 void
1398 {
1399  {
1402  {
1403  --mPathFindThread;
1404  return;
1405  }
1406  }
1407 
1408  while (!job.shouldCancel())
1409  {
1411  {
1413 
1414  if (!mValidLedger.empty() &&
1415  (!mPathLedger || (mPathLedger->info().seq != mValidLedgerSeq)))
1416  { // We have a new valid ledger since the last full pathfinding
1418  lastLedger = mPathLedger;
1419  }
1420  else if (mPathFindNewRequest)
1421  { // We have a new request but no new ledger
1422  lastLedger = app_.openLedger().current();
1423  }
1424  else
1425  { // Nothing to do
1426  --mPathFindThread;
1427  return;
1428  }
1429  }
1430 
1431  if (!standalone_)
1432  { // don't pathfind with a ledger that's more than 60 seconds old
1433  using namespace std::chrono;
1434  auto age = time_point_cast<seconds>(app_.timeKeeper().closeTime()) -
1435  lastLedger->info().closeTime;
1436  if (age > 1min)
1437  {
1438  JLOG(m_journal.debug())
1439  << "Published ledger too old for updating paths";
1441  --mPathFindThread;
1442  return;
1443  }
1444  }
1445 
1446  try
1447  {
1449  lastLedger, job.getCancelCallback());
1450  }
1451  catch (SHAMapMissingNode const& mn)
1452  {
1453  JLOG(m_journal.info()) << "During pathfinding: " << mn.what();
1454  if (lastLedger->open())
1455  {
1456  // our parent is the problem
1458  lastLedger->info().parentHash,
1459  lastLedger->info().seq - 1,
1461  }
1462  else
1463  {
1464  // this ledger is the problem
1466  lastLedger->info().hash,
1467  lastLedger->info().seq,
1469  }
1470  }
1471  }
1472 }
1473 
1474 bool
1476 {
1478  mPathFindNewRequest = newPFWork("pf:newRequest", ml);
1479  return mPathFindNewRequest;
1480 }
1481 
1482 bool
1484 {
1486  bool const ret = mPathFindNewRequest;
1487  mPathFindNewRequest = false;
1488  return ret;
1489 }
1490 
1491 // If the order book is radically updated, we need to reprocess all
1492 // pathfinding requests.
1493 bool
1495 {
1497  mPathLedger.reset();
1498 
1499  return newPFWork("pf:newOBDB", ml);
1500 }
1501 
1504 bool
1506  const char* name,
1508 {
1509  if (mPathFindThread < 2)
1510  {
1511  if (app_.getJobQueue().addJob(
1512  jtUPDATE_PF, name, [this](Job& j) { updatePaths(j); }))
1513  {
1514  ++mPathFindThread;
1515  }
1516  }
1517  // If we're stopping don't give callers the expectation that their
1518  // request will be fulfilled, even if it may be serviced.
1519  return mPathFindThread > 0 && !isStopping();
1520 }
1521 
1524 {
1525  return m_mutex;
1526 }
1527 
1528 // The current ledger is the ledger we believe new transactions should go in
1531 {
1532  return app_.openLedger().current();
1533 }
1534 
1535 Rules
1537 {
1538  // Once we have a guarantee that there's always a last validated
1539  // ledger then we can dispense with the if.
1540 
1541  // Return the Rules from the last validated ledger.
1542  if (auto const ledger = getValidatedLedger())
1543  return ledger->rules();
1544 
1545  return Rules(app_.config().features);
1546 }
1547 
1548 // This is the last ledger we published to clients and can lag the validated
1549 // ledger.
1552 {
1553  std::lock_guard lock(m_mutex);
1554  return mPubLedger;
1555 }
1556 
1559 {
1561  return to_string(mCompleteLedgers);
1562 }
1563 
1564 boost::optional<NetClock::time_point>
1566 {
1567  uint256 hash = getHashBySeq(ledgerIndex);
1568  return hash.isNonZero() ? getCloseTimeByHash(hash, ledgerIndex)
1569  : boost::none;
1570 }
1571 
1572 boost::optional<NetClock::time_point>
1574  LedgerHash const& ledgerHash,
1575  std::uint32_t index)
1576 {
1577  auto node = app_.getNodeStore().fetch(ledgerHash, index);
1578  if (node && (node->getData().size() >= 120))
1579  {
1580  SerialIter it(node->getData().data(), node->getData().size());
1581  if (safe_cast<HashPrefix>(it.get32()) == HashPrefix::ledgerMaster)
1582  {
1583  it.skip(
1584  4 + 8 + 32 + // seq drops parentHash
1585  32 + 32 + 4); // txHash acctHash parentClose
1587  }
1588  }
1589 
1590  return boost::none;
1591 }
1592 
1593 uint256
1595 {
1596  uint256 hash = mLedgerHistory.getLedgerHash(index);
1597 
1598  if (hash.isNonZero())
1599  return hash;
1600 
1601  return getHashByIndex(index, app_);
1602 }
1603 
1604 boost::optional<LedgerHash>
1606 {
1607  boost::optional<LedgerHash> ledgerHash;
1608 
1609  if (auto referenceLedger = mValidLedger.get())
1610  ledgerHash = walkHashBySeq(index, referenceLedger, reason);
1611 
1612  return ledgerHash;
1613 }
1614 
1615 boost::optional<LedgerHash>
1617  std::uint32_t index,
1618  std::shared_ptr<ReadView const> const& referenceLedger,
1619  InboundLedger::Reason reason)
1620 {
1621  if (!referenceLedger || (referenceLedger->info().seq < index))
1622  {
1623  // Nothing we can do. No validated ledger.
1624  return boost::none;
1625  }
1626 
1627  // See if the hash for the ledger we need is in the reference ledger
1628  auto ledgerHash = hashOfSeq(*referenceLedger, index, m_journal);
1629  if (ledgerHash)
1630  return ledgerHash;
1631 
1632  // The hash is not in the reference ledger. Get another ledger which can
1633  // be located easily and should contain the hash.
1634  LedgerIndex refIndex = getCandidateLedger(index);
1635  auto const refHash = hashOfSeq(*referenceLedger, refIndex, m_journal);
1636  assert(refHash);
1637  if (refHash)
1638  {
1639  // Try the hash and sequence of a better reference ledger just found
1640  auto ledger = mLedgerHistory.getLedgerByHash(*refHash);
1641 
1642  if (ledger)
1643  {
1644  try
1645  {
1646  ledgerHash = hashOfSeq(*ledger, index, m_journal);
1647  }
1648  catch (SHAMapMissingNode const&)
1649  {
1650  ledger.reset();
1651  }
1652  }
1653 
1654  // Try to acquire the complete ledger
1655  if (!ledger)
1656  {
1657  if (auto const l = app_.getInboundLedgers().acquire(
1658  *refHash, refIndex, reason))
1659  {
1660  ledgerHash = hashOfSeq(*l, index, m_journal);
1661  assert(ledgerHash);
1662  }
1663  }
1664  }
1665  return ledgerHash;
1666 }
1667 
1670 {
1671  if (index <= mValidLedgerSeq)
1672  {
1673  // Always prefer a validated ledger
1674  if (auto valid = mValidLedger.get())
1675  {
1676  if (valid->info().seq == index)
1677  return valid;
1678 
1679  try
1680  {
1681  auto const hash = hashOfSeq(*valid, index, m_journal);
1682 
1683  if (hash)
1684  return mLedgerHistory.getLedgerByHash(*hash);
1685  }
1686  catch (std::exception const&)
1687  {
1688  // Missing nodes are already handled
1689  }
1690  }
1691  }
1692 
1693  if (auto ret = mLedgerHistory.getLedgerBySeq(index))
1694  return ret;
1695 
1696  auto ret = mClosedLedger.get();
1697  if (ret && (ret->info().seq == index))
1698  return ret;
1699 
1700  clearLedger(index);
1701  return {};
1702 }
1703 
1706 {
1707  if (auto ret = mLedgerHistory.getLedgerByHash(hash))
1708  return ret;
1709 
1710  auto ret = mClosedLedger.get();
1711  if (ret && (ret->info().hash == hash))
1712  return ret;
1713 
1714  return {};
1715 }
1716 
1717 void
1719 {
1720  mLedgerCleaner->doClean(parameters);
1721 }
1722 
1723 void
1725 {
1727  mCompleteLedgers.insert(range(minV, maxV));
1728 }
1729 
1730 void
1732 {
1733  mLedgerHistory.tune(size, age);
1734 }
1735 
1736 void
1738 {
1740  fetch_packs_.sweep();
1741 }
1742 
1743 float
1745 {
1747 }
1748 
1751 {
1752  return *mLedgerCleaner;
1753 }
1754 
1755 void
1757 {
1759  if (seq > 0)
1760  mCompleteLedgers.erase(range(0u, seq - 1));
1761 }
1762 
1763 void
1765 {
1767 }
1768 
1769 void
1771 {
1772  replayData = std::move(replay);
1773 }
1774 
1777 {
1778  return std::move(replayData);
1779 }
1780 
1781 void
1783  std::uint32_t missing,
1784  bool& progress,
1785  InboundLedger::Reason reason,
1787 {
1788  ScopedUnlock sul{sl};
1789  if (auto hash = getLedgerHashForHistory(missing, reason))
1790  {
1791  assert(hash->isNonZero());
1792  auto ledger = getLedgerByHash(*hash);
1793  if (!ledger)
1794  {
1795  if (!app_.getInboundLedgers().isFailure(*hash))
1796  {
1797  ledger =
1798  app_.getInboundLedgers().acquire(*hash, missing, reason);
1799  if (!ledger && missing != fetch_seq_ &&
1800  missing > app_.getNodeStore().earliestLedgerSeq())
1801  {
1802  JLOG(m_journal.trace())
1803  << "fetchForHistory want fetch pack " << missing;
1804  fetch_seq_ = missing;
1805  getFetchPack(missing, reason);
1806  }
1807  else
1808  JLOG(m_journal.trace())
1809  << "fetchForHistory no fetch pack for " << missing;
1810  }
1811  else
1812  JLOG(m_journal.debug())
1813  << "fetchForHistory found failed acquire";
1814  }
1815  if (ledger)
1816  {
1817  auto seq = ledger->info().seq;
1818  assert(seq == missing);
1819  JLOG(m_journal.trace()) << "fetchForHistory acquired " << seq;
1820  if (reason == InboundLedger::Reason::SHARD)
1821  {
1822  ledger->setFull();
1823  {
1824  std::lock_guard lock(m_mutex);
1825  mShardLedger = ledger;
1826  }
1827  if (!ledger->stateMap().family().isShardBacked())
1828  app_.getShardStore()->storeLedger(ledger);
1829  }
1830  else
1831  {
1832  setFullLedger(ledger, false, false);
1833  int fillInProgress;
1834  {
1835  std::lock_guard lock(m_mutex);
1836  mHistLedger = ledger;
1837  fillInProgress = mFillInProgress;
1838  }
1839  if (fillInProgress == 0 &&
1840  getHashByIndex(seq - 1, app_) == ledger->info().parentHash)
1841  {
1842  {
1843  // Previous ledger is in DB
1844  std::lock_guard lock(m_mutex);
1845  mFillInProgress = seq;
1846  }
1848  jtADVANCE, "tryFill", [this, ledger](Job& j) {
1849  tryFill(j, ledger);
1850  });
1851  }
1852  }
1853  progress = true;
1854  }
1855  else
1856  {
1857  std::uint32_t fetchSz;
1858  if (reason == InboundLedger::Reason::SHARD)
1859  // Do not fetch ledger sequences lower
1860  // than the shard's first ledger sequence
1861  fetchSz = app_.getShardStore()->firstLedgerSeq(
1862  app_.getShardStore()->seqToShardIndex(missing));
1863  else
1864  // Do not fetch ledger sequences lower
1865  // than the earliest ledger sequence
1866  fetchSz = app_.getNodeStore().earliestLedgerSeq();
1867  fetchSz = missing >= fetchSz
1868  ? std::min(ledger_fetch_size_, (missing - fetchSz) + 1)
1869  : 0;
1870  try
1871  {
1872  for (std::uint32_t i = 0; i < fetchSz; ++i)
1873  {
1874  std::uint32_t seq = missing - i;
1875  if (auto h = getLedgerHashForHistory(seq, reason))
1876  {
1877  assert(h->isNonZero());
1878  app_.getInboundLedgers().acquire(*h, seq, reason);
1879  }
1880  }
1881  }
1882  catch (std::exception const&)
1883  {
1884  JLOG(m_journal.warn()) << "Threw while prefetching";
1885  }
1886  }
1887  }
1888  else
1889  {
1890  JLOG(m_journal.fatal())
1891  << "Can't find ledger following prevMissing " << missing;
1892  JLOG(m_journal.fatal())
1893  << "Pub:" << mPubLedgerSeq << " Val:" << mValidLedgerSeq;
1894  JLOG(m_journal.fatal())
1895  << "Ledgers: " << app_.getLedgerMaster().getCompleteLedgers();
1896  JLOG(m_journal.fatal())
1897  << "Acquire reason: "
1898  << (reason == InboundLedger::Reason::HISTORY ? "HISTORY" : "SHARD");
1899  clearLedger(missing + 1);
1900  progress = true;
1901  }
1902 }
1903 
1904 // Try to publish ledgers, acquire missing ledgers
1905 void
1907 {
1908  do
1909  {
1910  mAdvanceWork = false; // If there's work to do, we'll make progress
1911  bool progress = false;
1912 
1913  auto const pubLedgers = findNewLedgersToPublish(sl);
1914  if (pubLedgers.empty())
1915  {
1916  if (!standalone_ && !app_.getFeeTrack().isLoadedLocal() &&
1921  {
1922  // We are in sync, so can acquire
1924  boost::optional<std::uint32_t> missing;
1925  {
1927  missing = prevMissing(
1929  mPubLedger->info().seq,
1931  }
1932  if (missing)
1933  {
1934  JLOG(m_journal.trace())
1935  << "tryAdvance discovered missing " << *missing;
1936  if ((mFillInProgress == 0 || *missing > mFillInProgress) &&
1937  shouldAcquire(
1941  *missing,
1942  m_journal))
1943  {
1944  JLOG(m_journal.trace())
1945  << "advanceThread should acquire";
1946  }
1947  else
1948  missing = boost::none;
1949  }
1950  if (!missing && mFillInProgress == 0)
1951  {
1952  if (auto shardStore = app_.getShardStore())
1953  {
1954  missing = shardStore->prepareLedger(mValidLedgerSeq);
1955  if (missing)
1957  }
1958  }
1959  if (missing)
1960  {
1961  fetchForHistory(*missing, progress, reason, sl);
1963  {
1964  JLOG(m_journal.debug())
1965  << "tryAdvance found last valid changed";
1966  progress = true;
1967  }
1968  }
1969  }
1970  else
1971  {
1972  mHistLedger.reset();
1973  mShardLedger.reset();
1974  JLOG(m_journal.trace()) << "tryAdvance not fetching history";
1975  }
1976  }
1977  else
1978  {
1979  JLOG(m_journal.trace()) << "tryAdvance found " << pubLedgers.size()
1980  << " ledgers to publish";
1981  for (auto ledger : pubLedgers)
1982  {
1983  {
1984  ScopedUnlock sul{sl};
1985  JLOG(m_journal.debug())
1986  << "tryAdvance publishing seq " << ledger->info().seq;
1987  setFullLedger(ledger, true, true);
1988  }
1989 
1990  setPubLedger(ledger);
1991 
1992  {
1993  ScopedUnlock sul{sl};
1994  app_.getOPs().pubLedger(ledger);
1995  }
1996  }
1997 
1999  progress = newPFWork("pf:newLedger", sl);
2000  }
2001  if (progress)
2002  mAdvanceWork = true;
2003  } while (mAdvanceWork);
2004 }
2005 
2006 void
2008 {
2009  fetch_packs_.canonicalize_replace_client(hash, data);
2010 }
2011 
2012 boost::optional<Blob>
2014 {
2015  Blob data;
2016  if (fetch_packs_.retrieve(hash, data))
2017  {
2018  fetch_packs_.del(hash, false);
2019  if (hash == sha512Half(makeSlice(data)))
2020  return data;
2021  }
2022  return boost::none;
2023 }
2024 
2025 void
2027 {
2028  if (!mGotFetchPackThread.test_and_set(std::memory_order_acquire))
2029  {
2030  app_.getJobQueue().addJob(jtLEDGER_DATA, "gotFetchPack", [&](Job&) {
2032  mGotFetchPackThread.clear(std::memory_order_release);
2033  });
2034  }
2035 }
2036 
2037 void
2039  std::weak_ptr<Peer> const& wPeer,
2041  uint256 haveLedgerHash,
2042  UptimeClock::time_point uptime)
2043 {
2044  using namespace std::chrono_literals;
2045  if (UptimeClock::now() > uptime + 1s)
2046  {
2047  JLOG(m_journal.info()) << "Fetch pack request got stale";
2048  return;
2049  }
2050 
2051  if (app_.getFeeTrack().isLoadedLocal() || (getValidatedLedgerAge() > 40s))
2052  {
2053  JLOG(m_journal.info()) << "Too busy to make fetch pack";
2054  return;
2055  }
2056 
2057  auto peer = wPeer.lock();
2058 
2059  if (!peer)
2060  return;
2061 
2062  auto haveLedger = getLedgerByHash(haveLedgerHash);
2063 
2064  if (!haveLedger)
2065  {
2066  JLOG(m_journal.info())
2067  << "Peer requests fetch pack for ledger we don't have: "
2068  << haveLedger;
2069  peer->charge(Resource::feeRequestNoReply);
2070  return;
2071  }
2072 
2073  if (haveLedger->open())
2074  {
2075  JLOG(m_journal.warn())
2076  << "Peer requests fetch pack from open ledger: " << haveLedger;
2077  peer->charge(Resource::feeInvalidRequest);
2078  return;
2079  }
2080 
2081  if (haveLedger->info().seq < getEarliestFetch())
2082  {
2083  JLOG(m_journal.debug()) << "Peer requests fetch pack that is too early";
2084  peer->charge(Resource::feeInvalidRequest);
2085  return;
2086  }
2087 
2088  auto wantLedger = getLedgerByHash(haveLedger->info().parentHash);
2089 
2090  if (!wantLedger)
2091  {
2092  JLOG(m_journal.info())
2093  << "Peer requests fetch pack for ledger whose predecessor we "
2094  << "don't have: " << haveLedger;
2095  peer->charge(Resource::feeRequestNoReply);
2096  return;
2097  }
2098 
2099  auto fpAppender = [](protocol::TMGetObjectByHash* reply,
2100  std::uint32_t ledgerSeq,
2101  SHAMapHash const& hash,
2102  const Blob& blob) {
2103  protocol::TMIndexedObject& newObj = *(reply->add_objects());
2104  newObj.set_ledgerseq(ledgerSeq);
2105  newObj.set_hash(hash.as_uint256().begin(), 256 / 8);
2106  newObj.set_data(&blob[0], blob.size());
2107  };
2108 
2109  try
2110  {
2111  protocol::TMGetObjectByHash reply;
2112  reply.set_query(false);
2113 
2114  if (request->has_seq())
2115  reply.set_seq(request->seq());
2116 
2117  reply.set_ledgerhash(request->ledgerhash());
2118  reply.set_type(protocol::TMGetObjectByHash::otFETCH_PACK);
2119 
2120  // Building a fetch pack:
2121  // 1. Add the header for the requested ledger.
2122  // 2. Add the nodes for the AccountStateMap of that ledger.
2123  // 3. If there are transactions, add the nodes for the
2124  // transactions of the ledger.
2125  // 4. If the FetchPack now contains greater than or equal to
2126  // 256 entries then stop.
2127  // 5. If not very much time has elapsed, then loop back and repeat
2128  // the same process adding the previous ledger to the FetchPack.
2129  do
2130  {
2131  std::uint32_t lSeq = wantLedger->info().seq;
2132 
2133  protocol::TMIndexedObject& newObj = *reply.add_objects();
2134  newObj.set_hash(wantLedger->info().hash.data(), 256 / 8);
2135  Serializer s(256);
2137  addRaw(wantLedger->info(), s);
2138  newObj.set_data(s.getDataPtr(), s.getLength());
2139  newObj.set_ledgerseq(lSeq);
2140 
2141  wantLedger->stateMap().getFetchPack(
2142  &haveLedger->stateMap(),
2143  true,
2144  16384,
2145  std::bind(
2146  fpAppender,
2147  &reply,
2148  lSeq,
2149  std::placeholders::_1,
2150  std::placeholders::_2));
2151 
2152  if (wantLedger->info().txHash.isNonZero())
2153  wantLedger->txMap().getFetchPack(
2154  nullptr,
2155  true,
2156  512,
2157  std::bind(
2158  fpAppender,
2159  &reply,
2160  lSeq,
2161  std::placeholders::_1,
2162  std::placeholders::_2));
2163 
2164  if (reply.objects().size() >= 512)
2165  break;
2166 
2167  // move may save a ref/unref
2168  haveLedger = std::move(wantLedger);
2169  wantLedger = getLedgerByHash(haveLedger->info().parentHash);
2170  } while (wantLedger && UptimeClock::now() <= uptime + 1s);
2171 
2172  JLOG(m_journal.info())
2173  << "Built fetch pack with " << reply.objects().size() << " nodes";
2174  auto msg = std::make_shared<Message>(reply, protocol::mtGET_OBJECTS);
2175  peer->send(msg);
2176  }
2177  catch (std::exception const&)
2178  {
2179  JLOG(m_journal.warn()) << "Exception building fetch pach";
2180  }
2181 }
2182 
2185 {
2186  return fetch_packs_.getCacheSize();
2187 }
2188 
2189 // Returns the minimum ledger sequence in SQL database, if any.
2190 boost::optional<LedgerIndex>
2192 {
2193  boost::optional<LedgerIndex> seq;
2194  auto db = app_.getLedgerDB().checkoutDb();
2195  *db << "SELECT MIN(LedgerSeq) FROM Ledgers", soci::into(seq);
2196  return seq;
2197 }
2198 
2199 } // namespace ripple
ripple::NetworkOPs::pubLedger
virtual void pubLedger(std::shared_ptr< ReadView const > const &lpAccepted)=0
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::ReadView::info
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
ripple::LedgerMaster::getValidatedRange
bool getValidatedRange(std::uint32_t &minVal, std::uint32_t &maxVal)
Definition: LedgerMaster.cpp:612
ripple::LedgerMaster::mPubLedger
std::shared_ptr< Ledger const > mPubLedger
Definition: LedgerMaster.h:346
ripple::Resource::feeInvalidRequest
const Charge feeInvalidRequest
Schedule of fees charged for imposing load on the server.
ripple::Application
Definition: Application.h:97
ripple::LedgerMaster::mClosedLedger
LedgerHolder mClosedLedger
Definition: LedgerMaster.h:340
ripple::Application::getOrderBookDB
virtual OrderBookDB & getOrderBookDB()=0
ripple::InboundLedger::Reason::HISTORY
@ HISTORY
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
std::lock
T lock(T... args)
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:240
ripple::NodeStore::Database::getWriteLoad
virtual std::int32_t getWriteLoad() const =0
Retrieve the estimated number of pending write operations.
ripple::LedgerMaster::getPublishedLedger
std::shared_ptr< ReadView const > getPublishedLedger()
Definition: LedgerMaster.cpp:1551
ripple::LedgerIndex
std::uint32_t LedgerIndex
A ledger index.
Definition: Protocol.h:57
std::bind
T bind(T... args)
ripple::LedgerMaster::fetch_packs_
TaggedCache< uint256, Blob > fetch_packs_
Definition: LedgerMaster.h:402
ripple::OpenLedger::current
std::shared_ptr< OpenView const > current() const
Returns a view to the current open ledger.
Definition: OpenLedger.cpp:50
ripple::NodeStore::Database
Persistency layer for NodeObject.
Definition: Database.h:53
ripple::LedgerMaster::makeFetchPack
void makeFetchPack(std::weak_ptr< Peer > const &wPeer, std::shared_ptr< protocol::TMGetObjectByHash > const &request, uint256 haveLedgerHash, UptimeClock::time_point uptime)
Definition: LedgerMaster.cpp:2038
ripple::LedgerMaster::clearLedgerCachePrior
void clearLedgerCachePrior(LedgerIndex seq)
Definition: LedgerMaster.cpp:1764
std::string
STL class.
std::shared_ptr< Collector >
ripple::LedgerMaster::sweep
void sweep()
Definition: LedgerMaster.cpp:1737
ripple::SizedItem
SizedItem
Definition: Config.h:48
std::exception
STL class.
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:480
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::LedgerMaster::mBuildingLedgerSeq
std::atomic< LedgerIndex > mBuildingLedgerSeq
Definition: LedgerMaster.h:389
ripple::LedgerMaster::app_
Application & app_
Definition: LedgerMaster.h:334
ripple::LedgerMaster::advanceThread
void advanceThread()
Definition: LedgerMaster.cpp:1234
ripple::NodeStore::DatabaseShard::seqToShardIndex
virtual std::uint32_t seqToShardIndex(std::uint32_t seq) const =0
Calculates the shard index for a given ledger sequence.
ripple::apply
std::pair< TER, bool > apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition: apply.cpp:109
ripple::LedgerMaster::minSqlSeq
boost::optional< LedgerIndex > minSqlSeq()
Definition: LedgerMaster.cpp:2191
ripple::LedgerMaster::pruneHeldTransactions
std::vector< std::shared_ptr< STTx const > > pruneHeldTransactions(AccountID const &account, std::uint32_t const seq)
Get all the transactions held for a particular account.
Definition: LedgerMaster.cpp:547
ripple::LedgerMaster::mLedgerHistory
LedgerHistory mLedgerHistory
Definition: LedgerMaster.h:360
ripple::LedgerMaster::getLedgerHashForHistory
boost::optional< LedgerHash > getLedgerHashForHistory(LedgerIndex index, InboundLedger::Reason reason)
Definition: LedgerMaster.cpp:1255
std::atomic_flag::test_and_set
T test_and_set(T... args)
ripple::LedgerMaster::mHeldTransactions
CanonicalTXSet mHeldTransactions
Definition: LedgerMaster.h:362
std::pair::second
T second
std::vector::reserve
T reserve(T... args)
ripple::LedgerHistory::fixIndex
bool fixIndex(LedgerIndex ledgerIndex, LedgerHash const &ledgerHash)
Repair a hash to index mapping.
Definition: LedgerHistory.cpp:513
ripple::Validations::fees
std::vector< std::uint32_t > fees(ID const &ledgerID, std::uint32_t baseFee)
Returns fees reported by trusted full validators in the given ledger.
Definition: Validations.h:1033
beast::PropertyStream::Source
Subclasses can be called to write to a stream and have children.
Definition: PropertyStream.h:342
ripple::LedgerHolder::set
void set(std::shared_ptr< Ledger const > ledger)
Definition: LedgerHolder.h:43
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:212
ripple::Application::getAmendmentTable
virtual AmendmentTable & getAmendmentTable()=0
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:52
ripple::Application::isShutdown
virtual bool isShutdown()=0
ripple::InboundLedger::Reason::GENERIC
@ GENERIC
vector
std::map::find
T find(T... args)
std::vector::size
T size(T... args)
ripple::LedgerMaster::mHistLedger
std::shared_ptr< Ledger const > mHistLedger
Definition: LedgerMaster.h:352
ripple::LedgerMaster::getPublishedLedgerAge
std::chrono::seconds getPublishedLedgerAge()
Definition: LedgerMaster.cpp:249
std::back_inserter
T back_inserter(T... args)
ripple::LedgerMaster::upgradeWarningPrevTime_
TimeKeeper::time_point upgradeWarningPrevTime_
Definition: LedgerMaster.h:411
ripple::ValidatorList::getQuorumKeys
QuorumKeys getQuorumKeys() const
Get the quorum and all of the trusted keys.
Definition: ValidatorList.h:506
ripple::LedgerMaster::releaseReplay
std::unique_ptr< LedgerReplay > releaseReplay()
Definition: LedgerMaster.cpp:1776
std::chrono::minutes
ripple::ApplyFlags
ApplyFlags
Definition: ApplyView.h:30
ripple::SHAMapStore::onLedgerClosed
virtual void onLedgerClosed(std::shared_ptr< Ledger const > const &ledger)=0
Called by LedgerMaster every time a ledger validates.
ripple::LedgerMaster::getValidatedRules
Rules getValidatedRules()
Definition: LedgerMaster.cpp:1536
ripple::AmendmentTable::doValidatedLedger
void doValidatedLedger(std::shared_ptr< ReadView const > const &lastValidatedLedger)
Called when a new fully-validated ledger is accepted.
Definition: AmendmentTable.h:76
ripple::LedgerMaster::mCompleteLock
std::recursive_mutex mCompleteLock
Definition: LedgerMaster.h:367
ripple::LedgerHistory::tune
void tune(int size, std::chrono::seconds age)
Set the history cache's parameters.
Definition: LedgerHistory.cpp:527
ripple::LedgerMaster::applyHeldTransactions
void applyHeldTransactions()
Apply held transactions to the open ledger This is normally called as we close the ledger.
Definition: LedgerMaster.cpp:522
ripple::LedgerMaster::switchLCL
void switchLCL(std::shared_ptr< Ledger const > const &lastClosed)
Definition: LedgerMaster.cpp:478
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
std::recursive_mutex
STL class.
ripple::LedgerMaster::newPFWork
bool newPFWork(const char *name, std::unique_lock< std::recursive_mutex > &)
A thread needs to be dispatched to handle pathfinding work of some kind.
Definition: LedgerMaster.cpp:1505
std::lock_guard
STL class.
ripple::NetworkOPs::setAmendmentBlocked
virtual void setAmendmentBlocked()=0
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
ripple::NetworkOPs::isAmendmentWarned
virtual bool isAmendmentWarned()=0
ripple::LedgerMaster::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
Definition: LedgerMaster.cpp:1705
std::cerr
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s)
Definition: View.cpp:43
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:1605
ripple::LedgerMaster::isNewPathRequest
bool isNewPathRequest()
Definition: LedgerMaster.cpp:1483
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:166
ripple::stopwatch
Stopwatch & stopwatch()
Returns an instance of a wall clock.
Definition: chrono.h:86
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:88
ripple::LoadFeeTrack::getLoadBase
std::uint32_t getLoadBase() const
Definition: LoadFeeTrack.h:87
ripple::LedgerMaster::getCloseTimeByHash
boost::optional< NetClock::time_point > getCloseTimeByHash(LedgerHash const &ledgerHash, LedgerIndex ledgerIndex)
Definition: LedgerMaster.cpp:1573
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::jtUPDATE_PF
@ jtUPDATE_PF
Definition: Job.h:50
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
ripple::LedgerMaster::getEarliestFetch
std::uint32_t getEarliestFetch()
Definition: LedgerMaster.cpp:653
ripple::NetworkOPs::isAmendmentBlocked
virtual bool isAmendmentBlocked()=0
ripple::Application::openLedger
virtual OpenLedger & openLedger()=0
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:31
ripple::SizedItem::ledgerFetch
@ ledgerFetch
ripple::LedgerHistory::sweep
void sweep()
Remove stale cache entries.
Definition: LedgerHistory.h:81
ripple::Resource::feeRequestNoReply
const Charge feeRequestNoReply
ripple::LedgerHistory::getLedgerHash
LedgerHash getLedgerHash(LedgerIndex ledgerIndex)
Get a ledger's hash given its sequence number.
Definition: LedgerHistory.cpp:80
ripple::LedgerMaster::setFullLedger
void setFullLedger(std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
Definition: LedgerMaster.cpp:866
std::sort
T sort(T... args)
ripple::LedgerMaster::tune
void tune(int size, std::chrono::seconds age)
Definition: LedgerMaster.cpp:1731
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:43
algorithm
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::jtLEDGER_DATA
@ jtLEDGER_DATA
Definition: Job.h:47
ripple::LedgerMaster::fixMismatch
void fixMismatch(ReadView const &ledger)
Definition: LedgerMaster.cpp:812
std::atomic_flag::clear
T clear(T... args)
ripple::LedgerMaster::fetch_depth_
const std::uint32_t fetch_depth_
Definition: LedgerMaster.h:395
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::LedgerHistory::builtLedger
void builtLedger(std::shared_ptr< Ledger const > const &, uint256 const &consensusHash, Json::Value)
Report that we have locally built a particular ledger.
Definition: LedgerHistory.cpp:431
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::LedgerMaster::getCompleteLedgers
std::string getCompleteLedgers()
Definition: LedgerMaster.cpp:1558
ripple::LedgerMaster::ledger_fetch_size_
const std::uint32_t ledger_fetch_size_
Definition: LedgerMaster.h:400
ripple::Job::getCancelCallback
CancelCallback getCancelCallback() const
Definition: Job.cpp:58
ripple::BuildInfo::isRippledVersion
bool isRippledVersion(std::uint64_t version)
Check if the encoded software version is a rippled software version.
Definition: BuildInfo.cpp:158
ripple::getHashByIndex
uint256 getHashByIndex(std::uint32_t ledgerIndex, Application &app)
Definition: Ledger.cpp:1258
ripple::SHAMapMissingNode
Definition: SHAMapMissingNode.h:55
ripple::JobQueue::getJobCount
int getJobCount(JobType t) const
Jobs waiting at this priority.
Definition: JobQueue.cpp:121
std::vector::push_back
T push_back(T... args)
ripple::LedgerMaster::peekMutex
std::recursive_mutex & peekMutex()
Definition: LedgerMaster.cpp:1523
ripple::LedgerMaster::mGotFetchPackThread
std::atomic_flag mGotFetchPackThread
Definition: LedgerMaster.h:382
ripple::base_uint< 256 >
ripple::LoadFeeTrack::isLoadedLocal
bool isLoadedLocal() const
Definition: LoadFeeTrack.h:123
ripple::jtPUBOLDLEDGER
@ jtPUBOLDLEDGER
Definition: Job.h:42
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::LedgerMaster::mCompleteLedgers
RangeSet< std::uint32_t > mCompleteLedgers
Definition: LedgerMaster.h:368
ripple::LedgerMaster::getPropertySource
beast::PropertyStream::Source & getPropertySource()
Definition: LedgerMaster.cpp:1750
ripple::LedgerMaster::LedgerMaster
LedgerMaster(Application &app, Stopwatch &stopwatch, Stoppable &parent, beast::insight::Collector::ptr const &collector, beast::Journal journal)
Definition: LedgerMaster.cpp:178
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:200
ripple::UptimeClock::now
static time_point now()
Definition: UptimeClock.cpp:63
ripple::LedgerMaster::mFillInProgress
int mFillInProgress
Definition: LedgerMaster.h:377
ripple::NetworkOPs::isNeedNetworkLedger
virtual bool isNeedNetworkLedger()=0
ripple::LedgerHistory::insert
bool insert(std::shared_ptr< Ledger const > ledger, bool validated)
Track a ledger.
Definition: LedgerHistory.cpp:62
ripple::DatabaseCon::checkoutDb
LockedSociSession checkoutDb()
Definition: DatabaseCon.h:176
ripple::LedgerMaster::replayData
std::unique_ptr< LedgerReplay > replayData
Definition: LedgerMaster.h:365
ripple::LedgerMaster::gotFetchPack
void gotFetchPack(bool progress, std::uint32_t seq)
Definition: LedgerMaster.cpp:2026
ripple::LedgerMaster::fetchForHistory
void fetchForHistory(std::uint32_t missing, bool &progress, InboundLedger::Reason reason, std::unique_lock< std::recursive_mutex > &)
Definition: LedgerMaster.cpp:1782
ripple::LedgerMaster::failedSave
void failedSave(std::uint32_t seq, uint256 const &hash)
Definition: LedgerMaster.cpp:926
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::InboundLedgers::acquire
virtual std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason)=0
std::atomic::load
T load(T... args)
ripple::Job::shouldCancel
bool shouldCancel() const
Returns true if the running job should make a best-effort cancel.
Definition: Job.cpp:71
ripple::NetworkOPs::setAmendmentWarned
virtual void setAmendmentWarned()=0
ripple::Application::pendingSaves
virtual PendingSaves & pendingSaves()=0
ripple::SHAMapStore::minimumOnline
virtual boost::optional< LedgerIndex > minimumOnline() const =0
The minimum ledger to try and maintain in our database.
ripple::LedgerHolder::empty
bool empty()
Definition: LedgerHolder.h:62
ripple::LedgerHistory::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(LedgerHash const &ledgerHash)
Retrieve a ledger given its hash.
Definition: LedgerHistory.cpp:125
ripple::Serializer::getDataPtr
const void * getDataPtr() const
Definition: Serializer.h:187
ripple::MAX_LEDGER_GAP
static constexpr int MAX_LEDGER_GAP
Definition: LedgerMaster.cpp:141
ripple::LedgerMaster::getFetchPack
boost::optional< Blob > getFetchPack(uint256 const &hash) override
Retrieves partial ledger data of the coresponding hash from peers.
Definition: LedgerMaster.cpp:2013
ripple::NodeStore::Database::fetch
virtual std::shared_ptr< NodeObject > fetch(uint256 const &hash, std::uint32_t seq)=0
Fetch an object.
ripple::LedgerMaster::getFullValidatedRange
bool getFullValidatedRange(std::uint32_t &minVal, std::uint32_t &maxVal)
Definition: LedgerMaster.cpp:585
ripple::NetworkOPs::updateLocalTx
virtual void updateLocalTx(ReadView const &newValidLedger)=0
ripple::Application::config
virtual Config & config()=0
ripple::LedgerMaster::fixIndex
bool fixIndex(LedgerIndex ledgerIndex, LedgerHash const &ledgerHash)
Definition: LedgerMaster.cpp:504
ripple::isCurrent
bool isCurrent(ValidationParms const &p, NetClock::time_point now, NetClock::time_point signTime, NetClock::time_point seenTime)
Whether a validation is still current.
Definition: Validations.h:145
ripple::prevMissing
boost::optional< T > prevMissing(RangeSet< T > const &rs, T t, T minVal=0)
Find the largest value not in the set that is less than a given value.
Definition: RangeSet.h:184
std::unique_lock
STL class.
ripple::LedgerMaster::canBeCurrent
bool canBeCurrent(std::shared_ptr< Ledger const > const &ledger)
Check the sequence number and parent close time of a ledger against our clock and last validated ledg...
Definition: LedgerMaster.cpp:410
ripple::Application::getTxQ
virtual TxQ & getTxQ()=0
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::LedgerMaster::haveLedger
bool haveLedger(std::uint32_t seq)
Definition: LedgerMaster.cpp:570
ripple::LedgerMaster::getValidatedLedger
std::shared_ptr< Ledger const > getValidatedLedger()
Definition: LedgerMaster.h:94
ripple::calculatePercent
constexpr std::size_t calculatePercent(std::size_t count, std::size_t total)
Calculate one number divided by another number in percentage.
Definition: MathUtilities.h:44
beast::Journal::Stream
Provide a light-weight way to check active() before string formatting.
Definition: Journal.h:194
ripple::sfLedgerSequence
const SF_U32 sfLedgerSequence(access, STI_UINT32, 6, "LedgerSequence")
Definition: SField.h:358
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::LedgerMaster::isCompatible
bool isCompatible(ReadView const &, beast::Journal::Stream, char const *reason)
Definition: LedgerMaster.cpp:218
std::chrono::time_point
ripple::Overlay::checkSanity
virtual void checkSanity(std::uint32_t index)=0
Calls the checkSanity function on each peer.
ripple::OrderBookDB::setup
void setup(std::shared_ptr< ReadView const > const &ledger)
Definition: OrderBookDB.cpp:46
ripple::LedgerHistory::validatedLedger
void validatedLedger(std::shared_ptr< Ledger const > const &, boost::optional< uint256 > const &consensusHash)
Report that we have validated a particular ledger.
Definition: LedgerHistory.cpp:472
std::copy
T copy(T... args)
ripple::LedgerMaster::getLedgerBySeq
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
Definition: LedgerMaster.cpp:1669
ripple::Overlay::getActivePeers
virtual PeerSequence getActivePeers() const =0
Returns a sequence representing the current list of peers.
ripple::TimeKeeper::closeTime
virtual time_point closeTime() const =0
Returns the close time, in network time.
ripple::LedgerMaster::newPathRequest
bool newPathRequest()
Definition: LedgerMaster.cpp:1475
ripple::Job
Definition: Job.h:82
ripple::SerialIter
Definition: Serializer.h:308
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::Application::getValidations
virtual RCLValidations & getValidations()=0
ripple::Application::getLedgerDB
virtual DatabaseCon & getLedgerDB()=0
std::uint32_t
ripple::LedgerMaster::mLedgerCleaner
std::unique_ptr< detail::LedgerCleaner > mLedgerCleaner
Definition: LedgerMaster.h:370
ripple::NodeStore::Database::earliestLedgerSeq
std::uint32_t earliestLedgerSeq() const
Definition: Database.h:236
ripple::LedgerMaster::addHeldTransaction
void addHeldTransaction(std::shared_ptr< Transaction > const &trans)
Definition: LedgerMaster.cpp:399
ripple::SerialIter::skip
void skip(int num)
Definition: Serializer.cpp:344
ripple::LedgerMaster::setValidLedger
void setValidLedger(std::shared_ptr< Ledger const > const &l)
Definition: LedgerMaster.cpp:311
ripple::NetworkOPs::clearNeedNetworkLedger
virtual void clearNeedNetworkLedger()=0
std::map
STL class.
ripple::NodeStore::DatabaseShard::firstLedgerSeq
virtual std::uint32_t firstLedgerSeq(std::uint32_t shardIndex) const =0
Calculates the first ledger sequence for a given shard index.
ripple::LedgerHistory::getLedgerBySeq
std::shared_ptr< Ledger const > getLedgerBySeq(LedgerIndex ledgerIndex)
Get a ledger given its sequence number.
Definition: LedgerHistory.cpp:92
ripple::LedgerMaster::mPathFindNewRequest
bool mPathFindNewRequest
Definition: LedgerMaster.h:380
ripple::range
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition: RangeSet.h:53
ripple::Application::getPathRequests
virtual PathRequests & getPathRequests()=0
ripple::LedgerHolder::get
std::shared_ptr< Ledger const > get()
Definition: LedgerHolder.h:55
ripple::CanonicalTXSet::insert
void insert(std::shared_ptr< STTx const > const &txn)
Definition: CanonicalTXSet.cpp:107
ripple::LedgerMaster::getCurrentLedger
std::shared_ptr< ReadView const > getCurrentLedger()
Definition: LedgerMaster.cpp:1530
ripple::PendingSaves::getSnapshot
std::map< LedgerIndex, bool > getSnapshot() const
Get a snapshot of the pending saves.
Definition: PendingSaves.h:137
ripple::Validations::getTrustedForLedger
std::vector< WrappedValidationType > getTrustedForLedger(ID const &ledgerID)
Get trusted full validations for a specific ledger.
Definition: Validations.h:1010
ripple::LedgerMaster::newOrderBookDB
bool newOrderBookDB()
Definition: LedgerMaster.cpp:1494
ripple::LedgerMaster::getNeededValidations
std::size_t getNeededValidations()
Determines how many validations are needed to fully validate a ledger.
Definition: LedgerMaster.cpp:990
beast::abstract_clock< std::chrono::steady_clock >
memory
ripple::ValidatorList::negativeUNLFilter
std::vector< std::shared_ptr< STValidation > > negativeUNLFilter(std::vector< std::shared_ptr< STValidation >> &&validations) const
Remove validations that are from validators on the negative UNL.
Definition: ValidatorList.cpp:1004
ripple::areCompatible
bool areCompatible(ReadView const &validLedger, ReadView const &testLedger, beast::Journal::Stream &s, const char *reason)
Return false if the test ledger is provably incompatible with the valid ledger, that is,...
Definition: View.cpp:358
ripple::LedgerMaster::mAdvanceThread
bool mAdvanceThread
Definition: LedgerMaster.h:373
ripple::LedgerMaster::checkAccept
void checkAccept(std::shared_ptr< Ledger const > const &ledger)
Definition: LedgerMaster.cpp:996
ripple::Application::validators
virtual ValidatorList & validators()=0
ripple::AmendmentTable::hasUnsupportedEnabled
virtual bool hasUnsupportedEnabled() const =0
returns true if one or more amendments on the network have been enabled that this server does not sup...
ripple::LedgerMaster::NO_VALIDATED_LEDGER_AGE
static constexpr std::chrono::seconds NO_VALIDATED_LEDGER_AGE
Definition: LedgerMaster.h:58
std::weak_ptr
STL class.
std::min
T min(T... args)
ripple::LedgerMaster::max_ledger_difference_
const LedgerIndex max_ledger_difference_
Definition: LedgerMaster.h:408
ripple::Serializer
Definition: Serializer.h:39
ripple::LedgerMaster::getFetchPackCacheSize
std::size_t getFetchPackCacheSize() const
Definition: LedgerMaster.cpp:2184
ripple::BuildInfo::isNewerVersion
bool isNewerVersion(std::uint64_t version)
Check if the version is newer than the local node's rippled software version.
Definition: BuildInfo.cpp:165
ripple::LedgerMaster::doLedgerCleaner
void doLedgerCleaner(Json::Value const &parameters)
Definition: LedgerMaster.cpp:1718
ripple::hashOfSeq
boost::optional< uint256 > hashOfSeq(ReadView const &ledger, LedgerIndex seq, beast::Journal journal)
Return the hash of a ledger by sequence.
Definition: View.cpp:573
ripple::LedgerMaster::mPathLedger
std::shared_ptr< Ledger const > mPathLedger
Definition: LedgerMaster.h:349
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:268
ripple::LedgerMaster::getClosedLedger
std::shared_ptr< Ledger const > getClosedLedger()
Definition: LedgerMaster.h:87
ripple::LedgerMaster::mAdvanceWork
bool mAdvanceWork
Definition: LedgerMaster.h:376
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:188
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Config::features
std::unordered_set< uint256, beast::uhash<> > features
Definition: Config.h:185
ripple::NodeStore::Database::storeLedger
virtual bool storeLedger(std::shared_ptr< Ledger const > const &srcLedger)=0
Copies a ledger stored in a different database to this one.
ripple::shouldAcquire
static bool shouldAcquire(std::uint32_t const currentLedger, std::uint32_t const ledgerHistory, boost::optional< LedgerIndex > const minimumOnline, std::uint32_t const candidateLedger, beast::Journal j)
Definition: LedgerMaster.cpp:152
ripple::LedgerMaster::mPubLedgerClose
std::atomic< std::uint32_t > mPubLedgerClose
Definition: LedgerMaster.h:385
ripple::Application::getNodeStore
virtual NodeStore::Database & getNodeStore()=0
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::LedgerMaster::ledger_history_
const std::uint32_t ledger_history_
Definition: LedgerMaster.h:398
ripple::LedgerMaster::mPubLedgerSeq
std::atomic< LedgerIndex > mPubLedgerSeq
Definition: LedgerMaster.h:386
std::endl
T endl(T... args)
ripple::LedgerHistory::getCacheHitRate
float getCacheHitRate()
Get the ledgers_by_hash cache hit rate.
Definition: LedgerHistory.h:51
ripple::LedgerMaster::getBuildingLedger
LedgerIndex getBuildingLedger()
Definition: LedgerMaster.cpp:557
limits
ripple::LedgerMaster::addFetchPack
void addFetchPack(uint256 const &hash, std::shared_ptr< Blob > data)
Definition: LedgerMaster.cpp:2007
ripple::LedgerMaster::clearLedger
void clearLedger(std::uint32_t seq)
Definition: LedgerMaster.cpp:577
std::vector::begin
T begin(T... args)
ripple::NetworkOPs::clearAmendmentWarned
virtual void clearAmendmentWarned()=0
ripple::LedgerMaster::m_journal
beast::Journal m_journal
Definition: LedgerMaster.h:335
ripple::LedgerMaster::getCloseTimeBySeq
boost::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
Definition: LedgerMaster.cpp:1565
std
STL namespace.
ripple::LogicError
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:48
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:227
cassert
ripple::CanonicalTXSet::prune
std::vector< std::shared_ptr< STTx const > > prune(AccountID const &account, std::uint32_t const seq)
Definition: CanonicalTXSet.cpp:117
ripple::MAX_LEDGER_AGE_ACQUIRE
static constexpr std::chrono::minutes MAX_LEDGER_AGE_ACQUIRE
Definition: LedgerMaster.cpp:144
ripple::LedgerMaster::mValidLedgerSeq
std::atomic< LedgerIndex > mValidLedgerSeq
Definition: LedgerMaster.h:388
ripple::LedgerMaster::getCurrentLedgerIndex
LedgerIndex getCurrentLedgerIndex()
Definition: LedgerMaster.cpp:206
ripple::TimeKeeper::now
virtual time_point now() const override=0
Returns the estimate of wall time, in network time.
ripple::Application::overlay
virtual Overlay & overlay()=0
std::chrono::seconds::count
T count(T... args)
ripple::LedgerMaster::takeReplay
void takeReplay(std::unique_ptr< LedgerReplay > replay)
Definition: LedgerMaster.cpp:1770
ripple::LedgerMaster::mLastValidLedger
std::pair< uint256, LedgerIndex > mLastValidLedger
Definition: LedgerMaster.h:358
std::vector::empty
T empty(T... args)
ripple::Rules
Rules controlling protocol behavior.
Definition: ReadView.h:127
ripple::LedgerHistory::clearLedgerCachePrior
void clearLedgerCachePrior(LedgerIndex seq)
Definition: LedgerHistory.cpp:534
ripple::LedgerMaster::mShardLedger
std::shared_ptr< Ledger const > mShardLedger
Definition: LedgerMaster.h:355
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::LedgerMaster::updatePaths
void updatePaths(Job &job)
Definition: LedgerMaster.cpp:1397
std::size_t
ripple::getHashesByIndex
bool getHashesByIndex(std::uint32_t ledgerIndex, uint256 &ledgerHash, uint256 &parentHash, Application &app)
Definition: Ledger.cpp:1287
std::make_pair
T make_pair(T... args)
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::LedgerMaster::storeLedger
bool storeLedger(std::shared_ptr< Ledger const > ledger)
Definition: LedgerMaster.cpp:510
std::vector::end
T end(T... args)
ripple::InboundLedger::Reason
Reason
Definition: InboundLedger.h:51
ripple::Application::getSHAMapStore
virtual SHAMapStore & getSHAMapStore()=0
ripple::LedgerMaster::setLedgerRangePresent
void setLedgerRangePresent(std::uint32_t minV, std::uint32_t maxV)
Definition: LedgerMaster.cpp:1724
ripple::jtADVANCE
@ jtADVANCE
Definition: Job.h:53
std::max
T max(T... args)
ripple::Serializer::getLength
int getLength() const
Definition: Serializer.h:197
ripple::getCandidateLedger
LedgerIndex getCandidateLedger(LedgerIndex requested)
Find a ledger index from which we could easily get the requested ledger.
Definition: View.h:187
ripple::LedgerMaster::consensusBuilt
void consensusBuilt(std::shared_ptr< Ledger const > const &ledger, uint256 const &consensusHash, Json::Value consensus)
Report that the consensus process built a particular ledger.
Definition: LedgerMaster.cpp:1133
ripple::PathRequests::updateAll
void updateAll(std::shared_ptr< ReadView const > const &ledger, Job::CancelCallback shouldCancel)
Update all of the contained PathRequest instances.
Definition: PathRequests.cpp:58
ripple::SerialIter::get32
std::uint32_t get32()
Definition: Serializer.cpp:378
ripple::LedgerMaster::mValidLedger
LedgerHolder mValidLedger
Definition: LedgerMaster.h:343
ripple::LedgerMaster::fetch_seq_
std::uint32_t fetch_seq_
Definition: LedgerMaster.h:404
ripple::LoadFeeTrack::setRemoteFee
void setRemoteFee(std::uint32_t f)
Definition: LoadFeeTrack.h:59
ripple::LedgerMaster::getHashBySeq
uint256 getHashBySeq(std::uint32_t index)
Get a ledger's hash by sequence number using the cache.
Definition: LedgerMaster.cpp:1594
ripple::LedgerMaster::findNewLedgersToPublish
std::vector< std::shared_ptr< Ledger const > > findNewLedgersToPublish(std::unique_lock< std::recursive_mutex > &)
Definition: LedgerMaster.cpp:1278
ripple::pendSaveValidated
bool pendSaveValidated(Application &app, std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
Save, or arrange to save, a fully-validated ledger Returns false on error.
Definition: Ledger.cpp:1059
ripple::LedgerMaster::isCaughtUp
bool isCaughtUp(std::string &reason)
Definition: LedgerMaster.cpp:287
std::unique_ptr
STL class.
ripple::LedgerMaster::mPathFindThread
int mPathFindThread
Definition: LedgerMaster.h:379
ripple::InboundLedger::Reason::SHARD
@ SHARD
ripple::LedgerMaster::mValidLedgerSign
std::atomic< std::uint32_t > mValidLedgerSign
Definition: LedgerMaster.h:387
ripple::LedgerMaster::setBuildingLedger
void setBuildingLedger(LedgerIndex index)
Definition: LedgerMaster.cpp:564
ripple::LedgerMaster::doAdvance
void doAdvance(std::unique_lock< std::recursive_mutex > &)
Definition: LedgerMaster.cpp:1906
std::unordered_map
STL class.
ripple::LedgerMaster::tryAdvance
void tryAdvance()
Definition: LedgerMaster.cpp:1382
ripple::LedgerMaster::clearPriorLedgers
void clearPriorLedgers(LedgerIndex seq)
Definition: LedgerMaster.cpp:1756
ripple::LedgerMaster::setPubLedger
void setPubLedger(std::shared_ptr< Ledger const > const &l)
Definition: LedgerMaster.cpp:391
beast::abstract_clock< NetClock >::time_point
typename NetClock ::time_point time_point
Definition: abstract_clock.h:63
ripple::OpenLedger::modify
bool modify(modify_type const &f)
Modify the open ledger.
Definition: OpenLedger.cpp:57
ripple::InboundLedgers::isFailure
virtual bool isFailure(uint256 const &h)=0
ripple::LedgerMaster::tryFill
void tryFill(Job &job, std::shared_ptr< Ledger const > ledger)
Definition: LedgerMaster.cpp:667
ripple::AmendmentTable::firstUnsupportedExpected
virtual boost::optional< NetClock::time_point > firstUnsupportedExpected() const =0
std::runtime_error::what
T what(T... args)
ripple::LedgerMaster::getCacheHitRate
float getCacheHitRate()
Definition: LedgerMaster.cpp:1744
ripple::CanonicalTXSet::reset
void reset(LedgerHash const &salt)
Definition: CanonicalTXSet.h:100
ripple::sfServerVersion
const SF_U64 sfServerVersion(access, STI_UINT64, 11, "ServerVersion")
Definition: SField.h:405
ripple::MAX_WRITE_LOAD_ACQUIRE
static constexpr int MAX_WRITE_LOAD_ACQUIRE
Definition: LedgerMaster.cpp:147
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:342
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::Application::getMaxDisallowedLedger
virtual LedgerIndex getMaxDisallowedLedger()=0
Ensure that a newly-started validator does not sign proposals older than the last ledger it persisted...
ripple::LedgerMaster::m_mutex
std::recursive_mutex m_mutex
Definition: LedgerMaster.h:337
ripple::Validations::currentTrusted
std::vector< WrappedValidationType > currentTrusted()
Get the currently trusted full validations.
Definition: Validations.h:952
ripple::LedgerMaster::collect_metrics
void collect_metrics()
Definition: LedgerMaster.h:437
ripple::Stoppable::isStopping
bool isStopping() const
Returns true if the stoppable should stop.
Definition: Stoppable.cpp:54
ripple::LedgerMaster::standalone_
const bool standalone_
Definition: LedgerMaster.h:392
std::chrono