From c3c37ff70fcf30fd6354331e4adf0786a273abfe Mon Sep 17 00:00:00 2001 From: Mark Travis Date: Mon, 18 Sep 2023 15:15:46 -0700 Subject: [PATCH] Optimize when to acquire ledgers from the network. Particulary avoid acquiring ledgers likely to be produced locally very soon. --- src/ripple/app/ledger/impl/InboundLedgers.cpp | 44 +++++++++++++++++-- src/ripple/app/misc/NetworkOPs.cpp | 21 +++++++++ src/ripple/app/misc/NetworkOPs.h | 2 + 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/ripple/app/ledger/impl/InboundLedgers.cpp b/src/ripple/app/ledger/impl/InboundLedgers.cpp index 7ee49b4547a..ec422af131c 100644 --- a/src/ripple/app/ledger/impl/InboundLedgers.cpp +++ b/src/ripple/app/ledger/impl/InboundLedgers.cpp @@ -74,10 +74,46 @@ class InboundLedgersImp : public InboundLedgers reason != InboundLedger::Reason::SHARD || (seq != 0 && app_.getShardStore())); - // probably not the right rule - if (app_.getOPs().isNeedNetworkLedger() && - (reason != InboundLedger::Reason::GENERIC) && - (reason != InboundLedger::Reason::CONSENSUS)) + /* Acquiring ledgers is somewhat expensive. It requires lots of + * computation and network communication. Avoid it when it's not + * appropriate. Every validation from a peer for a ledger that + * we do not have locally results in a call to this function: even + * if we are moments away from validating the same ledger. + * + * When the following are all true, it is very likely that we will + * soon validate the ledger ourselves. Therefore, avoid acquiring + * ledgers from the network if: + * + Our mode is "full". It is very likely that we will build + * the ledger through the normal consensus process, and + * + Our latest ledger is close to the most recently validated ledger. + * Otherwise, we are likely falling behind the network because + * we have been closing ledgers that have not been validated, and + * + The requested ledger sequence is greater than our validated + * ledger, but not far into the future. Otherwise, it is either a + * request for an historical ledger or, if far into the future, + * likely we're quite behind and will benefit from acquiring it + * from the network. + */ + bool const isFull = app_.getOPs().isFull(); + bool const fallingBehind = app_.getOPs().isFallingBehind(); + LedgerIndex const validSeq = + app_.getLedgerMaster().getValidLedgerIndex(); + constexpr std::size_t lagLeeway = 20; + bool const nearFuture = + (seq > validSeq) && (seq < validSeq + lagLeeway); + bool const shouldAcquire = !(isFull && !fallingBehind && nearFuture); + JLOG(j_.trace()) << "Evaluating whether to acquire ledger " << hash + << ". full: " << (isFull ? "true" : "false") + << ". falling behind: " + << (fallingBehind ? "true" : "false") + << ". ledger sequence " << seq + << ". Valid sequence: " << validSeq + << ". Lag leeway: " << lagLeeway + << ". request for near future ledger: " + << (nearFuture ? "true" : "false") + << ". Acquiring ledger? " + << (shouldAcquire ? "true" : "false"); + if (!shouldAcquire) return {}; bool isNew = true; diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp index abb4acf029e..7d53384c755 100644 --- a/src/ripple/app/misc/NetworkOPs.cpp +++ b/src/ripple/app/misc/NetworkOPs.cpp @@ -402,6 +402,8 @@ class NetworkOPsImp final : public NetworkOPs clearLedgerFetch() override; Json::Value getLedgerFetchInfo() override; + bool + isFallingBehind() const override; std::uint32_t acceptLedger( std::optional consensusDelay) override; @@ -713,6 +715,7 @@ class NetworkOPsImp final : public NetworkOPs std::atomic amendmentBlocked_{false}; std::atomic amendmentWarned_{false}; std::atomic unlBlocked_{false}; + std::atomic fallingBehind_{false}; ClosureCounter waitHandlerCounter_; boost::asio::steady_timer heartbeatTimer_; @@ -1826,6 +1829,18 @@ NetworkOPsImp::beginConsensus(uint256 const& networkClosed) JLOG(m_journal.info()) << "Consensus time for #" << closingInfo.seq << " with LCL " << closingInfo.parentHash; + if (closingInfo.seq > m_ledgerMaster.getValidLedgerIndex() + 1) + { + fallingBehind_ = true; + JLOG(m_journal.warn()) << "Current ledger " << closingInfo.seq + << "has advanced at least 2 past validated " + << m_ledgerMaster.getValidLedgerIndex(); + } + else + { + fallingBehind_ = false; + } + auto prevLedger = m_ledgerMaster.getLedgerByHash(closingInfo.parentHash); if (!prevLedger) @@ -2743,6 +2758,12 @@ NetworkOPsImp::getLedgerFetchInfo() return app_.getInboundLedgers().getInfo(); } +bool +NetworkOPsImp::isFallingBehind() const +{ + return fallingBehind_; +} + void NetworkOPsImp::pubProposedTransaction( std::shared_ptr const& ledger, diff --git a/src/ripple/app/misc/NetworkOPs.h b/src/ripple/app/misc/NetworkOPs.h index 59285311172..d388ab310a0 100644 --- a/src/ripple/app/misc/NetworkOPs.h +++ b/src/ripple/app/misc/NetworkOPs.h @@ -258,6 +258,8 @@ class NetworkOPs : public InfoSub::Source clearLedgerFetch() = 0; virtual Json::Value getLedgerFetchInfo() = 0; + virtual bool + isFallingBehind() const = 0; /** Accepts the current transaction tree, return the new ledger's sequence