1#include <xrpld/app/ledger/LedgerMaster.h>
3#include <xrpld/app/consensus/RCLValidations.h>
4#include <xrpld/app/ledger/InboundLedger.h>
5#include <xrpld/app/ledger/InboundLedgers.h>
6#include <xrpld/app/ledger/LedgerPersistence.h>
7#include <xrpld/app/ledger/LedgerReplay.h>
8#include <xrpld/app/ledger/LedgerReplayer.h>
9#include <xrpld/app/ledger/OpenLedger.h>
10#include <xrpld/app/main/Application.h>
11#include <xrpld/app/misc/SHAMapStore.h>
12#include <xrpld/app/misc/Transaction.h>
13#include <xrpld/app/misc/TxQ.h>
14#include <xrpld/app/misc/ValidatorList.h>
15#include <xrpld/core/Config.h>
16#include <xrpld/core/TimeKeeper.h>
17#include <xrpld/overlay/Overlay.h>
18#include <xrpld/overlay/Peer.h>
19#include <xrpld/rpc/detail/PathRequestManager.h>
21#include <xrpl/basics/Log.h>
22#include <xrpl/basics/MathUtilities.h>
23#include <xrpl/basics/RangeSet.h>
24#include <xrpl/basics/Slice.h>
25#include <xrpl/basics/UnorderedContainers.h>
26#include <xrpl/basics/UptimeClock.h>
27#include <xrpl/basics/base_uint.h>
28#include <xrpl/basics/chrono.h>
29#include <xrpl/basics/contract.h>
30#include <xrpl/basics/safe_cast.h>
31#include <xrpl/basics/scope.h>
32#include <xrpl/beast/insight/Collector.h>
33#include <xrpl/beast/utility/Journal.h>
34#include <xrpl/beast/utility/Zero.h>
35#include <xrpl/beast/utility/instrumentation.h>
36#include <xrpl/core/Job.h>
37#include <xrpl/json/json_value.h>
38#include <xrpl/ledger/AmendmentTable.h>
39#include <xrpl/ledger/Ledger.h>
40#include <xrpl/ledger/OrderBookDB.h>
41#include <xrpl/ledger/PendingSaves.h>
42#include <xrpl/ledger/View.h>
43#include <xrpl/nodestore/Database.h>
44#include <xrpl/protocol/BuildInfo.h>
45#include <xrpl/protocol/HashPrefix.h>
46#include <xrpl/protocol/LedgerHeader.h>
47#include <xrpl/protocol/Protocol.h>
48#include <xrpl/protocol/RippleLedgerHash.h>
49#include <xrpl/protocol/SField.h>
50#include <xrpl/protocol/Serializer.h>
51#include <xrpl/protocol/digest.h>
52#include <xrpl/rdb/RelationalDatabase.h>
53#include <xrpl/resource/Fees.h>
54#include <xrpl/server/LoadFeeTrack.h>
55#include <xrpl/server/NetworkOPs.h>
56#include <xrpl/shamap/SHAMap.h>
57#include <xrpl/shamap/SHAMapMissingNode.h>
58#include <xrpl/shamap/SHAMapTreeNode.h>
60#include <boost/icl/concept/interval_associator.hpp>
61#include <boost/icl/concept/interval_set.hpp>
128 bool const ret = [&]() {
130 if (candidateLedger >= currentLedger)
134 if (currentLedger - candidateLedger <= ledgerHistory)
139 return minimumOnline.
has_value() && candidateLedger >= *minimumOnline;
142 JLOG(j.
trace()) <<
"Missing ledger " << candidateLedger << (ret ?
" should" :
" should NOT")
162 std::chrono::seconds{45},
164 app_.getJournal(
"TaggedCache"))
172 return app_.getOpenLedger().current()->header().seq;
186 if (validLedger && !
areCompatible(*validLedger, view, s, reason))
207 using namespace std::chrono_literals;
211 JLOG(
journal_.debug()) <<
"No published ledger";
217 ret = (ret > 0s) ? ret : 0s;
222 JLOG(
journal_.trace()) <<
"Published ledger age is " << ret.
count();
231 using namespace std::chrono_literals;
236 JLOG(
journal_.debug()) <<
"No validated ledger";
242 ret = (ret > 0s) ? ret : 0s;
247 JLOG(
journal_.trace()) <<
"Validated ledger age is " << ret.
count();
256 using namespace std::chrono_literals;
260 reason =
"No recently-published ledger";
265 if ((validClose == 0u) || (pubClose == 0u))
267 reason =
"No published ledger";
270 if (validClose > (pubClose + 90))
272 reason =
"Published ledger lags validated ledger";
286 auto validations =
app_.getValidators().negativeUNLFilter(
287 app_.getValidations().getTrustedForLedger(l->header().hash, l->header().seq));
288 times.
reserve(validations.size());
289 for (
auto const& val : validations)
292 if (!validations.empty())
293 consensusHash = validations.front()->getConsensusHash();
298 if (!times.
empty() && times.
size() >=
app_.getValidators().quorum())
302 auto const t0 = times[(times.
size() - 1) / 2];
303 auto const t1 = times[times.
size() / 2];
304 signTime = t0 + (t1 - t0) / 2;
308 signTime = l->header().closeTime;
316 "xrpl::LedgerMaster::setValidLedger : valid ledger sequence");
320 app_.getOPs().updateLocalTx(*l);
323 app_.getAmendmentTable().doValidatedLedger(l);
324 if (!
app_.getOPs().isBlocked())
326 if (
app_.getAmendmentTable().hasUnsupportedEnabled())
328 JLOG(
journal_.error()) <<
"One or more unsupported amendments "
329 "activated: server blocked.";
330 app_.getOPs().setAmendmentBlocked();
332 else if (!
app_.getOPs().isAmendmentWarned() || l->isFlagLedger())
343 if (
auto const first =
app_.getAmendmentTable().firstUnsupportedExpected())
345 JLOG(
journal_.error()) <<
"One or more unsupported amendments "
346 "reached majority. Upgrade before "
348 <<
" to prevent your server from "
349 "becoming amendment blocked.";
350 app_.getOPs().setAmendmentWarned();
354 app_.getOPs().clearAmendmentWarned();
381 XRPL_ASSERT(ledger,
"xrpl::LedgerMaster::canBeCurrent : non-null input");
387 if (validLedger && (ledger->header().seq < validLedger->header().seq))
389 JLOG(
journal_.trace()) <<
"Candidate for current ledger has low seq "
390 << ledger->header().seq <<
" < " << validLedger->header().seq;
399 auto closeTime =
app_.getTimeKeeper().closeTime();
400 auto ledgerClose = ledger->header().parentCloseTime;
402 using namespace std::chrono_literals;
403 if ((validLedger || (ledger->header().seq > 10)) &&
404 ((
std::max(closeTime, ledgerClose) -
std::min(closeTime, ledgerClose)) > 5min))
406 JLOG(
journal_.warn()) <<
"Candidate for current ledger has close time "
407 <<
to_string(ledgerClose) <<
" at network time "
408 <<
to_string(closeTime) <<
" seq " << ledger->header().seq;
419 LedgerIndex maxSeq = validLedger->header().seq + 10;
421 if (closeTime > validLedger->header().parentCloseTime)
424 closeTime - validLedger->header().parentCloseTime)
429 if (ledger->header().seq > maxSeq)
431 JLOG(
journal_.warn()) <<
"Candidate for current ledger has high seq "
432 << ledger->header().seq <<
" > " << maxSeq;
436 JLOG(
journal_.trace()) <<
"Acceptable seq range: " << validLedger->header().seq
437 <<
" <= " << ledger->header().seq <<
" <= " << maxSeq;
446 XRPL_ASSERT(lastClosed,
"xrpl::LedgerMaster::switchLCL : non-null input");
447 if (!lastClosed->isImmutable())
450 if (lastClosed->open())
451 logicError(
"The new last closed ledger is open!");
478 bool const validated = ledger->header().validated;
502 app_.getOPs().processTransactionSet(
set);
555 XRPL_ASSERT(hash->isNonZero(),
"xrpl::LedgerMaster::isValidated : nonzero hash");
556 UInt256 const valHash =
app_.getRelationalDatabase().getHashByIndex(seq);
568 JLOG(
journal_.warn()) <<
"Ledger #" << seq <<
": " << mn.
what();
594 if (maybeMin == std::nullopt)
600 minVal = 1 + *maybeMin;
616 auto const pendingSaves =
app_.getPendingSaves().getSnapshot();
618 if (!pendingSaves.empty() && ((minVal != 0) || (maxVal != 0)))
623 while (pendingSaves.contains(maxVal))
625 while (pendingSaves.contains(minVal))
629 for (
auto v : pendingSaves)
631 if ((v.first >= minVal) && (v.first <= maxVal))
633 if (v.first > ((minVal + maxVal) / 2))
635 maxVal = v.first - 1;
639 minVal = v.first + 1;
674 UInt256 prevHash = ledger->header().parentHash;
682 while (!
app_.getJobQueue().isStopping() && seq > 0)
693 auto it(ledgerHashes.
find(seq));
695 if (it == ledgerHashes.
end())
697 if (
app_.isStopping())
706 app_.getRelationalDatabase().getHashesByIndex((seq < 500) ? 0 : (seq - 499), seq);
707 it = ledgerHashes.
find(seq);
709 if (it == ledgerHashes.
end())
713 ledgerHashes.
begin()->second.ledgerHash, ledgerHashes.
begin()->first))
717 <<
"SQL DB ledger sequence " << seq <<
" mismatches node store";
722 if (it->second.ledgerHash != prevHash)
725 prevHash = it->second.parentHash;
748 if (!haveHash || haveHash->isZero())
750 JLOG(
journal_.error()) <<
"No hash for fetch pack. Missing Index " << missing;
759 auto peerList =
app_.getOverlay().getActivePeers();
760 for (
auto const& peer : peerList)
762 if (peer->hasRange(missing, missing + 1))
764 int const score = peer->getScore(
true);
765 if (!target || (score > maxScore))
776 protocol::TMGetObjectByHash tmBH;
777 tmBH.set_query(
true);
778 tmBH.set_type(protocol::TMGetObjectByHash::otFETCH_PACK);
779 tmBH.set_ledgerhash(haveHash->begin(), 32);
782 target->send(packet);
783 JLOG(
journal_.trace()) <<
"Requested fetch pack for " << missing;
787 JLOG(
journal_.debug()) <<
"No peer for fetch pack";
808 <<
"fixMismatch encounters partial ledger. Exception: " << ex.
what();
818 if (otherLedger && (otherLedger->header().hash == *hash))
823 JLOG(
journal_.warn()) <<
"Match at " << lSeq <<
", " << invalidate
824 <<
" prior ledgers invalidated";
839 JLOG(
journal_.warn()) <<
"All " << invalidate <<
" prior ledgers invalidated";
850 JLOG(
journal_.debug()) <<
"Ledger " << ledger->header().seq
851 <<
" accepted :" << ledger->header().hash;
853 ledger->stateMap().getHash().isNonZero(),
854 "xrpl::LedgerMaster::setFullLedger : nonzero ledger state hash");
856 ledger->setValidated();
866 app_.getRelationalDatabase().getHashByIndex(ledger->header().seq - 1);
867 if (prevHash.
isNonZero() && prevHash != ledger->header().parentHash)
886 app_.getOrderBookDB().setup(ledger);
889 if (ledger->header().seq != 0 &&
haveLedger(ledger->header().seq - 1))
894 if (!prevLedger || (prevLedger->header().hash != ledger->header().parentHash))
896 JLOG(
journal_.warn()) <<
"Acquired ledger invalidates previous ledger: "
897 << (prevLedger ?
"hashMismatch" :
"missingLedger");
924 auto validations =
app_.getValidators().negativeUNLFilter(
925 app_.getValidations().getTrustedForLedger(hash, seq));
926 valCount = validations.size();
927 if (valCount >=
app_.getValidators().quorum())
949 if (valCount >=
app_.getValidators().quorum())
950 app_.getOverlay().checkTracking(seq);
989 auto validations =
app_.getValidators().negativeUNLFilter(
990 app_.getValidations().getTrustedForLedger(ledger->header().hash, ledger->header().seq));
991 auto const tvc = validations.size();
994 JLOG(
journal_.trace()) <<
"Only " << tvc <<
" validations for " << ledger->header().hash;
998 JLOG(
journal_.info()) <<
"Advancing accepted ledger to " << ledger->header().seq
999 <<
" with >= " << minVal <<
" validations";
1001 ledger->setValidated();
1008 app_.getOrderBookDB().setup(ledger);
1012 auto fees =
app_.getValidations().fees(ledger->header().hash, base);
1014 auto fees2 =
app_.getValidations().fees(ledger->header().parentHash, base);
1015 fees.reserve(fees.size() + fees2.size());
1022 if (
auto stream =
journal_.debug())
1025 s <<
"Received fees from validations: (" << fees.size() <<
") ";
1026 for (
auto const fee1 : fees)
1032 fee = fees[fees.size() / 2];
1039 app_.getFeeTrack().setRemoteFee(fee);
1043 if (ledger->seq() % 256 == 0)
1053 auto currentTime =
app_.getTimeKeeper().now();
1054 bool needPrint =
false;
1061 auto const vals =
app_.getValidations().getTrustedForLedger(
1062 ledger->header().parentHash, ledger->header().seq - 1);
1065 for (
auto const& v : vals)
1067 if (v->isFieldPresent(sfServerVersion))
1069 auto version = v->getFieldU64(sfServerVersion);
1078 if (higherVersionCount > 0 && xrpldCount > 0)
1080 static constexpr std::size_t kReportingPercent = 90;
1082 auto const unlSize{
app_.getValidators().getQuorumKeys().second.size()};
1083 needPrint = unlSize > 0 &&
1101 auto const upgradeMsg =
1102 "Check for upgrade: "
1103 "A majority of trusted validators are "
1104 "running a newer version.";
1106 JLOG(
journal_.error()) << upgradeMsg;
1127 ledgerHistory_.builtLedger(ledger, consensusHash, std::move(consensus));
1131 auto stream =
app_.getJournal(
"LedgerConsensus").info();
1132 JLOG(stream) <<
"Consensus built old ledger: " << ledger->header().seq
1142 auto stream =
app_.getJournal(
"LedgerConsensus").debug();
1143 JLOG(stream) <<
"Consensus ledger fully validated";
1151 app_.getValidators().negativeUNLFilter(
app_.getValidations().currentTrusted());
1199 for (
auto const& v : validations)
1201 ValSeq& vs = count[v->getLedgerHash()];
1202 vs.mergeValidation(v->getFieldU32(sfLedgerSequence));
1207 auto maxLedger = ledger->header().hash;
1211 for (
auto& v : count)
1213 if (v.second.valCount > neededValidations)
1216 if (v.second.ledgerSeq == 0)
1219 v.second.ledgerSeq = l->header().seq;
1222 if (v.second.ledgerSeq > maxSeq)
1224 maxSeq = v.second.ledgerSeq;
1225 maxLedger = v.first;
1232 auto stream =
app_.getJournal(
"LedgerConsensus").debug();
1233 JLOG(stream) <<
"Consensus triggered check of ledger";
1245 if (l && l->header().seq >= index)
1263 JLOG(
journal_.trace()) <<
"findNewLedgersToPublish<";
1268 JLOG(
journal_.trace()) <<
"No valid journal, nothing to publish.";
1286 app_.getOrderBookDB().setup(valLedger);
1293 JLOG(
journal_.trace()) <<
"No valid journal, nothing to publish.";
1308 JLOG(
journal_.trace()) <<
"Trying to fetch/publish valid ledger " << seq;
1322 else if (hash->isZero())
1325 JLOG(
journal_.fatal()) <<
"Ledger: " << valSeq <<
" does not have hash for " << seq;
1327 "xrpl::LedgerMaster::findNewLedgersToPublish : ledger "
1336 if (!
app_.config().ledgerReplay)
1341 ledger =
app_.getInboundLedgers().acquire(
1347 if (ledger && (ledger->header().seq == pubSeq))
1349 ledger->setValidated();
1355 JLOG(
journal_.trace()) <<
"ready to publish " << ret.
size() <<
" ledgers.";
1359 JLOG(
journal_.error()) <<
"Exception while trying to find ledgers to publish: "
1363 if (
app_.config().ledgerReplay)
1372 auto finishLedger = valLedger;
1373 while (startLedger->seq() + 1 < finishLedger->seq())
1375 if (
auto const parent =
1376 ledgerHistory_.getLedgerByHash(finishLedger->header().parentHash);
1379 finishLedger = parent;
1383 auto numberLedgers = finishLedger->seq() - startLedger->seq() + 1;
1385 <<
"Publish LedgerReplays " << numberLedgers
1386 <<
" ledgers, from seq=" << startLedger->header().seq <<
", "
1387 << startLedger->header().hash <<
" to seq=" << finishLedger->header().seq
1388 <<
", " << finishLedger->header().hash;
1389 app_.getLedgerReplayer().replay(
1409 app_.getJobQueue().addJob(
JtAdvance,
"AdvanceLedger", [
this]() {
1414 "xrpl::LedgerMaster::tryAdvance : has valid ledger");
1416 JLOG(
journal_.trace()) <<
"advanceThread<";
1424 JLOG(
journal_.fatal()) <<
"doAdvance throws: " << ex.
what();
1428 JLOG(
journal_.trace()) <<
"advanceThread>";
1438 if (
app_.getOPs().isNeedNetworkLedger())
1442 JLOG(
journal_.debug()) <<
"Need network ledger for updating paths";
1447 while (!
app_.getJobQueue().isStopping())
1449 JLOG(
journal_.debug()) <<
"updatePaths running";
1462 lastLedger =
app_.getOpenLedger().current();
1468 JLOG(
journal_.debug()) <<
"Nothing to do for updating paths";
1477 lastLedger->header().closeTime;
1480 JLOG(
journal_.debug()) <<
"Published ledger too old for updating paths";
1490 auto& pathRequests =
app_.getPathRequestManager();
1493 if (!pathRequests.requestsPending())
1497 JLOG(
journal_.debug()) <<
"No path requests found. Nothing to do for updating "
1503 JLOG(
journal_.debug()) <<
"Updating paths";
1504 pathRequests.updateAll(lastLedger);
1507 if (!pathRequests.requestsPending())
1509 JLOG(
journal_.debug()) <<
"No path requests left. No need for further updating "
1518 JLOG(
journal_.info()) <<
"During pathfinding: " << mn.
what();
1519 if (lastLedger->open())
1522 app_.getInboundLedgers().acquire(
1523 lastLedger->header().parentHash,
1524 lastLedger->header().seq - 1,
1530 app_.getInboundLedgers().acquire(
1531 lastLedger->header().hash,
1532 lastLedger->header().seq,
1576 if (
app_.getJobQueue().addJob(
JtUpdatePf, name, [
this]() { updatePaths(); }))
1596 return app_.getOpenLedger().current();
1613 return ledger->rules();
1643 UNREACHABLE(
"xrpl::LedgerMaster::missingFromCompleteLedgerRange : invalid parameters");
1650 auto const missing = [&target,
this] {
1655 return boost::icl::size(missing);
1668 auto nodeObject =
app_.getNodeStore().fetchNodeObject(ledgerHash, index);
1669 if (nodeObject && (nodeObject->getData().size() >= 120))
1671 SerialIter it(nodeObject->getData().data(), nodeObject->getData().size());
1681 return std::nullopt;
1689 if (
hash.isNonZero())
1692 return app_.getRelationalDatabase().getHashByIndex(index);
1712 if (!referenceLedger || (referenceLedger->header().seq < index))
1715 return std::nullopt;
1727 XRPL_ASSERT(refHash,
"xrpl::LedgerMaster::walkHashBySeq : found ledger");
1748 if (
auto const l =
app_.getInboundLedgers().acquire(*refHash, refIndex, reason))
1753 "xrpl::LedgerMaster::walkHashBySeq : has complete "
1769 if (
valid->header().seq == index)
1790 if (ret && (ret->header().seq == index))
1804 if (ret && (ret->header().hash ==
hash))
1866 XRPL_ASSERT(
hash->isNonZero(),
"xrpl::LedgerMaster::fetchForHistory : found ledger");
1870 if (!
app_.getInboundLedgers().isFailure(*
hash))
1872 ledger =
app_.getInboundLedgers().acquire(*
hash, missing, reason);
1874 missing >
app_.getNodeStore().earliestLedgerSeq())
1876 JLOG(
journal_.trace()) <<
"fetchForHistory want fetch pack " << missing;
1882 JLOG(
journal_.trace()) <<
"fetchForHistory no fetch pack for " << missing;
1887 JLOG(
journal_.debug()) <<
"fetchForHistory found failed acquire";
1892 auto seq = ledger->header().seq;
1893 XRPL_ASSERT(seq == missing,
"xrpl::LedgerMaster::fetchForHistory : sequence match");
1894 JLOG(
journal_.trace()) <<
"fetchForHistory acquired " << seq;
1896 int fillInProgress = 0;
1902 if (fillInProgress == 0 &&
1903 app_.getRelationalDatabase().getHashByIndex(seq - 1) == ledger->header().parentHash)
1910 app_.getJobQueue().addJob(
1920 fetchSz =
app_.getNodeStore().earliestLedgerSeq();
1931 "xrpl::LedgerMaster::fetchForHistory : "
1932 "prefetched ledger");
1933 app_.getInboundLedgers().acquire(*h, seq, reason);
1939 JLOG(
journal_.warn()) <<
"Threw while prefetching: " << ex.
what();
1945 JLOG(
journal_.fatal()) <<
"Can't find ledger following prevMissing " << missing;
1947 JLOG(
journal_.fatal()) <<
"Ledgers: " <<
app_.getLedgerMaster().getCompleteLedgers();
1948 JLOG(
journal_.fatal()) <<
"Acquire reason: "
1963 bool progress =
false;
1966 if (pubLedgers.empty())
1982 app_.getNodeStore().earliestLedgerSeq());
1986 JLOG(
journal_.trace()) <<
"tryAdvance discovered missing " << *missing;
1991 app_.getSHAMapStore().minimumOnline(),
1995 JLOG(
journal_.trace()) <<
"advanceThread should acquire";
1999 missing = std::nullopt;
2007 JLOG(
journal_.debug()) <<
"tryAdvance found last valid changed";
2015 JLOG(
journal_.trace()) <<
"tryAdvance not fetching history";
2021 <<
"tryAdvance found " << pubLedgers.size() <<
" ledgers to publish";
2022 for (
auto const& ledger : pubLedgers)
2026 JLOG(
journal_.debug()) <<
"tryAdvance publishing seq " << ledger->header().seq;
2034 app_.getOPs().pubLedger(ledger);
2038 app_.getOPs().clearNeedNetworkLedger();
2039 progress =
newPFWork(
"PthFindNewLed", sl);
2062 return std::nullopt;
2071 app_.getInboundLedgers().gotFetchPack();
2108 protocol::TMGetObjectByHash* into,
2110 bool withLeaves =
true)
2112 XRPL_ASSERT(cnt,
"xrpl::populateFetchPack : nonzero count input");
2117 if (!withLeaves && n.
isLeaf())
2125 protocol::TMIndexedObject* obj = into->add_objects();
2126 obj->set_ledgerseq(seq);
2127 obj->set_hash(
hash.data(),
hash.size());
2141 using namespace std::chrono_literals;
2144 JLOG(
journal_.info()) <<
"Fetch pack request got stale";
2150 JLOG(
journal_.info()) <<
"Too busy to make fetch pack";
2154 auto peer = wPeer.
lock();
2163 JLOG(
journal_.info()) <<
"Peer requests fetch pack for ledger we don't have: " << have;
2170 JLOG(
journal_.warn()) <<
"Peer requests fetch pack from open ledger: " << have;
2177 JLOG(
journal_.debug()) <<
"Peer requests fetch pack that is too early";
2186 JLOG(
journal_.info()) <<
"Peer requests fetch pack for ledger whose predecessor we "
2187 <<
"don't have: " << have;
2196 protocol::TMGetObjectByHash reply;
2197 reply.set_query(
false);
2199 reply.set_ledgerhash(request->ledgerhash());
2200 reply.set_type(protocol::TMGetObjectByHash::otFETCH_PACK);
2219 addRaw(want->header(), hdr);
2222 protocol::TMIndexedObject* obj = reply.add_objects();
2223 obj->set_hash(want->header().hash.data(), want->header().hash.size());
2225 obj->set_ledgerseq(lSeq);
2232 if (want->header().txHash.isNonZero())
2235 if (reply.objects().size() >= 512)
2238 have = std::move(want);
2244 JLOG(
journal_.info()) <<
"Built fetch pack with " << reply.objects().size() <<
" nodes ("
2245 << msg->getBufferSize() <<
" bytes)";
2251 JLOG(
journal_.warn()) <<
"Exception building fetch pack. Exception: " << ex.
what();
2265 return app_.getRelationalDatabase().getMinLedgerSeq();
2277 if (!lgr || lgr->txs.empty())
2280 for (
auto it = lgr->txs.begin(); it != lgr->txs.end(); ++it)
2282 if (it->first && it->second && it->second->isFieldPresent(sfTransactionIndex) &&
2283 it->second->getFieldU32(sfTransactionIndex) == txnIndex)
2284 return it->first->getTransactionID();
T back_inserter(T... args)
NetClock::time_point time_point
Provide a light-weight way to check active() before string formatting.
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
std::shared_ptr< Collector > Ptr
Holds transactions which were deferred to the next pass of consensus.
std::optional< LedgerIndex > minSqlSeq()
Returns the minimum ledger sequence in SQL database, if any.
LedgerIndex const maxLedgerDifference_
Try to keep a validator from switching from test to live network without first wiping the database.
std::atomic_flag gotFetchPackThread_
Set while a GotFetchPack job is outstanding, so only one ever is.
std::pair< UInt256, LedgerIndex > lastValidLedger_
Fully validated ledger, whether or not we have the ledger resident.
std::size_t getNeededValidations()
Determines how many validations are needed to fully validate a ledger.
bool isCompatible(ReadView const &, beast::Journal::Stream, char const *reason)
Tests whether a view can belong to the same chain as what we validated.
std::shared_ptr< STTx const > popAcctTransaction(std::shared_ptr< STTx const > const &tx)
Get the next transaction held for a particular account if any.
void setValidLedger(std::shared_ptr< Ledger const > const &l)
Adopts a ledger as the last validated one and tells the rest of the server, including the amendment-s...
void switchLCL(std::shared_ptr< Ledger const > const &lastClosed)
Adopts a ledger as the last closed ledger, then either accepts it directly (standalone) or tests it f...
std::recursive_mutex & peekMutex()
Exposes mutex_.
std::chrono::seconds getValidatedLedgerAge()
Stats stats_
The gauges and the collector hook that samples them.
TimeKeeper::time_point upgradeWarningPrevTime_
Time that the previous upgrade warning was issued.
bool pathFindNewRequest_
A pathfinding request arrived and has not been picked up yet.
std::uint32_t const ledgerFetchSize_
Cap on ledgers acquired in one publication or prefetch pass.
std::atomic< std::uint32_t > pubLedgerClose_
Close time of pubLedger_, in seconds since the network epoch; 0 if none.
LedgerIndex getCurrentLedgerIndex()
bool fixIndex(LedgerIndex ledgerIndex, LedgerHash const &ledgerHash)
Corrects the cached sequence-to-hash mapping for one ledger.
bool getValidatedRange(std::uint32_t &minVal, std::uint32_t &maxVal)
Returns Ledgers we have all the nodes for and are indexed: a contiguous part of getFullValidatedRange...
void applyHeldTransactions()
Apply held transactions to the open ledger This is normally called as we close the ledger.
bool storeLedger(std::shared_ptr< Ledger const > ledger)
Adds a ledger to the history cache.
void gotFetchPack(bool progress, std::uint32_t seq)
Signals that fetch-pack data arrived, so waiting acquires can use it.
beast::Journal journal_
Log sink for this component.
void tryFill(std::shared_ptr< Ledger const > ledger)
Walks back from a ledger through the SQL index, marking each ancestor resident until the chain breaks...
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
Finds a ledger by sequence, preferring the validated chain.
void setPubLedger(std::shared_ptr< Ledger const > const &l)
Records how far publication has reached.
bool newPFWork(char const *name, std::unique_lock< std::recursive_mutex > &)
A thread needs to be dispatched to handle pathfinding work of some kind.
void setFullLedger(std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
A new ledger has been accepted as part of the trusted chain: mark it validated and full,...
std::atomic< LedgerIndex > pubLedgerSeq_
Sequence of pubLedger_; 0 if nothing has been published.
void clearPriorLedgers(LedgerIndex seq)
Forgets that we hold any ledger below a sequence, without touching the cached ledgers themselves.
void setBuildingLedger(LedgerIndex index)
Records which ledger consensus is currently building, so validations for it are not chased separately...
std::uint32_t fetchSeq_
Sequence of the last fetch-pack attempt, so the same one is not tried twice in a row.
void consensusBuilt(std::shared_ptr< Ledger const > const &ledger, UInt256 const &consensusHash, json::Value consensus)
Report that the consensus process built a particular ledger.
UInt256 getHashBySeq(std::uint32_t index)
Get a ledger's hash by sequence number using the cache.
bool isCaughtUp(std::string &reason)
Decides whether the node is close enough to the network to serve clients.
std::size_t getFetchPackCacheSize() const
std::vector< std::shared_ptr< Ledger const > > findNewLedgersToPublish(std::unique_lock< std::recursive_mutex > &)
Collects the next run of validated ledgers to publish, acquiring or replaying the ones that are missi...
std::atomic< LedgerIndex > buildingLedgerSeq_
Sequence consensus is building; 0 once it is built.
std::optional< NetClock::time_point > getCloseTimeByHash(LedgerHash const &ledgerHash, LedgerIndex ledgerIndex)
Reads a close time straight out of the serialized header in the node store.
void clearLedger(std::uint32_t seq)
Marks a ledger no longer resident.
void clearLedgerCachePrior(LedgerIndex seq)
Drops cached ledgers below a sequence.
TaggedCache< UInt256, Blob > fetchPacks_
Fetch-pack nodes keyed by node hash.
void sweep()
Expires stale entries from the ledger history and fetch-pack caches.
bool newPathRequest()
Notes a new pathfinding request and dispatches a worker if one is due.
std::unique_ptr< LedgerReplay > replayData_
A set of transactions to replay during the next close.
LedgerMaster(Application &app, Stopwatch &stopwatch, beast::insight::Collector::Ptr const &collector, beast::Journal journal)
Constructs the tracker; reads history and fetch limits from the config.
std::optional< UInt256 > txnIdFromIndex(uint32_t ledgerSeq, uint32_t txnIndex)
Iff a txn exists at the specified ledger and offset then return its txnid.
std::atomic< LedgerIndex > validLedgerSeq_
Sequence of validLedger_; 0 if nothing is validated.
std::shared_ptr< Ledger const > getClosedLedger()
The finalized ledger is the last closed/accepted ledger.
std::shared_ptr< Ledger const > getLedgerByHash(UInt256 const &hash)
void setLedgerRangePresent(std::uint32_t minV, std::uint32_t maxV)
Records a closed range of sequences as resident.
std::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
std::shared_ptr< Ledger const > getValidatedLedger()
The validated ledger is the last fully validated ledger.
void fetchForHistory(std::uint32_t missing, bool &progress, InboundLedger::Reason reason, std::unique_lock< std::recursive_mutex > &)
Starts acquiring one missing historical ledger.
bool isValidated(ReadView const &ledger)
Tests whether a ledger is on the validated chain, using the skip list when the ledger does not alread...
void fixMismatch(ReadView const &ledger)
Walks back from a ledger, dropping every resident ledger it cannot confirm against that ledger's skip...
LedgerIndex getValidLedgerIndex()
LedgerHolder validLedger_
The highest-sequence ledger we have fully accepted.
CanonicalTXSet heldTransactions_
Transactions deferred to the next open ledger, in canonical order.
bool const standalone_
The server is in standalone mode.
std::shared_ptr< Ledger const > pathLedger_
The last ledger we did pathfinding against.
std::shared_ptr< Ledger const > pubLedger_
The last ledger we have published.
std::shared_ptr< ReadView const > getPublishedLedger()
This is the last ledger we published to clients and can lag the validated ledger.
bool newOrderBookDB()
If the order book is radically updated, we need to reprocess all pathfinding requests.
std::uint32_t const fetchDepth_
How many ledgers before the closed ledger do we allow peers to request?
std::recursive_mutex mutex_
Guards pubLedger_, pathLedger_, lastValidLedger_, the held transactions and the job flags other than ...
void collectMetrics()
Samples both ledger ages into the gauges.
Rules getValidatedRules()
The Rules are in the last fully validated ledger if there is one.
bool advanceWork_
Publish thread has work to do.
LedgerHistory ledgerHistory_
Cache of ledgers by hash and of validated sequence-to-hash mappings.
std::optional< LedgerHash > walkHashBySeq(std::uint32_t index, InboundLedger::Reason reason)
Walk to a ledger's hash using the skip list.
std::chrono::seconds getPublishedLedgerAge()
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...
LedgerHolder closedLedger_
The ledger that most recently closed.
bool getFullValidatedRange(std::uint32_t &minVal, std::uint32_t &maxVal)
Returns Ledgers we have all the nodes for: the contiguous resident range ending at the published ledg...
std::optional< LedgerHash > getLedgerHashForHistory(LedgerIndex index, InboundLedger::Reason reason)
Finds the hash of a ledger the history back-fill wants, preferring the last back-filled ledger as the...
void tryAdvance()
Signals that the ledger stream may be able to make progress.
int fillInProgress_
Sequence a tryFill() job is currently walking back from, or 0 when no fill is running.
int pathFindThread_
Pathfinding jobs queued or running.
RangeSet< std::uint32_t > completeLedgers_
Sequences of the ledgers this node believes it holds in full.
void checkAccept(std::shared_ptr< Ledger const > const &ledger)
If the ledger passes canBeCurrent(), is newer than the validated ledger and has a quorum,...
std::optional< Blob > getFetchPack(UInt256 const &hash) override
Consumes one cached fetch-pack node.
std::uint32_t const ledgerHistorySize_
How much history do we want to keep.
std::atomic< std::uint32_t > validLedgerSign_
Sign time of validLedger_, in seconds since the network epoch: the median of its trusted validations,...
void doAdvance(std::unique_lock< std::recursive_mutex > &)
Try to publish ledgers, acquire missing ledgers.
void addHeldTransaction(std::shared_ptr< Transaction > const &trans)
Defers a transaction to the next open ledger.
std::shared_ptr< ReadView const > getCurrentLedger()
The current ledger is the ledger we believe new transactions should go in.
std::recursive_mutex completeLock_
Guards completeLedgers_ only.
std::string getCompleteLedgers() const
void takeReplay(std::unique_ptr< LedgerReplay > replay)
Stores a transaction set to replay when the next ledger closes.
void updatePaths()
Runs one pathfinding pass per new validated ledger or new request, and exits when neither is new,...
std::unique_ptr< LedgerReplay > releaseReplay()
std::size_t missingFromCompleteLedgerRange(LedgerIndex first, LedgerIndex last) const
Counts gaps in a closed sequence interval.
bool advanceThread_
An AdvanceLedger job is queued or running.
bool haveLedger(std::uint32_t seq) const
std::uint32_t getEarliestFetch()
Get the earliest ledger we will let peers fetch.
void makeFetchPack(std::weak_ptr< Peer > const &wPeer, std::shared_ptr< protocol::TMGetObjectByHash > const &request, UInt256 haveLedgerHash, UptimeClock::time_point uptime)
Builds a fetch pack of the ledgers preceding the one a peer says it has, and sends it.
std::shared_ptr< Ledger const > histLedger_
The last ledger we handled fetching history.
void addFetchPack(UInt256 const &hash, std::shared_ptr< Blob > data)
Caches one fetch-pack node received from a peer.
Application & app_
Owning application, the route to every other subsystem.
void failedSave(std::uint32_t seq, UInt256 const &hash)
Marks a ledger no longer resident after its save failed, and starts fetching it again.
std::chrono::time_point< NetClock > time_point
std::chrono::duration< rep, period > duration
virtual LedgerHeader const & header() const =0
Returns information about the ledger.
virtual bool open() const =0
Returns true if this reflects an open ledger.
Rules controlling protocol behavior.
UInt256 const & asUInt256() const
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.
virtual bool isLeaf() const =0
Determines if this is a leaf node.
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.
Automatically unlocks and re-locks a unique_lock object.
void const * getDataPtr() const
std::chrono::time_point< UptimeClock > time_point
Persistency layer for NodeObject.
std::shared_ptr< NodeObject > fetchNodeObject(UInt256 const &hash, std::uint32_t ledgerSeq=0, FetchType fetchType=FetchType::Synchronous, bool duplicate=false)
Fetch a node object.
T duration_cast(T... args)
bool isXrpldVersion(std::uint64_t version)
Check if the encoded software version is an xrpld software version.
bool isNewerVersion(std::uint64_t version)
Check if the version is newer than the local node's xrpld software version.
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Charge const kFeeRequestNoReply
Charge const kFeeMalformedRequest
Schedule of fees charged for imposing load on the server.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static constexpr int kMaxLedgerGap
Don't catch up more than 100 ledgers (cannot exceed 256).
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
std::optional< UInt256 > hashOfSeq(ReadView const &ledger, LedgerIndex seq, beast::Journal journal)
Return the hash of a ledger by sequence.
beast::AbstractClock< std::chrono::steady_clock > Stopwatch
A clock for measuring elapsed time.
bool isCurrent(ValidationParms const &p, NetClock::time_point now, NetClock::time_point signTime, NetClock::time_point seenTime)
Whether a validation is still current.
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.
bool pendSaveValidated(ServiceRegistry ®istry, std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
Save, or arrange to save, a fully-validated ledger.
std::uint32_t LedgerIndex
A ledger index.
Stopwatch & stopwatch()
Returns an instance of a wall clock.
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
constexpr std::size_t calculatePercent(std::size_t count, std::size_t total)
Calculate one number divided by another number in percentage.
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.
constexpr Dest safeCast(Src s) noexcept
std::string to_string(BaseUInt< Bits, Tag > const &a)
void logicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
bool areCompatible(ReadView const &validLedger, ReadView const &testLedger, beast::Journal::Stream &s, char const *reason)
Return false if the test ledger is provably incompatible with the valid ledger, that is,...
LedgerIndex getCandidateLedger(LedgerIndex requested)
Find a ledger index from which we could easily get the requested ledger.
Slice makeSlice(std::array< T, N > const &a)
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
boost::icl::interval_set< T, std::less, ClosedInterval< T > > RangeSet
A set of closed intervals over the domain T.
@ LedgerMaster
ledger master data for signing
std::unordered_map< Key, Value, Hash, Pred, Allocator > HashMap
std::chrono::duration< int, std::ratio_multiply< Days::period, std::ratio< 7 > > > Weeks
std::vector< unsigned char > Blob
Storage for linear binary data.
static constexpr int kMaxWriteLoadAcquire
Don't acquire history if write load is too high.
static constexpr std::chrono::minutes kMaxLedgerAgeAcquire
Don't acquire history if ledger is too old.
Sha512HalfHasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
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)
Helper function for LedgerMaster::doAdvance() Return true if candidateLedger should be fetched from t...
T time_point_cast(T... args)
T time_since_epoch(T... args)