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