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