From d4650441fbcab65f01cd90eb145f2f0cf6011618 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Tue, 30 Jun 2026 16:10:50 +0700 Subject: [PATCH] feat(consensus): default sidecar reconciliation off Compile out sidecar acquisition and merge plumbing unless xahaud_sidecar_reconciliation is enabled, and move fetch-positive .testnet scenarios into an opt-in suite. When reconciliation is enabled, gate eager fetches on current trusted root support so first-seen transient roots do not trigger network acquisition. This keeps the recovery path available for measurement without making it the default path. Verified default OFF with x-format-changed, git diff --check, x-quick-check, cmake configure/build, and ./build/rippled --unittest=ConsensusExtensions. ON path syntax-checked; Claude is assigned the parallel ON build/test review in a separate worktree. --- .testnet/scenarios/export-suite.yml | 10 - .../sidecar-reconciliation-suite.yml | 48 +++++ .testnet/scenarios/suite.yml | 7 - cmake/RippledCore.cmake | 3 + cmake/RippledSettings.cmake | 2 +- src/test/app/Export_test.cpp | 12 +- .../consensus/ConsensusExtensions_test.cpp | 38 ++-- .../app/consensus/ConsensusExtensions.cpp | 188 ++++++++++++++---- src/xrpld/app/consensus/ConsensusExtensions.h | 27 ++- src/xrpld/app/consensus/RCLConsensus.cpp | 25 +-- .../app/ledger/detail/TransactionAcquire.cpp | 56 +++++- src/xrpld/app/misc/NetworkOPs.cpp | 5 + 12 files changed, 328 insertions(+), 93 deletions(-) create mode 100644 .testnet/scenarios/sidecar-reconciliation-suite.yml diff --git a/.testnet/scenarios/export-suite.yml b/.testnet/scenarios/export-suite.yml index 25e695f80..87ffc0803 100644 --- a/.testnet/scenarios/export-suite.yml +++ b/.testnet/scenarios/export-suite.yml @@ -39,16 +39,6 @@ tests: - n3:no_export_sig=true - n4:no_export_sig=true - # Resilience counterpart to export_degradation: all nodes DO sign, but the - # scenario drops one validator's proposals to n0 after setup. n0 remains above - # quorum from direct proposals, but must reconstruct the missing sidecar leaf - # through the fetch/acquisition path. - - name: export_sidecar_fetch_under_proposal_drop_ce - script: .testnet/scenarios/export/export_fetch_under_proposal_drop.py - network: - rc: - - rng_poll_ms=333 - - name: export_without_unl_report script: .testnet/scenarios/export/export_without_unl_report.py network: diff --git a/.testnet/scenarios/sidecar-reconciliation-suite.yml b/.testnet/scenarios/sidecar-reconciliation-suite.yml new file mode 100644 index 000000000..f63b44e19 --- /dev/null +++ b/.testnet/scenarios/sidecar-reconciliation-suite.yml @@ -0,0 +1,48 @@ +# Opt-in suite for the sidecar SHAMap reconciliation path. +# +# These scenarios assert fetch/acquire/merge behavior and require a binary built +# with: +# +# -Dxahaud_sidecar_reconciliation=ON +# +# The normal feature suites default to proposal-carried CE/export material and +# do not run these tests while reconciliation is disabled by default. + +defaults: + network: + node_count: 5 + launcher: tmux + find_ports: true + slave_delay: 0.2 + features: + - ConsensusEntropy + - Export + track_features: + - ConsensusEntropy + - Export + unl_report: true + log_levels: + TxQ: info + Protocol: debug + Peer: debug + LedgerConsensus: debug + ConsensusExtensions: debug + NetworkOPs: info + env: + XAHAU_RESOURCE_PER_PORT: "1" + rc: + - rng_poll_ms=333 + +tests: + - name: entropy_fetch_recovers_dropped_claims + script: .testnet/scenarios/entropy/fetch_recovers_dropped_claims.py + network: + rc: + - rng_poll_ms=333 + - n0:rngrevealdrop=100 + + - name: export_sidecar_fetch_under_proposal_drop_ce + script: .testnet/scenarios/export/export_fetch_under_proposal_drop.py + network: + rc: + - rng_poll_ms=333 diff --git a/.testnet/scenarios/suite.yml b/.testnet/scenarios/suite.yml index a49802723..8094c4b41 100644 --- a/.testnet/scenarios/suite.yml +++ b/.testnet/scenarios/suite.yml @@ -25,13 +25,6 @@ tests: - name: steady_state_entropy script: .testnet/scenarios/entropy/steady_state_entropy.py - - name: entropy_fetch_recovers_dropped_claims - script: .testnet/scenarios/entropy/fetch_recovers_dropped_claims.py - network: - rc: - - rng_poll_ms=333 - - n0:rngrevealdrop=100 - - name: fallback_without_unl_report script: .testnet/scenarios/entropy/fallback_without_unl_report.py network: diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake index eafdb7b27..4bee93018 100644 --- a/cmake/RippledCore.cmake +++ b/cmake/RippledCore.cmake @@ -181,6 +181,9 @@ if(xrpld) file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp" ) + if(NOT xahaud_sidecar_reconciliation) + list(FILTER sources EXCLUDE REGEX "/src/xrpld/app/ledger/SidecarSetSF\\.cpp$") + endif() target_sources(rippled PRIVATE ${sources}) if(tests) diff --git a/cmake/RippledSettings.cmake b/cmake/RippledSettings.cmake index a5de50924..cc55f1a5c 100644 --- a/cmake/RippledSettings.cmake +++ b/cmake/RippledSettings.cmake @@ -21,7 +21,7 @@ option(xahaud_runtime_test_config option(xahaud_sidecar_reconciliation "Enable consensus-extension sidecar SHAMap fetch/acquire/reconcile path" - ON) + OFF) option(unity "Creates a build using UNITY support in cmake. This is the default" ON) if(unity) diff --git a/src/test/app/Export_test.cpp b/src/test/app/Export_test.cpp index 19d6248c1..60239a083 100644 --- a/src/test/app/Export_test.cpp +++ b/src/test/app/Export_test.cpp @@ -1143,7 +1143,9 @@ struct Export_test : public beast::unit_test::suite ce.exportSigCollector().addVerifiedSignature( txHash, valPK, originalSig, applySeq); auto const agreedHash = ce.buildExportSigSet(applySeq); - BEAST_EXPECT(ce.isSidecarSet(agreedHash)); + BEAST_EXPECT( + ce.isSidecarSet(agreedHash) == + ConsensusExtensions::sidecarReconciliationEnabled()); ce.acceptExportSigSet(agreedHash); ce.setExportSigConvergenceFailed(); @@ -1541,7 +1543,9 @@ struct Export_test : public beast::unit_test::suite ce.exportSigCollector().addVerifiedSignature( txHash, valPK, sig, applySeq); auto const agreedHash = ce.buildExportSigSet(applySeq); - BEAST_EXPECT(ce.isSidecarSet(agreedHash)); + BEAST_EXPECT( + ce.isSidecarSet(agreedHash) == + ConsensusExtensions::sidecarReconciliationEnabled()); ce.acceptExportSigSet(agreedHash); auto const parent = env.app().getLedgerMaster().getClosedLedger(); @@ -1613,7 +1617,9 @@ struct Export_test : public beast::unit_test::suite ce.exportSigCollector().addVerifiedSignature( txHash, valPK, sig, applySeq); auto const agreedHash = ce.buildExportSigSet(applySeq); - BEAST_EXPECT(ce.isSidecarSet(agreedHash)); + BEAST_EXPECT( + ce.isSidecarSet(agreedHash) == + ConsensusExtensions::sidecarReconciliationEnabled()); ce.acceptExportSigSet(agreedHash); ExportResultBuilder::SignatureSnapshot signatures; diff --git a/src/test/consensus/ConsensusExtensions_test.cpp b/src/test/consensus/ConsensusExtensions_test.cpp index 847663725..8185e1160 100644 --- a/src/test/consensus/ConsensusExtensions_test.cpp +++ b/src/test/consensus/ConsensusExtensions_test.cpp @@ -1471,7 +1471,9 @@ class ConsensusExtensions_test : public beast::unit_test::suite auto const entropySetHash = ce.buildEntropySet(seq); ce.acceptEntropySet(entropySetHash); - BEAST_EXPECT(ce.isSidecarSet(entropySetHash)); + BEAST_EXPECT( + ce.isSidecarSet(entropySetHash) == + ConsensusExtensions::sidecarReconciliationEnabled()); // Once the sidecar gate has accepted a hash, injection is derived from // that sidecar snapshot. A local failure flag is diagnostic state, not // an additional selector input. @@ -2362,7 +2364,9 @@ class ConsensusExtensions_test : public beast::unit_test::suite ce.exportSigCollector().addVerifiedSignature( txHash, valPK, originalSig, seq); auto const exportSigSetHash = ce.buildExportSigSet(seq); - BEAST_EXPECT(ce.isSidecarSet(exportSigSetHash)); + BEAST_EXPECT( + ce.isSidecarSet(exportSigSetHash) == + ConsensusExtensions::sidecarReconciliationEnabled()); auto const view = ce.activeValidatorView(); // A locally-built export signature map is not closed-ledger material @@ -4154,7 +4158,9 @@ class ConsensusExtensions_test : public beast::unit_test::suite auto const seq = ledger->info().seq + 1; auto const commitHash = ce.buildCommitSet(seq); - BEAST_EXPECT(ce.isSidecarSet(commitHash)); + BEAST_EXPECT( + ce.isSidecarSet(commitHash) == + ConsensusExtensions::sidecarReconciliationEnabled()); ExtendedPosition revealPos{commitPos.txSetHash}; revealPos.myReveal = ce.getEntropySecret(); @@ -4178,7 +4184,9 @@ class ConsensusExtensions_test : public beast::unit_test::suite BEAST_EXPECT(ce.pendingRevealCount() == 1); BEAST_EXPECT(ce.hasMinimumReveals()); auto const entropyHash = ce.buildEntropySet(seq); - BEAST_EXPECT(ce.isSidecarSet(entropyHash)); + BEAST_EXPECT( + ce.isSidecarSet(entropyHash) == + ConsensusExtensions::sidecarReconciliationEnabled()); } public: @@ -4203,16 +4211,22 @@ public: testOnPreBuildTier2WithNegativeUNL(); testProposalProofRoundTrip(); testHarvestRngDataReplacementAndRejection(); - testExportSidecarBuildFetchAndMerge(); - testExportSidecarIgnoresCancelOnlyExports(); - testExportSidecarBuildCapsConsensusCandidates(); - testExportSidecarRejectsInvalidFetchedEntries(); - testExportSidecarRejectsOversizedFetchedSet(); + if constexpr (ConsensusExtensions::sidecarReconciliationEnabled()) + { + testExportSidecarBuildFetchAndMerge(); + testExportSidecarIgnoresCancelOnlyExports(); + testExportSidecarBuildCapsConsensusCandidates(); + testExportSidecarRejectsInvalidFetchedEntries(); + testExportSidecarRejectsOversizedFetchedSet(); + } testExportAgreedSignaturesIgnoreLiveCollectorMutation(); testOnPreBuildPreservesExportDecision(); - testRngSidecarBuildFetchAndMerge(); - testRngSidecarRejectsOversizedFetchedSet(); - testRngSidecarRejectsInvalidFetchedEntries(); + if constexpr (ConsensusExtensions::sidecarReconciliationEnabled()) + { + testRngSidecarBuildFetchAndMerge(); + testRngSidecarRejectsOversizedFetchedSet(); + testRngSidecarRejectsInvalidFetchedEntries(); + } testOnPreBuildInjectsStandaloneEntropy(); testOnPreBuildEntropyMismatchKeepsAgreed(); testDiagnosticsJsonAndPositionLogging(); diff --git a/src/xrpld/app/consensus/ConsensusExtensions.cpp b/src/xrpld/app/consensus/ConsensusExtensions.cpp index 8abe6a982..e3ed0d6ea 100644 --- a/src/xrpld/app/consensus/ConsensusExtensions.cpp +++ b/src/xrpld/app/consensus/ConsensusExtensions.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include namespace ripple { @@ -181,6 +182,7 @@ makeSidecarItem(STObject const& sidecar) return make_shamapitem(itemKey, s.slice()); } +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION bool sidecarLeafCountWithin(SHAMap const& map, std::size_t maxLeaves) { @@ -196,6 +198,7 @@ sidecarLeafCountWithin(SHAMap const& map, std::size_t maxLeaves) }); return within; } +#endif //@@start active-validator-view-build ActiveValidatorViewSource @@ -406,6 +409,117 @@ ConsensusExtensions::entropyGateThreshold() const return entropyGateThresholdForView(view->size(), view->originalViewSize); } +void +ConsensusExtensions::recordSidecarRootSupport( + NodeID const& nodeId, + ExtendedPosition const& position) +{ +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION + if (!isUNLReportMember(nodeId)) + return; + + auto record = [&](auto& roots, std::optional const& hash) { + for (auto it = roots.begin(); it != roots.end();) + { + auto current = it++; + current->second.erase(nodeId); + if (current->second.empty()) + roots.erase(current); + } + + if (hash && *hash != uint256{}) + roots[*hash].insert(nodeId); + }; + + record(sidecarRootSupport_.commitSet, position.commitSetHash); + record(sidecarRootSupport_.entropySet, position.entropySetHash); + record(sidecarRootSupport_.exportSigSet, position.exportSigSetHash); +#else + (void)nodeId; + (void)position; +#endif +} + +std::size_t +ConsensusExtensions::sidecarRootSupport(SidecarKind kind, uint256 const& hash) + const +{ +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION + auto observedSupport = [&](auto const& roots) -> std::size_t { + auto const it = roots.find(hash); + return it == roots.end() ? 0 : it->second.size(); + }; + + std::size_t support = 0; + auto const localContribution = + localIsActiveValidator() ? std::size_t{1} : std::size_t{0}; + switch (kind) + { + case SidecarKind::commitSet: + support = observedSupport(sidecarRootSupport_.commitSet); + if (commitSetMap_ && commitSetMap_->getHash().as_uint256() == hash) + support += localContribution; + break; + case SidecarKind::entropySet: + support = observedSupport(sidecarRootSupport_.entropySet); + if (entropySetMap_ && + entropySetMap_->getHash().as_uint256() == hash) + support += localContribution; + break; + case SidecarKind::exportSigSet: + support = observedSupport(sidecarRootSupport_.exportSigSet); + if (exportSigSetMap_ && + exportSigSetMap_->getHash().as_uint256() == hash) + support += localContribution; + break; + } + return support; +#else + (void)kind; + (void)hash; + return 0; +#endif +} + +std::size_t +ConsensusExtensions::sidecarFetchSupportThreshold(SidecarKind kind) const +{ +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION + auto const threshold = kind == SidecarKind::exportSigSet + ? exportSigQuorumThreshold() + : entropyGateThreshold(); + return threshold == 0 ? std::numeric_limits::max() : threshold; +#else + (void)kind; + return std::numeric_limits::max(); +#endif +} + +bool +ConsensusExtensions::shouldEagerFetchSidecarSet( + SidecarKind kind, + uint256 const& hash) const +{ +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION + auto const support = sidecarRootSupport(kind, hash); + auto const threshold = sidecarFetchSupportThreshold(kind); + if (support >= threshold) + return true; + + JLOG(j_.trace()) << "SIDECARFETCH: skip" + << " kind=" << sidecarKindName(kind) + << " origin=eagerProposal" + << " hash=" << hash + << " reason=root-support-below-threshold" + << " support=" << support << " threshold=" << threshold; + return false; +#else + (void)kind; + (void)hash; + return false; +#endif +} + std::size_t ConsensusExtensions::entropyGateThresholdForView( std::size_t effectiveViewSize, @@ -1425,6 +1539,7 @@ ConsensusExtensions::clearRngStatePreservingExport() consensusExportTxns_.clear(); consensusTxSetHash_.reset(); pendingSidecarFetches_.clear(); + sidecarRootSupport_ = {}; observedParticipantsHash_.reset(); observedParticipantsCount_ = 0; observedParticipantsBitmapBin_.clear(); @@ -1555,9 +1670,7 @@ ConsensusExtensions::isActiveValidator( bool ConsensusExtensions::isSidecarSet(uint256 const& hash) const { - if constexpr (!sidecarReconciliationEnabled()) - return false; - +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION if (commitSetMap_ && commitSetMap_->getHash().as_uint256() == hash) return true; if (entropySetMap_ && entropySetMap_->getHash().as_uint256() == hash) @@ -1565,6 +1678,10 @@ ConsensusExtensions::isSidecarSet(uint256 const& hash) const if (exportSigSetMap_ && exportSigSetMap_->getHash().as_uint256() == hash) return true; return pendingSidecarFetches_.find(hash) != pendingSidecarFetches_.end(); +#else + (void)hash; + return false; +#endif } //@@end is-sidecar-set @@ -1573,14 +1690,7 @@ ConsensusExtensions::isSidecarSet(uint256 const& hash) const void ConsensusExtensions::onAcquiredSidecarSet(std::shared_ptr const& map) { - if constexpr (!sidecarReconciliationEnabled()) - { - JLOG(j_.debug()) << "SIDECARFETCH: acquired set ignored" - << " reason=reconciliation-disabled" - << " hash=" << map->getHash().as_uint256(); - return; - } - +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION auto const hash = map->getHash().as_uint256(); // Look up the expected kind before erasing. @@ -1974,6 +2084,11 @@ ConsensusExtensions::onAcquiredSidecarSet(std::shared_ptr const& map) << " pendingBefore=" << pendingBefore << " pendingAfter=" << pendingAfter << " pendingDelta=" << pendingDelta; +#else + JLOG(j_.debug()) << "SIDECARFETCH: acquired set ignored" + << " reason=reconciliation-disabled" + << " hash=" << map->getHash().as_uint256(); +#endif } //@@end handle-acquired-sidecar @@ -1983,18 +2098,7 @@ ConsensusExtensions::fetchSidecarSetIfNeeded( SidecarKind kind, char const* origin) { - if constexpr (!sidecarReconciliationEnabled()) - { - if (hash && *hash != uint256{}) - { - JLOG(j_.trace()) - << "SIDECARFETCH: skip" - << " kind=" << sidecarKindName(kind) << " origin=" << origin - << " hash=" << *hash << " reason=reconciliation-disabled"; - } - return; - } - +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION if (!hash) { JLOG(j_.trace()) << "SIDECARFETCH: skip" @@ -2090,6 +2194,15 @@ ConsensusExtensions::fetchSidecarSetIfNeeded( << " origin=" << origin << " hash=" << *hash; onAcquiredSidecarSet(immediate); } +#else + if (hash && *hash != uint256{}) + { + JLOG(j_.trace()) << "SIDECARFETCH: skip" + << " kind=" << sidecarKindName(kind) + << " origin=" << origin << " hash=" << *hash + << " reason=reconciliation-disabled"; + } +#endif } void @@ -2097,19 +2210,22 @@ ConsensusExtensions::fetchSidecarsIfNeeded( ExtendedPosition const& peerPos, char const* origin) { - if constexpr (!sidecarReconciliationEnabled()) - { - (void)peerPos; - (void)origin; - return; - } +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION + auto const isEager = std::strcmp(origin, "eagerProposal") == 0; + auto fetch = [&](std::optional const& hash, SidecarKind kind) { + if (isEager && hash && *hash != uint256{} && + !shouldEagerFetchSidecarSet(kind, *hash)) + return; + fetchSidecarSetIfNeeded(hash, kind, origin); + }; - fetchSidecarSetIfNeeded( - peerPos.commitSetHash, SidecarKind::commitSet, origin); - fetchSidecarSetIfNeeded( - peerPos.entropySetHash, SidecarKind::entropySet, origin); - fetchSidecarSetIfNeeded( - peerPos.exportSigSetHash, SidecarKind::exportSigSet, origin); + fetch(peerPos.commitSetHash, SidecarKind::commitSet); + fetch(peerPos.entropySetHash, SidecarKind::entropySet); + fetch(peerPos.exportSigSetHash, SidecarKind::exportSigSet); +#else + (void)peerPos; + (void)origin; +#endif } void @@ -2850,6 +2966,8 @@ ConsensusExtensions::onTrustedPeerProposal( return; } + recordSidecarRootSupport(nodeId, position); + harvestRngData( nodeId, publicKey, diff --git a/src/xrpld/app/consensus/ConsensusExtensions.h b/src/xrpld/app/consensus/ConsensusExtensions.h index 0e8225f07..5033623ec 100644 --- a/src/xrpld/app/consensus/ConsensusExtensions.h +++ b/src/xrpld/app/consensus/ConsensusExtensions.h @@ -28,7 +28,7 @@ namespace ripple { #ifndef XAHAUD_ENABLE_SIDECAR_RECONCILIATION -#define XAHAUD_ENABLE_SIDECAR_RECONCILIATION 1 +#define XAHAUD_ENABLE_SIDECAR_RECONCILIATION 0 #endif class Application; @@ -127,6 +127,17 @@ private: // content-sniffing and logs can attribute eager vs gate-triggered fetches. hash_map pendingSidecarFetches_; + struct SidecarRootSupport + { + hash_map> commitSet; + hash_map> entropySet; + hash_map> exportSigSet; + }; + + // Per-round support for sidecar roots observed in trusted proposals. Eager + // acquisition uses this to avoid fetching first-seen transient roots. + SidecarRootSupport sidecarRootSupport_; + // Parent-ledger validator view used by RNG and Export quorum logic. ActiveValidatorViewPtr activeValidatorView_ = std::make_shared(); @@ -175,6 +186,20 @@ private: char const* sourceTag, RngProofCachePolicy proofCachePolicy); + void + recordSidecarRootSupport( + NodeID const& nodeId, + ExtendedPosition const& position); + + std::size_t + sidecarRootSupport(SidecarKind kind, uint256 const& hash) const; + + std::size_t + sidecarFetchSupportThreshold(SidecarKind kind) const; + + bool + shouldEagerFetchSidecarSet(SidecarKind kind, uint256 const& hash) const; + // Commit proofs keyed by NodeID. Only seq=0 proofs are cached because the // commit sidecar hash must be deterministic across all nodes. hash_map commitProofs_; diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 798c06572..ceedfd314 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -1032,29 +1032,21 @@ RCLConsensus::phase() const bool RCLConsensus::isExtensionSet(uint256 const& hash) const { - if constexpr (!ConsensusExtensions::sidecarReconciliationEnabled()) - { - (void)hash; - return false; - } - +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION std::lock_guard _{mutex_}; if (consensus_->phase() == ConsensusPhase::accepted) return false; return adaptor_.ce().isSidecarSet(hash); +#else + (void)hash; + return false; +#endif } void RCLConsensus::gotExtensionSet(std::shared_ptr const& map) { - if constexpr (!ConsensusExtensions::sidecarReconciliationEnabled()) - { - JLOG(j_.debug()) << "Ignoring acquired sidecar set " - << map->getHash().as_uint256() - << " reason=reconciliation-disabled"; - return; - } - +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION std::lock_guard _{mutex_}; // Accept builds run without the consensus mutex and clear extension // working state. Late sidecar fetches belong to the previous establish @@ -1066,6 +1058,11 @@ RCLConsensus::gotExtensionSet(std::shared_ptr const& map) return; } adaptor_.ce().onAcquiredSidecarSet(map); +#else + JLOG(j_.debug()) << "Ignoring acquired sidecar set " + << map->getHash().as_uint256() + << " reason=reconciliation-disabled"; +#endif } bool diff --git a/src/xrpld/app/ledger/detail/TransactionAcquire.cpp b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp index 022ac83bb..c8238782b 100644 --- a/src/xrpld/app/ledger/detail/TransactionAcquire.cpp +++ b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp @@ -20,16 +20,24 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include +#ifndef XAHAUD_ENABLE_SIDECAR_RECONCILIATION +#define XAHAUD_ENABLE_SIDECAR_RECONCILIATION 0 +#endif + +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION +#include +#endif + namespace ripple { using namespace std::chrono_literals; @@ -47,14 +55,47 @@ namespace { std::unique_ptr makeSyncFilter(InboundSetKind kind, Application& app) { +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION // Sidecars deliberately reuse candidate tx-set acquisition; the filter only // changes leaf handling so sidecar STObjects are cached, not submitted. if (kind == InboundSetKind::sidecar) return std::make_unique(app.getTempNodeCache()); +#else + if (kind == InboundSetKind::sidecar) + LogicError("Sidecar acquisition requested while disabled"); +#endif return std::make_unique(app, app.getTempNodeCache()); } +SHAMapType +acquireMapType(InboundSetKind kind) +{ +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION + if (kind == InboundSetKind::sidecar) + return SHAMapType::SIDECAR; +#else + if (kind == InboundSetKind::sidecar) + LogicError("Sidecar SHAMap acquisition requested while disabled"); +#endif + + return SHAMapType::TRANSACTION; +} + +char const* +acquireSetKindName(InboundSetKind kind) +{ +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION + if (kind == InboundSetKind::sidecar) + return "sidecar"; +#else + if (kind == InboundSetKind::sidecar) + return "sidecar-disabled"; +#endif + + return "TX"; +} + } // namespace TransactionAcquire::TransactionAcquire( @@ -72,13 +113,10 @@ TransactionAcquire::TransactionAcquire( , mPeerSet(std::move(peerSet)) , mSetKind(kind) { - // Keep sidecar fetch on the same content-addressed SHAMap path as tx sets: - // normal reply limits, peer scoring, charging, and timeout behavior apply. + // Candidate set acquisition is content-addressed; normal reply limits, peer + // scoring, charging, and timeout behavior apply. mMap = std::make_shared( - kind == InboundSetKind::sidecar ? SHAMapType::SIDECAR - : SHAMapType::TRANSACTION, - hash, - app_.getNodeFamily()); + acquireMapType(kind), hash, app_.getNodeFamily()); mMap->setUnbacked(); } @@ -94,9 +132,7 @@ TransactionAcquire::done() else { JLOG(journal_.debug()) - << "Acquired " - << (mSetKind == InboundSetKind::sidecar ? "sidecar" : "TX") - << " set " << hash_; + << "Acquired " << acquireSetKindName(mSetKind) << " set " << hash_; mMap->setImmutable(); uint256 const& hash(hash_); diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index 49820a7f4..8c4e96c7b 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -1990,6 +1990,7 @@ NetworkOPsImp::mapComplete(std::shared_ptr const& map, bool fromAcquire) auto const hash = map->getHash().as_uint256(); if (map->mapType() == SHAMapType::SIDECAR) { +#if XAHAUD_ENABLE_SIDECAR_RECONCILIATION if (mConsensus.isExtensionSet(hash)) { // Extension sidecar set (commitSet, entropySet, or @@ -2005,6 +2006,10 @@ NetworkOPsImp::mapComplete(std::shared_ptr const& map, bool fromAcquire) JLOG(m_journal.debug()) << "Ignoring stale acquired sidecar set " << hash; } +#else + JLOG(m_journal.debug()) << "Ignoring acquired sidecar set " << hash + << " reason=reconciliation-disabled"; +#endif return; } mConsensus.gotTxSet(app_.timeKeeper().closeTime(), RCLTxSet{map});