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