diff --git a/src/bucket/BucketListSnapshot.h b/src/bucket/BucketListSnapshot.h index 371932456a..4b8007d2fd 100644 --- a/src/bucket/BucketListSnapshot.h +++ b/src/bucket/BucketListSnapshot.h @@ -234,7 +234,6 @@ class SearchableLiveBucketListSnapshot LedgerEntryType type, std::function callback) const; - friend class BucketSnapshotState; friend class CompleteConstLedgerState; friend class LedgerStateSnapshot; }; diff --git a/src/bucket/BucketManager.cpp b/src/bucket/BucketManager.cpp index f190dbabfb..53a1405734 100644 --- a/src/bucket/BucketManager.cpp +++ b/src/bucket/BucketManager.cpp @@ -1156,7 +1156,7 @@ BucketManager::startBackgroundEvictionScan(ApplyLedgerStateSnapshot lclSnapshot, // Start the eviction scan for then _next_ ledger auto ledgerSeq = lclSnapshot.getLedgerSeq() + 1; - auto ledgerVers = lclSnapshot.getLedgerHeader().ledgerVersion; + auto ledgerVers = lclSnapshot.getLedgerHeader().current().ledgerVersion; auto const& sas = cfg.stateArchivalSettings(); @@ -1185,10 +1185,10 @@ BucketManager::resolveBackgroundEvictionScan( ZoneScoped; releaseAssert(mEvictionStatistics); auto timer = mBucketListEvictionMetrics.blockingTime.TimeScope(); - auto ls = LedgerSnapshot(ltx); - auto ledgerSeq = ls.getLedgerHeader().current().ledgerSeq; - auto ledgerVers = ls.getLedgerHeader().current().ledgerVersion; - auto networkConfig = SorobanNetworkConfig::loadFromLedger(ls); + LedgerTxnReadOnly ltxSnap(ltx); + auto ledgerSeq = ltxSnap.getLedgerHeader().current().ledgerSeq; + auto ledgerVers = ltxSnap.getLedgerHeader().current().ledgerVersion; + auto networkConfig = SorobanNetworkConfig::loadFromLedger(ltxSnap); releaseAssert(ledgerSeq == lclSnapshot.getLedgerSeq() + 1); if (!mEvictionFuture.valid()) diff --git a/src/bucket/test/BucketListTests.cpp b/src/bucket/test/BucketListTests.cpp index b58c7788bf..6c95c120a3 100644 --- a/src/bucket/test/BucketListTests.cpp +++ b/src/bucket/test/BucketListTests.cpp @@ -1112,15 +1112,15 @@ TEST_CASE_VERSIONS("eviction scan", "[bucketlist][archival][soroban]") LedgerKey stateArchivalKey(CONFIG_SETTING); stateArchivalKey.configSetting().configSettingID = ConfigSettingID::CONFIG_SETTING_STATE_ARCHIVAL; - LedgerSnapshot ls(*app); - auto stateArchivalEntry = ls.load(stateArchivalKey).current(); + LedgerReadView lrv(*app); + auto stateArchivalEntry = lrv.load(stateArchivalKey).current(); modifyStateArchivalFn(stateArchivalEntry.data.configSetting() .stateArchivalSettings()); LedgerKey evictionIterKey(CONFIG_SETTING); evictionIterKey.configSetting().configSettingID = ConfigSettingID::CONFIG_SETTING_EVICTION_ITERATOR; - auto evictionIterEntry = ls.load(evictionIterKey).current(); + auto evictionIterEntry = lrv.load(evictionIterKey).current(); modifyEvictionIteratorFn( evictionIterEntry.data.configSetting().evictionIterator()); diff --git a/src/bucket/test/BucketTestUtils.cpp b/src/bucket/test/BucketTestUtils.cpp index 8b40088fa0..2cce309b8b 100644 --- a/src/bucket/test/BucketTestUtils.cpp +++ b/src/bucket/test/BucketTestUtils.cpp @@ -310,12 +310,18 @@ LedgerManagerForBucketTests::finalizeLedgerTxnChanges( if (protocolVersionStartsFrom(lh.ledgerVersion, SOROBAN_PROTOCOL_VERSION)) { - auto liveData = - std::make_shared>( - mApp.getBucketManager().getLiveBucketList()); - LedgerSnapshot ls(mApp.getMetrics(), std::move(liveData), lh); - finalSorobanConfig = - std::make_optional(SorobanNetworkConfig::loadFromLedger(ls)); + // Tests may inject config upgrades directly into the BucketList, so + // we need to construct a temp dummy snapshot to load the injected + // config. + LedgerHeaderHistoryEntry tempLcl; + tempLcl.header = lh; + HistoryArchiveState tempHas; + tempHas.currentLedger = lh.ledgerSeq; + auto& bm = mApp.getBucketManager(); + auto tempState = CompleteConstLedgerState::createAndMaybeLoadConfig( + bm.getLiveBucketList(), bm.getHotArchiveBucketList(), tempLcl, + tempHas, mApp.getMetrics(), nullptr, 0); + finalSorobanConfig = tempState->getSorobanConfig(); } mApplyState.updateInMemorySorobanState( diff --git a/src/herder/HerderImpl.cpp b/src/herder/HerderImpl.cpp index 974f6b92a2..ef48c4dce0 100644 --- a/src/herder/HerderImpl.cpp +++ b/src/herder/HerderImpl.cpp @@ -1587,8 +1587,8 @@ HerderImpl::triggerNextLedger(uint32_t ledgerSeqToTrigger, // see if we need to include some upgrades std::vector upgrades; { - LedgerSnapshot ls(mApp); - upgrades = mUpgrades.createUpgradesFor(lcl.header, ls); + LedgerReadView lrv(mApp); + upgrades = mUpgrades.createUpgradesFor(lcl.header, lrv); } for (auto const& upgrade : upgrades) { @@ -1655,8 +1655,8 @@ HerderImpl::setUpgrades(Upgrades::UpgradeParameters const& upgrades) std::string HerderImpl::getUpgradesJson() { - auto ls = LedgerSnapshot(mApp); - return mUpgrades.getParameters().toDebugJson(ls); + auto lrv = LedgerReadView(mApp); + return mUpgrades.getParameters().toDebugJson(lrv); } void diff --git a/src/herder/TransactionQueue.cpp b/src/herder/TransactionQueue.cpp index 1851bd3ee7..b8c904770f 100644 --- a/src/herder/TransactionQueue.cpp +++ b/src/herder/TransactionQueue.cpp @@ -439,7 +439,7 @@ TransactionQueue::canAdd( } } - LedgerSnapshot ls(mApp); + LedgerReadView lrv(mApp); // Subtle: transactions are rejected based on the source account limit // prior to this point. This is safe because we can't evict transactions // from the same source account, so a newer transaction won't replace an @@ -464,11 +464,12 @@ TransactionQueue::canAdd( auto closeTime = mApp.getLedgerManager() .getLastClosedLedgerHeader() .header.scpValue.closeTime; + // Validate minSeqLedgerGap and LedgerBounds against the next ledgerSeq, + // which is what will be used at apply time. + std::optional validationLedgerSeq; if (protocolVersionStartsFrom(ledgerVersion, ProtocolVersion::V_19)) { - // This is done so minSeqLedgerGap is validated against the next - // ledgerSeq, which is what will be used at apply time - ls.getLedgerHeader().currentToModify().ledgerSeq = + validationLedgerSeq = mApp.getLedgerManager().getLastClosedLedgerNum() + 1; } @@ -478,9 +479,10 @@ TransactionQueue::canAdd( if (!isLoadgenTx) #endif { - auto validationResult = tx->checkValid( - mApp.getAppConnector(), ls, 0, 0, - getUpperBoundCloseTimeOffset(mApp, closeTime), diagnosticEvents); + auto validationResult = + tx->checkValid(mApp.getAppConnector(), lrv, 0, 0, + getUpperBoundCloseTimeOffset(mApp, closeTime), + diagnosticEvents, validationLedgerSeq); if (!validationResult->isSuccess()) { return AddResult(TransactionQueue::AddResultCode::ADD_STATUS_ERROR, @@ -497,12 +499,12 @@ TransactionQueue::canAdd( if (!isLoadgenTx && !mApp.getRunInOverlayOnlyMode()) #endif { - auto const feeSource = ls.getAccount(tx->getFeeSourceID()); + auto const feeSource = lrv.getAccount(tx->getFeeSourceID()); auto feeStateIter = mAccountStates.find(tx->getFeeSourceID()); int64_t totalFees = feeStateIter == mAccountStates.end() ? 0 : feeStateIter->second.mTotalFees; - if (getAvailableBalance(ls.getLedgerHeader().current(), + if (getAvailableBalance(lrv.getLedgerHeader().current(), feeSource.current()) - newFullFee < totalFees) diff --git a/src/herder/TxSetUtils.cpp b/src/herder/TxSetUtils.cpp index 1b8100f842..df132c4aad 100644 --- a/src/herder/TxSetUtils.cpp +++ b/src/herder/TxSetUtils.cpp @@ -171,11 +171,16 @@ TxSetUtils::getInvalidTxListWithErrors( { ZoneScoped; releaseAssert(threadIsMain()); - LedgerSnapshot ls(app); - // This is done so minSeqLedgerGap is validated against the next - // ledgerSeq, which is what will be used at apply time - ls.getLedgerHeader().currentToModify().ledgerSeq = - app.getLedgerManager().getLastClosedLedgerNum() + 1; + LedgerReadView lrv(app); + // Validate minSeqLedgerGap and LedgerBounds against the next ledgerSeq, + // which is what will be used at apply time. + std::optional validationLedgerSeq; + if (protocolVersionStartsFrom(lrv.getLedgerHeader().current().ledgerVersion, + ProtocolVersion::V_19)) + { + validationLedgerSeq = + app.getLedgerManager().getLastClosedLedgerNum() + 1; + } TxFrameListWithErrors invalidTxsWithError; auto& invalidTxs = invalidTxsWithError.first; @@ -186,9 +191,9 @@ TxSetUtils::getInvalidTxListWithErrors( auto diagnostics = DiagnosticEventManager::createDisabled(); for (auto const& tx : txs) { - auto txResult = tx->checkValid(app.getAppConnector(), ls, 0, - lowerBoundCloseTimeOffset, - upperBoundCloseTimeOffset, diagnostics); + auto txResult = tx->checkValid( + app.getAppConnector(), lrv, 0, lowerBoundCloseTimeOffset, + upperBoundCloseTimeOffset, diagnostics, validationLedgerSeq); if (!txResult->isSuccess()) { invalidTxs.emplace_back(tx); @@ -209,7 +214,7 @@ TxSetUtils::getInvalidTxListWithErrors( } } - auto header = ls.getLedgerHeader().current(); + auto header = lrv.getLedgerHeader().current(); for (auto const& tx : txs) { // Already added invalid tx @@ -219,7 +224,7 @@ TxSetUtils::getInvalidTxListWithErrors( } auto feeSourceID = tx->getFeeSourceID(); - auto feeSource = ls.getAccount(feeSourceID); + auto feeSource = lrv.getAccount(feeSourceID); // feeSource should exist since we've already run checkValid, log // internal bug if (!feeSource) diff --git a/src/herder/Upgrades.cpp b/src/herder/Upgrades.cpp index 7a7cfc9902..daa2cbf367 100644 --- a/src/herder/Upgrades.cpp +++ b/src/herder/Upgrades.cpp @@ -174,12 +174,12 @@ namespace stellar namespace { uint32_t -readMaxSorobanTxSetSize(LedgerSnapshot const& ls) +readMaxSorobanTxSetSize(LedgerReadView const& lrv) { LedgerKey key(LedgerEntryType::CONFIG_SETTING); key.configSetting().configSettingID = ConfigSettingID::CONFIG_SETTING_CONTRACT_EXECUTION_LANES; - return ls.load(key) + return lrv.load(key) .current() .data.configSetting() .contractExecutionLanes() @@ -211,7 +211,7 @@ Upgrades::UpgradeParameters::toJson() const } std::string -Upgrades::UpgradeParameters::toDebugJson(LedgerSnapshot const& ls) const +Upgrades::UpgradeParameters::toDebugJson(LedgerReadView const& lrv) const { Json::Value upgradesJson; Json::Reader reader; @@ -226,7 +226,7 @@ Upgrades::UpgradeParameters::toDebugJson(LedgerSnapshot const& ls) const upgradesJson.removeMember("configupgradesetkey"); auto upgradeSetPtr = - ConfigUpgradeSetFrame::makeFromKey(ls, *mConfigUpgradeSetKey); + ConfigUpgradeSetFrame::makeFromKey(lrv, *mConfigUpgradeSetKey); if (upgradeSetPtr) { Json::Value configUpgradeSetJson; @@ -277,7 +277,7 @@ Upgrades::getParameters() const std::vector Upgrades::createUpgradesFor(LedgerHeader const& lclHeader, - LedgerSnapshot const& ls) const + LedgerReadView const& lrv) const { auto result = std::vector{}; if (!timeForUpgrade(lclHeader.scpValue.closeTime)) @@ -319,10 +319,10 @@ Upgrades::createUpgradesFor(LedgerHeader const& lclHeader, auto key = mParams.mConfigUpgradeSetKey; if (key) { - auto cfgUpgrade = ConfigUpgradeSetFrame::makeFromKey(ls, *key); + auto cfgUpgrade = ConfigUpgradeSetFrame::makeFromKey(lrv, *key); if (cfgUpgrade != nullptr && cfgUpgrade->isValidForApply() == UpgradeValidity::VALID && - cfgUpgrade->upgradeNeeded(ls)) + cfgUpgrade->upgradeNeeded(lrv)) { result.emplace_back(LEDGER_UPGRADE_CONFIG); result.back().newConfig() = cfgUpgrade->getKey(); @@ -332,7 +332,7 @@ Upgrades::createUpgradesFor(LedgerHeader const& lclHeader, { if (protocolVersionStartsFrom(lclHeader.ledgerVersion, SOROBAN_PROTOCOL_VERSION) && - readMaxSorobanTxSetSize(ls) != *mParams.mMaxSorobanTxSetSize) + readMaxSorobanTxSetSize(lrv) != *mParams.mMaxSorobanTxSetSize) { result.emplace_back(LEDGER_UPGRADE_MAX_SOROBAN_TX_SET_SIZE); result.back().newMaxSorobanTxSetSize() = @@ -365,7 +365,7 @@ Upgrades::applyTo(LedgerUpgrade const& upgrade, Application& app, break; case LEDGER_UPGRADE_CONFIG: { - LedgerSnapshot ltxState(ltx); + LedgerReadView ltxState(ltx); auto cfgUpgrade = ConfigUpgradeSetFrame::makeFromKey(ltxState, upgrade.newConfig()); if (!cfgUpgrade) @@ -564,7 +564,7 @@ Upgrades::removeUpgrades(std::vector::const_iterator beginUpdates, Upgrades::UpgradeValidity Upgrades::isValidForApply(UpgradeType const& opaqueUpgrade, LedgerUpgrade& upgrade, Application& app, - LedgerSnapshot const& ls) + LedgerReadView const& lrv) { try { @@ -576,7 +576,7 @@ Upgrades::isValidForApply(UpgradeType const& opaqueUpgrade, } bool res = true; - auto version = ls.getLedgerHeader().current().ledgerVersion; + auto version = lrv.getLedgerHeader().current().ledgerVersion; switch (upgrade.type()) { case LEDGER_UPGRADE_VERSION: @@ -609,7 +609,7 @@ Upgrades::isValidForApply(UpgradeType const& opaqueUpgrade, return UpgradeValidity::INVALID; } auto cfgUpgrade = - ConfigUpgradeSetFrame::makeFromKey(ls, upgrade.newConfig()); + ConfigUpgradeSetFrame::makeFromKey(lrv, upgrade.newConfig()); if (!cfgUpgrade) { return UpgradeValidity::INVALID; @@ -638,9 +638,9 @@ Upgrades::isValidForApply(UpgradeType const& opaqueUpgrade, bool Upgrades::isValidForNomination(LedgerUpgrade const& upgrade, - LedgerSnapshot const& ls) const + LedgerReadView const& lrv) const { - if (!timeForUpgrade(ls.getLedgerHeader().current().scpValue.closeTime)) + if (!timeForUpgrade(lrv.getLedgerHeader().current().scpValue.closeTime)) { return false; } @@ -668,10 +668,10 @@ Upgrades::isValidForNomination(LedgerUpgrade const& upgrade, } auto cfgUpgrade = - ConfigUpgradeSetFrame::makeFromKey(ls, upgrade.newConfig()); + ConfigUpgradeSetFrame::makeFromKey(lrv, upgrade.newConfig()); return cfgUpgrade && cfgUpgrade->isConsistentWith(ConfigUpgradeSetFrame::makeFromKey( - ls, *mParams.mConfigUpgradeSetKey)); + lrv, *mParams.mConfigUpgradeSetKey)); } case LEDGER_UPGRADE_MAX_SOROBAN_TX_SET_SIZE: return mParams.mMaxSorobanTxSetSize && @@ -687,13 +687,13 @@ Upgrades::isValid(UpgradeType const& upgrade, LedgerUpgradeType& upgradeType, bool nomination, Application& app) const { LedgerUpgrade lupgrade; - auto ls = LedgerSnapshot(app); + auto lrv = LedgerReadView(app); bool res = - isValidForApply(upgrade, lupgrade, app, ls) == UpgradeValidity::VALID; + isValidForApply(upgrade, lupgrade, app, lrv) == UpgradeValidity::VALID; if (nomination) { - res = res && isValidForNomination(lupgrade, ls); + res = res && isValidForNomination(lupgrade, lrv); } if (res) @@ -1290,19 +1290,19 @@ Upgrades::applyReserveUpgrade(AbstractLedgerTxn& ltx, uint32_t newReserve) } ConfigUpgradeSetFrameConstPtr -ConfigUpgradeSetFrame::makeFromKey(LedgerSnapshot const& ls, +ConfigUpgradeSetFrame::makeFromKey(LedgerReadView const& lrv, ConfigUpgradeSetKey const& key) { auto lk = ConfigUpgradeSetFrame::getLedgerKey(key); - auto ltxe = ls.load(lk); + auto ltxe = lrv.load(lk); if (!ltxe) { return nullptr; } - auto ttlLtxe = ls.load(getTTLKey(lk)); + auto ttlLtxe = lrv.load(getTTLKey(lk)); releaseAssert(ttlLtxe); - if (!isLive(ttlLtxe.current(), ls.getLedgerHeader().current().ledgerSeq)) + if (!isLive(ttlLtxe.current(), lrv.getLedgerHeader().current().ledgerSeq)) { return nullptr; } @@ -1326,7 +1326,7 @@ ConfigUpgradeSetFrame::makeFromKey(LedgerSnapshot const& ls, } return std::shared_ptr(new ConfigUpgradeSetFrame( - upgradeSet, key, ls.getLedgerHeader().current().ledgerVersion)); + upgradeSet, key, lrv.getLedgerHeader().current().ledgerVersion)); } ConfigUpgradeSetFrame::ConfigUpgradeSetFrame( @@ -1414,9 +1414,9 @@ ConfigUpgradeSetFrame::getLedgerKey(ConfigUpgradeSetKey const& upgradeKey) } bool -ConfigUpgradeSetFrame::upgradeNeeded(LedgerSnapshot const& ls) const +ConfigUpgradeSetFrame::upgradeNeeded(LedgerReadView const& lrv) const { - if (protocolVersionIsBefore(ls.getLedgerHeader().current().ledgerVersion, + if (protocolVersionIsBefore(lrv.getLedgerHeader().current().ledgerVersion, SOROBAN_PROTOCOL_VERSION)) { return false; @@ -1436,7 +1436,7 @@ ConfigUpgradeSetFrame::upgradeNeeded(LedgerSnapshot const& ls) const LedgerKey key(LedgerEntryType::CONFIG_SETTING); key.configSetting().configSettingID = updatedEntry.configSettingID(); bool isSame = - ls.load(key).current().data.configSetting() == updatedEntry; + lrv.load(key).current().data.configSetting() == updatedEntry; if (!isSame) { return true; diff --git a/src/herder/Upgrades.h b/src/herder/Upgrades.h index 306ef0f172..9a5da3b566 100644 --- a/src/herder/Upgrades.h +++ b/src/herder/Upgrades.h @@ -20,7 +20,7 @@ class Config; class Database; struct LedgerHeader; struct LedgerUpgrade; -class LedgerSnapshot; +class LedgerReadView; class ConfigUpgradeSetFrame; using ConfigUpgradeSetFrameConstPtr = @@ -70,7 +70,7 @@ class Upgrades std::string toJson() const; void fromJson(std::string const& s); - std::string toDebugJson(LedgerSnapshot const& ls) const; + std::string toDebugJson(LedgerReadView const& lrv) const; }; Upgrades() @@ -85,7 +85,7 @@ class Upgrades // create upgrades for given ledger std::vector createUpgradesFor(LedgerHeader const& lclHeader, - LedgerSnapshot const& ls) const; + LedgerReadView const& lrv) const; // apply upgrade to ledger header static void applyTo(LedgerUpgrade const& upgrade, Application& app, @@ -109,7 +109,7 @@ class Upgrades static UpgradeValidity isValidForApply(UpgradeType const& upgrade, LedgerUpgrade& lupgrade, Application& app, - LedgerSnapshot const& ls); + LedgerReadView const& lrv); // returns true if upgrade is a valid upgrade step // in which case it also sets upgradeType @@ -136,7 +136,7 @@ class Upgrades // returns true if upgrade is a valid upgrade step // in which case it also sets lupgrade bool isValidForNomination(LedgerUpgrade const& upgrade, - LedgerSnapshot const& ls) const; + LedgerReadView const& lrv) const; static void applyVersionUpgrade(Application& app, AbstractLedgerTxn& ltx, uint32_t newVersion); @@ -156,7 +156,7 @@ class ConfigUpgradeSetFrame { public: static ConfigUpgradeSetFrameConstPtr - makeFromKey(LedgerSnapshot const& ls, ConfigUpgradeSetKey const& key); + makeFromKey(LedgerReadView const& lrv, ConfigUpgradeSetKey const& key); static LedgerKey getLedgerKey(ConfigUpgradeSetKey const& upgradeKey); @@ -164,7 +164,7 @@ class ConfigUpgradeSetFrame ConfigUpgradeSetKey const& getKey() const; - bool upgradeNeeded(LedgerSnapshot const& ls) const; + bool upgradeNeeded(LedgerReadView const& lrv) const; void applyTo(AbstractLedgerTxn& ltx, Application& app) const; diff --git a/src/herder/test/HerderTests.cpp b/src/herder/test/HerderTests.cpp index 7ea0fe76c3..45d2c7f0b0 100644 --- a/src/herder/test/HerderTests.cpp +++ b/src/herder/test/HerderTests.cpp @@ -311,7 +311,7 @@ testTxSet(uint32 protocolVersion) SECTION("invalid tx") { auto diagnostics = DiagnosticEventManager::createDisabled(); - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); SECTION("no user") { @@ -321,7 +321,7 @@ testTxSet(uint32 protocolVersion) // Individual tx check: account doesn't exist REQUIRE(badTx - ->checkValid(app->getAppConnector(), ls, 0, 0, 0, + ->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txNO_ACCOUNT); @@ -351,7 +351,7 @@ testTxSet(uint32 protocolVersion) // Individual tx check: bad sequence number REQUIRE(badTx - ->checkValid(app->getAppConnector(), ls, 0, 0, 0, + ->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txBAD_SEQ); @@ -382,7 +382,7 @@ testTxSet(uint32 protocolVersion) // Individual tx check: insufficient balance // Need fresh snapshot after account creation - LedgerSnapshot lsNew(*app); + LedgerReadView lsNew(*app); REQUIRE(badTx ->checkValid(app->getAppConnector(), lsNew, 0, 0, 0, diagnostics) @@ -416,7 +416,7 @@ testTxSet(uint32 protocolVersion) // Individual tx check: bad auth (signature invalidated by maxTime // change) REQUIRE(badTx - ->checkValid(app->getAppConnector(), ls, 0, 0, 0, + ->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txBAD_AUTH); @@ -532,7 +532,7 @@ testTxSetWithFeeBumps(uint32 protocolVersion) }; auto diagnostics = DiagnosticEventManager::createDisabled(); - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); SECTION("invalid transaction") { @@ -542,7 +542,7 @@ testTxSetWithFeeBumps(uint32 protocolVersion) auto fb1 = feeBump(*app, account2, tx1, minBalance2); // Individual tx check: fee bump exceeds fee source balance - REQUIRE(fb1->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb1->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txINSUFFICIENT_BALANCE); @@ -568,10 +568,10 @@ testTxSetWithFeeBumps(uint32 protocolVersion) auto fb2 = feeBump(*app, account2, tx2, 200); // Individual tx checks: first exceeds balance, second is valid - REQUIRE(fb1->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb1->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txINSUFFICIENT_BALANCE); - REQUIRE(fb2->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb2->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); @@ -596,10 +596,10 @@ testTxSetWithFeeBumps(uint32 protocolVersion) auto tx2 = transaction(*app, account3, 1, 1, 100); auto fb2 = feeBump(*app, account2, tx2, minBalance2); - REQUIRE(fb1->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb1->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); - REQUIRE(fb2->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb2->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txINSUFFICIENT_BALANCE); @@ -625,10 +625,10 @@ testTxSetWithFeeBumps(uint32 protocolVersion) auto fb2 = feeBump(*app, account2, tx2, 200); // Individual tx checks - REQUIRE(fb1->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb1->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); - REQUIRE(fb2->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb2->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txFEE_BUMP_INNER_FAILED); @@ -657,14 +657,14 @@ testTxSetWithFeeBumps(uint32 protocolVersion) feeBump(*app, account2, tx3, minBalance2 - minBalance0 - 199); // Individual tx checks - REQUIRE(fb1->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb1->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); - REQUIRE(fb2->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb2->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txFEE_BUMP_INNER_FAILED); // Individually, fb2 is valid, but with fb1 it would exceed balance - REQUIRE(fb3->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb3->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); @@ -685,10 +685,10 @@ testTxSetWithFeeBumps(uint32 protocolVersion) SECTION("two fee bumps, same fee source, valid individually, combined " "exceed balance") { - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); auto balanceOfFbAccount = getAvailableBalance( - ls.getLedgerHeader().current(), - ls.getAccount(account2.getPublicKey()).current()); + lrv.getLedgerHeader().current(), + lrv.getAccount(account2.getPublicKey()).current()); // Enforce balance invariance int64_t fee1 = 200; @@ -704,10 +704,10 @@ testTxSetWithFeeBumps(uint32 protocolVersion) auto fb2 = feeBump(*app, account2, tx2, fee2); // Individual txs are valid auto diagnostics = DiagnosticEventManager::createDisabled(); - REQUIRE(fb1->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb1->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); - REQUIRE(fb2->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb2->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); @@ -757,10 +757,10 @@ testTxSetWithFeeBumps(uint32 protocolVersion) createUploadWasmTx(*app, sorobanAccount2, 100, DEFAULT_TEST_RESOURCE_FEE, resources); - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); auto balanceOfFbAccount = getAvailableBalance( - ls.getLedgerHeader().current(), - ls.getAccount(feeSourceAccount.getPublicKey()).current()); + lrv.getLedgerHeader().current(), + lrv.getAccount(feeSourceAccount.getPublicKey()).current()); // Set fees so that each is valid individually but combined they // exceed the fee source's balance @@ -778,10 +778,10 @@ testTxSetWithFeeBumps(uint32 protocolVersion) // Individual txs are valid auto diagnostics = DiagnosticEventManager::createDisabled(); - REQUIRE(fb1->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb1->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); - REQUIRE(fb2->checkValid(app->getAppConnector(), ls, 0, 0, 0, + REQUIRE(fb2->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); @@ -850,11 +850,11 @@ testTxSetWithFeeBumps(uint32 protocolVersion) auto diagnostics = DiagnosticEventManager::createDisabled(); REQUIRE(classicFb - ->checkValid(app->getAppConnector(), ls, 0, 0, 0, + ->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); REQUIRE(sorobanFb - ->checkValid(app->getAppConnector(), ls, 0, 0, 0, + ->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); @@ -907,10 +907,10 @@ TEST_CASE("getInvalidTxListWithErrors returns no duplicates") auto account3 = root->create("a3", minBalance2); auto account4 = root->create("a4", minBalance2); - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); auto balanceOfFeeSource = - getAvailableBalance(ls.getLedgerHeader().current(), - ls.getAccount(account2.getPublicKey()).current()); + getAvailableBalance(lrv.getLedgerHeader().current(), + lrv.getAccount(account2.getPublicKey()).current()); // Create three fee bumps from account2 (fee source): // - fb1: fails checkValid (bad sequence number) @@ -942,12 +942,12 @@ TEST_CASE("getInvalidTxListWithErrors returns no duplicates") // Verify fb1 fails checkValid - inner tx has bad sequence number auto diagnostics = DiagnosticEventManager::createDisabled(); - REQUIRE(fb1->checkValid(app->getAppConnector(), ls, 0, 0, 0, diagnostics) + REQUIRE(fb1->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->getResultCode() == txFEE_BUMP_INNER_FAILED); // Verify fb2 and fb3 pass checkValid individually - REQUIRE(fb2->checkValid(app->getAppConnector(), ls, 0, 0, 0, diagnostics) + REQUIRE(fb2->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); - REQUIRE(fb3->checkValid(app->getAppConnector(), ls, 0, 0, 0, diagnostics) + REQUIRE(fb3->checkValid(app->getAppConnector(), lrv, 0, 0, 0, diagnostics) ->isSuccess()); // Verify combined fees of fb2 + fb3 exceed balance @@ -5176,8 +5176,9 @@ TEST_CASE("ledger state update flow with parallel apply", "[herder][parallel]") REQUIRE(lm.getLastClosedLedgerNum() == lcl); REQUIRE(lm.getLastClosedLedgerHAS().currentLedger == lastHeader.ledgerSeq); - REQUIRE(lm.copyLedgerStateSnapshot().getLedgerHeader() == - lastHeader); + REQUIRE( + lm.copyLedgerStateSnapshot().getLedgerHeader().current() == + lastHeader); // Apply state got committed, but has not yet been propagated to // read-only state @@ -5229,8 +5230,9 @@ TEST_CASE("ledger state update flow with parallel apply", "[herder][parallel]") auto readOnly = lm.getLastClosedLedgerHeader(); REQUIRE(readOnly.header.ledgerSeq == lcl + 1); REQUIRE(lm.getLastClosedLedgerNum() == lcl + 1); - REQUIRE(lm.copyLedgerStateSnapshot().getLedgerHeader() == - readOnly.header); + REQUIRE( + lm.copyLedgerStateSnapshot().getLedgerHeader().current() == + readOnly.header); auto has = lm.getLastClosedLedgerHAS(); REQUIRE(has.currentLedger == readOnly.header.ledgerSeq); diff --git a/src/herder/test/TxSetTests.cpp b/src/herder/test/TxSetTests.cpp index 43c1a97736..78563bf51d 100644 --- a/src/herder/test/TxSetTests.cpp +++ b/src/herder/test/TxSetTests.cpp @@ -1153,8 +1153,8 @@ TEST_CASE("applicable txset validation - transactions belong to correct phase", 1)}, 2000); } - LedgerSnapshot ls(*app); - REQUIRE(tx->checkValid(app->getAppConnector(), ls, 0, 0, 0) + LedgerReadView lrv(*app); + REQUIRE(tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0) ->isSuccess()); return tx; }; @@ -1314,8 +1314,8 @@ TEST_CASE("applicable txset validation - Soroban resources", "[txset][soroban]") auto tx = sorobanTransactionFrameFromOps( app->getNetworkID(), source, {op}, {}, resources, 2000, 100'000'000); - LedgerSnapshot ls(*app); - REQUIRE(tx->checkValid(app->getAppConnector(), ls, 0, 0, 0) + LedgerReadView lrv(*app); + REQUIRE(tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0) ->isSuccess()); return tx; }; @@ -1681,8 +1681,8 @@ TEST_CASE("generalized tx set with multiple txs per source account", // tx1 is valid on its own { - LedgerSnapshot ls(*app); - REQUIRE(tx1->checkValid(app->getAppConnector(), ls, 0, 0, 0) + LedgerReadView lrv(*app); + REQUIRE(tx1->checkValid(app->getAppConnector(), lrv, 0, 0, 0) ->isSuccess()); } @@ -1714,10 +1714,10 @@ TEST_CASE("generalized tx set with multiple txs per source account", // Both txs individually are valid { - LedgerSnapshot ls(*app); - REQUIRE(tx1->checkValid(app->getAppConnector(), ls, 0, 0, 0) + LedgerReadView lrv(*app); + REQUIRE(tx1->checkValid(app->getAppConnector(), lrv, 0, 0, 0) ->isSuccess()); - REQUIRE(tx2->checkValid(app->getAppConnector(), ls, 0, 0, 0) + REQUIRE(tx2->checkValid(app->getAppConnector(), lrv, 0, 0, 0) ->isSuccess()); } @@ -1815,7 +1815,7 @@ TEST_CASE("generalized tx set fees", "[txset][soroban]") } if (validateTx) { - REQUIRE(tx->checkValid(app->getAppConnector(), LedgerSnapshot(*app), + REQUIRE(tx->checkValid(app->getAppConnector(), LedgerReadView(*app), 0, 0, 0) ->isSuccess()); } @@ -2023,7 +2023,7 @@ TEST_CASE("generalized tx set fees", "[txset][soroban]") auto feeBumpTx = feeBump(*app, *root, tx, 300); REQUIRE(feeBumpTx ->checkValid(app->getAppConnector(), - LedgerSnapshot(*app), 0, 0, 0) + LedgerReadView(*app), 0, 0, 0) ->isSuccess()); auto ledgerHash = app->getLedgerManager().getLastClosedLedgerHeader().hash; @@ -2062,7 +2062,7 @@ TEST_CASE("generalized tx set fees", "[txset][soroban]") auto feeBumpTx = feeBump(*app, *root, tx, 200); REQUIRE(feeBumpTx ->checkValid(app->getAppConnector(), - LedgerSnapshot(*app), 0, 0, 0) + LedgerReadView(*app), 0, 0, 0) ->isSuccess()); auto ledgerHash = app->getLedgerManager().getLastClosedLedgerHeader().hash; @@ -2557,9 +2557,9 @@ runParallelTxSetBuildingTest(bool variableStageCount) // its resources. auto tx = createUploadWasmTx(*app, source, inclusionFee, resourceFee, resources); - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); REQUIRE( - tx->checkValid(app->getAppConnector(), ls, 0, 0, 0)->isSuccess()); + tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0)->isSuccess()); return tx; }; diff --git a/src/herder/test/UpgradesTests.cpp b/src/herder/test/UpgradesTests.cpp index 57fa457339..f01acdf154 100644 --- a/src/herder/test/UpgradesTests.cpp +++ b/src/herder/test/UpgradesTests.cpp @@ -339,12 +339,12 @@ testListUpgrades(VirtualClock::system_time_point preferredUpgradeDatetime, makeTxCountUpgrade(cfg.TESTING_UPGRADE_MAX_TX_SET_SIZE); auto baseReserveUpgrade = makeBaseReserveUpgrade(cfg.TESTING_UPGRADE_RESERVE); - auto ls = LedgerSnapshot(*app); + auto lrv = LedgerReadView(*app); SECTION("protocol version upgrade needed") { header.ledgerVersion--; - auto upgrades = Upgrades{cfg}.createUpgradesFor(header, ls); + auto upgrades = Upgrades{cfg}.createUpgradesFor(header, lrv); auto expected = shouldListAny ? std::vector{protocolVersionUpgrade} : std::vector{}; @@ -354,7 +354,7 @@ testListUpgrades(VirtualClock::system_time_point preferredUpgradeDatetime, SECTION("base fee upgrade needed") { header.baseFee /= 2; - auto upgrades = Upgrades{cfg}.createUpgradesFor(header, ls); + auto upgrades = Upgrades{cfg}.createUpgradesFor(header, lrv); auto expected = shouldListAny ? std::vector{baseFeeUpgrade} : std::vector{}; @@ -364,7 +364,7 @@ testListUpgrades(VirtualClock::system_time_point preferredUpgradeDatetime, SECTION("tx count upgrade needed") { header.maxTxSetSize /= 2; - auto upgrades = Upgrades{cfg}.createUpgradesFor(header, ls); + auto upgrades = Upgrades{cfg}.createUpgradesFor(header, lrv); auto expected = shouldListAny ? std::vector{txCountUpgrade} : std::vector{}; @@ -374,7 +374,7 @@ testListUpgrades(VirtualClock::system_time_point preferredUpgradeDatetime, SECTION("base reserve upgrade needed") { header.baseReserve /= 2; - auto upgrades = Upgrades{cfg}.createUpgradesFor(header, ls); + auto upgrades = Upgrades{cfg}.createUpgradesFor(header, lrv); auto expected = shouldListAny ? std::vector{baseReserveUpgrade} : std::vector{}; @@ -387,7 +387,7 @@ testListUpgrades(VirtualClock::system_time_point preferredUpgradeDatetime, header.baseFee /= 2; header.maxTxSetSize /= 2; header.baseReserve /= 2; - auto upgrades = Upgrades{cfg}.createUpgradesFor(header, ls); + auto upgrades = Upgrades{cfg}.createUpgradesFor(header, lrv); auto expected = shouldListAny ? std::vector{protocolVersionUpgrade, @@ -706,14 +706,14 @@ TEST_CASE("config upgrade validation", "[upgrades]") LedgerTxn ltx(app->getLedgerTxnRoot()); ltx.loadHeader().current() = header; - auto ls = LedgerSnapshot(ltx); + auto lrv = LedgerReadView(ltx); LedgerUpgrade outUpgrade; SECTION("valid") { REQUIRE(Upgrades::isValidForApply( toUpgradeType(makeConfigUpgrade(*configUpgradeSet)), outUpgrade, *app, - ls) == Upgrades::UpgradeValidity::VALID); + lrv) == Upgrades::UpgradeValidity::VALID); REQUIRE(outUpgrade.newConfig() == configUpgradeSet->getKey()); } SECTION("unknown upgrade") @@ -725,7 +725,7 @@ TEST_CASE("config upgrade validation", "[upgrades]") ConfigUpgradeSetKey{contractID, upgradeHash}; REQUIRE(Upgrades::isValidForApply(toUpgradeType(ledgerUpgrade), - outUpgrade, *app, ls) == + outUpgrade, *app, lrv) == Upgrades::UpgradeValidity::INVALID); } SECTION("not valid") @@ -742,7 +742,7 @@ TEST_CASE("config upgrade validation", "[upgrades]") toUpgradeType( makeConfigUpgrade(*configUpgradeSetFrame)), outUpgrade, *app, - ls) == Upgrades::UpgradeValidity::XDR_INVALID); + lrv) == Upgrades::UpgradeValidity::XDR_INVALID); }; SECTION("no updated entries") { @@ -796,7 +796,7 @@ TEST_CASE("config upgrade validation", "[upgrades]") upgrade.newConfig() = upgradeKey; REQUIRE(Upgrades::isValidForApply(toUpgradeType(upgrade), - outUpgrade, *app, ls) == + outUpgrade, *app, lrv) == Upgrades::UpgradeValidity::INVALID); } } @@ -807,7 +807,7 @@ TEST_CASE("config upgrade validation", "[upgrades]") toUpgradeType(makeConfigUpgrade( *makeMaxContractSizeBytesTestUpgrade(ltx, 0))), outUpgrade, *app, - ls) == Upgrades::UpgradeValidity::INVALID); + lrv) == Upgrades::UpgradeValidity::INVALID); } } @@ -879,11 +879,11 @@ TEST_CASE("config upgrade validation for protocol 23", "[upgrades]") } LedgerTxn ltx(app->getLedgerTxnRoot()); ltx.loadHeader().current() = header; - auto ls = LedgerSnapshot(ltx); + auto lrv = LedgerReadView(ltx); LedgerUpgrade outUpgrade; return Upgrades::isValidForApply( toUpgradeType(makeConfigUpgrade(*configUpgradeSet)), outUpgrade, - *app, ls); + *app, lrv); }; SECTION("valid for apply") @@ -1098,11 +1098,11 @@ TEST_CASE("upgrades affect in-memory Soroban state state size", .getLedgerManager() .getSorobanInMemoryStateSizeForTesting(); auto getExpectedInMemorySize = [&]() { - LedgerSnapshot ls(test.getApp()); + LedgerReadView lrv(test.getApp()); auto res = expectedInMemorySizeDelta; for (auto const& key : addedKeys) { - auto le = ls.load(key); + auto le = lrv.load(key); res += ledgerEntrySizeForRent(le.current(), xdr::xdr_size(le.current()), 23, test.getNetworkCfg()); @@ -1111,11 +1111,11 @@ TEST_CASE("upgrades affect in-memory Soroban state state size", }; auto getStateSizeWindow = [&]() { - LedgerSnapshot ls(test.getApp()); + LedgerReadView lrv(test.getApp()); LedgerKey key(CONFIG_SETTING); key.configSetting().configSettingID = ConfigSettingID::CONFIG_SETTING_LIVE_SOROBAN_STATE_SIZE_WINDOW; - auto le = ls.load(key); + auto le = lrv.load(key); REQUIRE(le); std::vector windowFromLtx = le.current().data.configSetting().liveSorobanStateSizeWindow(); @@ -1408,11 +1408,11 @@ TEST_CASE("config upgrades applied to ledger", "[soroban][upgrades]") .liveSorobanStateSizeWindowSampleSize == size); }; auto loadWindow = [&]() { - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); LedgerKey key(CONFIG_SETTING); key.configSetting().configSettingID = ConfigSettingID::CONFIG_SETTING_LIVE_SOROBAN_STATE_SIZE_WINDOW; - return ls.load(key) + return lrv.load(key) .current() .data.configSetting() .liveSorobanStateSizeWindow(); @@ -2975,8 +2975,8 @@ TEST_CASE("parallel Soroban settings upgrade", "[upgrades]") } { - LedgerSnapshot ls(*app); - REQUIRE(!ls.load(getParallelComputeSettingsLedgerKey())); + LedgerReadView lrv(*app); + REQUIRE(!lrv.load(getParallelComputeSettingsLedgerKey())); } executeUpgrade(*app, makeProtocolVersionUpgrade(static_cast( @@ -2984,9 +2984,9 @@ TEST_CASE("parallel Soroban settings upgrade", "[upgrades]") // Make sure initial value is correct. { - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); auto parellelComputeEntry = - ls.load(getParallelComputeSettingsLedgerKey()) + lrv.load(getParallelComputeSettingsLedgerKey()) .current() .data.configSetting(); REQUIRE(parellelComputeEntry.configSettingID() == @@ -3011,9 +3011,9 @@ TEST_CASE("parallel Soroban settings upgrade", "[upgrades]") executeUpgrade(*app, makeConfigUpgrade(*configUpgradeSet)); } - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); - REQUIRE(ls.load(getParallelComputeSettingsLedgerKey()) + REQUIRE(lrv.load(getParallelComputeSettingsLedgerKey()) .current() .data.configSetting() .contractParallelCompute() diff --git a/src/history/HistoryManager.h b/src/history/HistoryManager.h index 4c1d80dc9e..9f731f310b 100644 --- a/src/history/HistoryManager.h +++ b/src/history/HistoryManager.h @@ -181,6 +181,9 @@ namespace stellar { class Application; class Bucket; +class CompleteConstLedgerState; +using CompleteConstLedgerStatePtr = + std::shared_ptr; class LiveBucketList; class Config; class Database; @@ -322,15 +325,15 @@ class HistoryManager // a multiple of getCheckpointFrequency(). Returns true if checkpoint // publication of the LCL was queued, otherwise false. ledgerVers must align // with lcl. - virtual bool maybeQueueHistoryCheckpoint(uint32_t lcl, - uint32_t ledgerVers) = 0; + virtual bool + maybeQueueHistoryCheckpoint(CompleteConstLedgerStatePtr ledgerState) = 0; // Checkpoint the LCL -- both the log of history from the previous // checkpoint to it, as well as the bucketlist of its state -- to a // publication-queue in the database. This should be followed shortly - // (typically after commit) with a call to publishQueuedHistory. ledgerVers - // must align with lcl. - virtual void queueCurrentHistory(uint32_t lcl, uint32_t ledgerVers) = 0; + // (typically after commit) with a call to publishQueuedHistory. + virtual void + queueCurrentHistory(CompleteConstLedgerStatePtr ledgerState) = 0; // Return the youngest ledger still in the outgoing publish queue; // returns 0 if the publish queue has nothing in it. diff --git a/src/history/HistoryManagerImpl.cpp b/src/history/HistoryManagerImpl.cpp index 6b7375eb97..11eb836cae 100644 --- a/src/history/HistoryManagerImpl.cpp +++ b/src/history/HistoryManagerImpl.cpp @@ -8,8 +8,6 @@ #include "util/asio.h" #include "bucket/BucketManager.h" -#include "bucket/LiveBucket.h" -#include "bucket/LiveBucketList.h" #include "herder/HerderImpl.h" #include #include @@ -24,7 +22,7 @@ #include "historywork/PutSnapshotFilesWork.h" #include "historywork/ResolveSnapshotWork.h" #include "historywork/WriteSnapshotWork.h" -#include "ledger/LedgerManager.h" +#include "ledger/LedgerStateSnapshot.h" #include "main/Application.h" #include "main/Config.h" #include "medida/meter.h" @@ -285,9 +283,10 @@ HistoryManager::getMaxLedgerQueuedToPublish(Config const& cfg) } bool -HistoryManagerImpl::maybeQueueHistoryCheckpoint(uint32_t lcl, - uint32_t ledgerVers) +HistoryManagerImpl::maybeQueueHistoryCheckpoint( + CompleteConstLedgerStatePtr ledgerState) { + auto lcl = ledgerState->getLastClosedLedgerHeader().header.ledgerSeq; if (!publishCheckpointOnLedgerClose(lcl, mApp.getConfig())) { return false; @@ -308,36 +307,19 @@ HistoryManagerImpl::maybeQueueHistoryCheckpoint(uint32_t lcl, return false; } - queueCurrentHistory(lcl, ledgerVers); + queueCurrentHistory(std::move(ledgerState)); return true; } void -HistoryManagerImpl::queueCurrentHistory(uint32_t ledger, uint32_t ledgerVers) +HistoryManagerImpl::queueCurrentHistory(CompleteConstLedgerStatePtr ledgerState) { ZoneScoped; - // Only one thread can modify the bucketlist, access BL from the _same_ - // thread - LiveBucketList bl = mApp.getBucketManager().getLiveBucketList(); - - HistoryArchiveState has; - if (protocolVersionStartsFrom( - ledgerVers, - LiveBucket::FIRST_PROTOCOL_SUPPORTING_PERSISTENT_EVICTION)) - { - auto hotBl = mApp.getBucketManager().getHotArchiveBucketList(); - has = HistoryArchiveState(ledger, bl, hotBl, - mApp.getConfig().NETWORK_PASSPHRASE); - } - else - { - has = HistoryArchiveState(ledger, bl, - mApp.getConfig().NETWORK_PASSPHRASE); - } - - CLOG_INFO(History, "Queueing publish state for ledger {}", ledger); - mEnqueueTimes.emplace(ledger, std::chrono::steady_clock::now()); + auto const& has = ledgerState->getLastClosedHistoryArchiveState(); + CLOG_INFO(History, "Queueing publish state for ledger {}", + has.currentLedger); + mEnqueueTimes.emplace(has.currentLedger, std::chrono::steady_clock::now()); // We queue history inside ledger commit, so do not finalize the file yet writeCheckpointFile(mApp, has, /* finalize */ false); diff --git a/src/history/HistoryManagerImpl.h b/src/history/HistoryManagerImpl.h index f5c495b8a2..2a1a0ec506 100644 --- a/src/history/HistoryManagerImpl.h +++ b/src/history/HistoryManagerImpl.h @@ -45,10 +45,10 @@ class HistoryManagerImpl : public HistoryManager void logAndUpdatePublishStatus() override; - bool maybeQueueHistoryCheckpoint(uint32_t lcl, - uint32_t ledgerVers) override; + bool maybeQueueHistoryCheckpoint( + CompleteConstLedgerStatePtr ledgerState) override; - void queueCurrentHistory(uint32_t lcl, uint32_t ledgerVers) override; + void queueCurrentHistory(CompleteConstLedgerStatePtr ledgerState) override; void takeSnapshotAndPublish(HistoryArchiveState const& has); diff --git a/src/invariant/ArchivedStateConsistency.cpp b/src/invariant/ArchivedStateConsistency.cpp index 271a3c1b31..79375e55a3 100644 --- a/src/invariant/ArchivedStateConsistency.cpp +++ b/src/invariant/ArchivedStateConsistency.cpp @@ -49,7 +49,7 @@ ArchivedStateConsistency::checkOnLedgerCommit( std::chrono::milliseconds(1)); auto ledgerSeq = lclSnapshot.getLedgerSeq() + 1; - auto ledgerVers = lclSnapshot.getLedgerHeader().ledgerVersion; + auto ledgerVers = lclSnapshot.getLedgerHeader().current().ledgerVersion; if (protocolVersionIsBefore( ledgerVers, diff --git a/src/invariant/BucketListStateConsistency.cpp b/src/invariant/BucketListStateConsistency.cpp index 53bd905c86..65978b6710 100644 --- a/src/invariant/BucketListStateConsistency.cpp +++ b/src/invariant/BucketListStateConsistency.cpp @@ -43,7 +43,7 @@ BucketListStateConsistency::checkSnapshot( LogSlowExecution logSlow("BucketListStateConsistency::checkSnapshot", LogSlowExecution::Mode::AUTOMATIC_RAII, "took", std::chrono::minutes(2)); - auto const& header = snapshot.getLedgerHeader(); + auto const& header = snapshot.getLedgerHeader().current(); if (protocolVersionIsBefore(header.ledgerVersion, SOROBAN_PROTOCOL_VERSION)) { @@ -66,8 +66,7 @@ BucketListStateConsistency::checkSnapshot( std::string errorMsg; // Property 7: Track total entry sizes for validation - LedgerSnapshot lsForConfig(snapshot); - auto sorobanConfig = SorobanNetworkConfig::loadFromLedger(lsForConfig); + auto sorobanConfig = SorobanNetworkConfig::loadFromLedger(snapshot); uint64_t expectedSorobanSize = 0; auto checkLiveEntry = [&seenLiveNonTTLKeys, &seenDeadKeys, &errorMsg, diff --git a/src/invariant/ConservationOfLumens.cpp b/src/invariant/ConservationOfLumens.cpp index f3d9795684..2df5c01ed5 100644 --- a/src/invariant/ConservationOfLumens.cpp +++ b/src/invariant/ConservationOfLumens.cpp @@ -318,7 +318,7 @@ ConservationOfLumens::checkSnapshot( LogSlowExecution::Mode::AUTOMATIC_RAII, "took", std::chrono::seconds(90)); - auto const& header = snapshot.getLedgerHeader(); + auto const& header = snapshot.getLedgerHeader().current(); // This invariant can fail prior to v24 due to bugs if (protocolVersionIsBefore(header.ledgerVersion, ProtocolVersion::V_24)) diff --git a/src/ledger/InMemorySorobanState.cpp b/src/ledger/InMemorySorobanState.cpp index ded1ec1bcf..1ea5053d2a 100644 --- a/src/ledger/InMemorySorobanState.cpp +++ b/src/ledger/InMemorySorobanState.cpp @@ -451,12 +451,11 @@ InMemorySorobanState::initializeStateFromSnapshot( releaseAssertOrThrow(mContractCodeEntries.empty()); releaseAssertOrThrow(mPendingTTLs.empty()); - auto const& lclHeader = snap.getLedgerHeader(); + auto const& lclHeader = snap.getLedgerHeader().current(); auto ledgerVersion = lclHeader.ledgerVersion; if (protocolVersionStartsFrom(ledgerVersion, SOROBAN_PROTOCOL_VERSION)) { - LedgerSnapshot ls(snap); - auto sorobanConfig = SorobanNetworkConfig::loadFromLedger(ls); + auto sorobanConfig = SorobanNetworkConfig::loadFromLedger(snap); // Check if entry is a DEADENTRY and add it to deletedKeys. Otherwise, // check if the entry is shadowed by a DEADENTRY. std::unordered_set deletedKeys; diff --git a/src/ledger/LedgerManagerImpl.cpp b/src/ledger/LedgerManagerImpl.cpp index 4c14006952..7636dc6941 100644 --- a/src/ledger/LedgerManagerImpl.cpp +++ b/src/ledger/LedgerManagerImpl.cpp @@ -1134,8 +1134,7 @@ LedgerManagerImpl::ApplyState::maybeRebuildModuleCache( // linearTerm is in 1/128ths in the cost model, to reduce rounding error. uint64_t scale = 128; - LedgerSnapshot lsForConfig(snap); - auto sorobanConfig = SorobanNetworkConfig::loadFromLedger(lsForConfig); + auto sorobanConfig = SorobanNetworkConfig::loadFromLedger(snap); auto const& memParams = sorobanConfig.memCostParams(); if (memParams.size() > (size_t)stellar::VmInstantiation) { @@ -1664,9 +1663,9 @@ LedgerManagerImpl::applyLedger(LedgerCloseData const& ledgerData, for (size_t i = 0; i < sv.upgrades.size(); i++) { LedgerUpgrade lupgrade; - LedgerSnapshot ls(ltx); + LedgerReadView lrv(ltx); auto valid = - Upgrades::isValidForApply(sv.upgrades[i], lupgrade, mApp, ls); + Upgrades::isValidForApply(sv.upgrades[i], lupgrade, mApp, lrv); switch (valid) { case Upgrades::UpgradeValidity::VALID: @@ -1711,7 +1710,6 @@ LedgerManagerImpl::applyLedger(LedgerCloseData const& ledgerData, } } - auto maybeNewVersion = ltx.loadHeader().current().ledgerVersion; auto ledgerSeq = ltx.loadHeader().current().ledgerSeq; auto lclSnap = mApplyState.copyLedgerStateSnapshot(); @@ -1819,7 +1817,7 @@ LedgerManagerImpl::applyLedger(LedgerCloseData const& ledgerData, // consistent with the ledger header, we must base checkpoints off the new // ledgerVers here and not the initial ledgerVers. auto& hm = mApp.getHistoryManager(); - hm.maybeQueueHistoryCheckpoint(ledgerSeq, maybeNewVersion); + hm.maybeQueueHistoryCheckpoint(appliedLedgerState); JITTER_INJECT_DELAY(); // step 2 @@ -2108,25 +2106,23 @@ LedgerManagerImpl::buildLedgerState( mApplyState.threadInvariant(); auto& bm = mApp.getBucketManager(); - // If the caller didn't provide a SorobanNetworkConfig, load it from the - // BucketList (at this point the BucketList must have already been updated). - if (!sorobanConfig && protocolVersionStartsFrom(header.ledgerVersion, - SOROBAN_PROTOCOL_VERSION)) - { - auto liveData = std::make_shared>( - bm.getLiveBucketList()); - LedgerSnapshot ls(mApp.getMetrics(), std::move(liveData), header); - sorobanConfig = SorobanNetworkConfig::loadFromLedger(ls); - } - LedgerHeaderHistoryEntry lcl; lcl.header = header; lcl.hash = xdrSha256(header); - return std::make_shared( + if (sorobanConfig) + { + // Caller already loaded config (e.g. from LTX during ledger close) + return std::make_shared( + bm.getLiveBucketList(), bm.getHotArchiveBucketList(), lcl, has, + std::move(sorobanConfig), std::move(prevState), + mNumHistoricalSnapshots); + } + + // Auto-load SorobanNetworkConfig from the BucketList + return CompleteConstLedgerState::createAndMaybeLoadConfig( bm.getLiveBucketList(), bm.getHotArchiveBucketList(), lcl, has, - std::move(sorobanConfig), std::move(prevState), - mNumHistoricalSnapshots); + mApp.getMetrics(), std::move(prevState), mNumHistoricalSnapshots); } CompleteConstLedgerStatePtr diff --git a/src/ledger/LedgerStateSnapshot.cpp b/src/ledger/LedgerStateSnapshot.cpp index dd1052db1b..f9d180080b 100644 --- a/src/ledger/LedgerStateSnapshot.cpp +++ b/src/ledger/LedgerStateSnapshot.cpp @@ -11,6 +11,7 @@ #include "main/Application.h" #include "transactions/TransactionFrame.h" #include "transactions/TransactionUtils.h" +#include "util/ProtocolVersion.h" #include "xdr/Stellar-ledger.h" namespace stellar @@ -72,23 +73,10 @@ LedgerHeaderWrapper::LedgerHeaderWrapper(LedgerTxnHeader&& header) { } -LedgerHeaderWrapper::LedgerHeaderWrapper(std::shared_ptr header) - : mHeader(header) -{ -} - -LedgerHeader& -LedgerHeaderWrapper::currentToModify() +LedgerHeaderWrapper::LedgerHeaderWrapper( + std::shared_ptr header) + : mHeader(std::move(header)) { - switch (mHeader.index()) - { - case 0: - return std::get<0>(mHeader).current(); - case 1: - return *std::get<1>(mHeader); - default: - throw std::runtime_error("Invalid LedgerHeaderWrapper index"); - } } LedgerHeader const& @@ -162,86 +150,19 @@ LedgerTxnReadOnly::load(LedgerKey const& key) const void LedgerTxnReadOnly::executeWithMaybeInnerSnapshot( - std::function f) const + std::function f) const { LedgerTxn inner(mLedgerTxn); - LedgerSnapshot lsg(inner); - return f(lsg); -} - -BucketSnapshotState::BucketSnapshotState(LedgerStateSnapshot const& snap) - : mLiveSnap(snap.mLiveSnapshot) - , mLedgerHeader(std::make_shared(snap.getLedgerHeader())) -{ -} - -BucketSnapshotState::BucketSnapshotState(ApplyLedgerStateSnapshot const& snap) - : mLiveSnap(static_cast(snap).mLiveSnapshot) - , mLedgerHeader(std::make_shared(snap.getLedgerHeader())) -{ -} - -BucketSnapshotState::BucketSnapshotState( - MetricsRegistry& metrics, - std::shared_ptr const> liveData, - LedgerHeader const& header) - : mLiveSnap(metrics, std::move(liveData), {}, header.ledgerSeq) - , mLedgerHeader(std::make_shared(header)) -{ -} - -BucketSnapshotState::~BucketSnapshotState() -{ -} - -LedgerHeaderWrapper -BucketSnapshotState::getLedgerHeader() const -{ - return LedgerHeaderWrapper(mLedgerHeader); -} - -LedgerEntryWrapper -BucketSnapshotState::getAccount(AccountID const& account) const -{ - return LedgerEntryWrapper(mLiveSnap.load(accountKey(account))); -} - -LedgerEntryWrapper -BucketSnapshotState::getAccount(LedgerHeaderWrapper const& header, - TransactionFrame const& tx) const -{ - return getAccount(tx.getSourceID()); -} - -LedgerEntryWrapper -BucketSnapshotState::getAccount(LedgerHeaderWrapper const& header, - TransactionFrame const& tx, - AccountID const& AccountID) const -{ - return getAccount(AccountID); -} - -LedgerEntryWrapper -BucketSnapshotState::load(LedgerKey const& key) const -{ - return LedgerEntryWrapper(mLiveSnap.load(key)); -} - -void -BucketSnapshotState::executeWithMaybeInnerSnapshot( - std::function f) const -{ - throw std::runtime_error( - "BucketSnapshotState::executeWithMaybeInnerSnapshot is illegal: " - "BucketSnapshotState has no nested snapshots"); + LedgerReadView lrv(inner); + return f(lrv); } -LedgerSnapshot::LedgerSnapshot(AbstractLedgerTxn& ltx) +LedgerReadView::LedgerReadView(AbstractLedgerTxn& ltx) : mGetter(std::make_unique(ltx)) { } -LedgerSnapshot::LedgerSnapshot(Application& app) +LedgerReadView::LedgerReadView(Application& app) { releaseAssert(threadIsMain()); #ifdef BUILD_TESTS @@ -256,51 +177,37 @@ LedgerSnapshot::LedgerSnapshot(Application& app) else #endif { - auto snap = app.getLedgerManager().copyLedgerStateSnapshot(); - mGetter = std::make_unique(snap); + mGetter = std::make_unique( + app.getLedgerManager().copyLedgerStateSnapshot()); } } -LedgerSnapshot::LedgerSnapshot(LedgerStateSnapshot const& snap) - : mGetter(std::make_unique(snap)) -{ -} - -LedgerSnapshot::LedgerSnapshot(ApplyLedgerStateSnapshot const& snap) - : mGetter(std::make_unique(snap)) -{ -} - -LedgerSnapshot::LedgerSnapshot( - MetricsRegistry& metrics, - std::shared_ptr const> liveData, - LedgerHeader const& header) - : mGetter(std::make_unique( - metrics, std::move(liveData), header)) +LedgerReadView::LedgerReadView(LedgerStateSnapshot const& snap) + : mGetter(std::make_unique(snap)) { } LedgerHeaderWrapper -LedgerSnapshot::getLedgerHeader() const +LedgerReadView::getLedgerHeader() const { return mGetter->getLedgerHeader(); } LedgerEntryWrapper -LedgerSnapshot::getAccount(AccountID const& account) const +LedgerReadView::getAccount(AccountID const& account) const { return mGetter->getAccount(account); } LedgerEntryWrapper -LedgerSnapshot::load(LedgerKey const& key) const +LedgerReadView::load(LedgerKey const& key) const { return mGetter->load(key); } void -LedgerSnapshot::executeWithMaybeInnerSnapshot( - std::function f) const +LedgerReadView::executeWithMaybeInnerSnapshot( + std::function f) const { return mGetter->executeWithMaybeInnerSnapshot(f); } @@ -401,6 +308,30 @@ CompleteConstLedgerState::getLastClosedHistoryArchiveState() const return mLastClosedHistoryArchiveState; } +CompleteConstLedgerStatePtr +CompleteConstLedgerState::createAndMaybeLoadConfig( + LiveBucketList const& liveBL, HotArchiveBucketList const& hotArchiveBL, + LedgerHeaderHistoryEntry const& lcl, HistoryArchiveState const& has, + MetricsRegistry& metrics, CompleteConstLedgerStatePtr prevState, + uint32_t numHistoricalSnapshots) +{ + std::optional sorobanConfig; + if (protocolVersionStartsFrom(lcl.header.ledgerVersion, + SOROBAN_PROTOCOL_VERSION)) + { + // Bootstrap: build a lightweight temporary state (no historical + // snapshots) just to load config from the current live bucket list. + auto tempState = std::make_shared( + liveBL, hotArchiveBL, lcl, has, /*sorobanConfig*/ std::nullopt, + /*prevState*/ nullptr, /*numHistoricalSnapshots*/ 0); + LedgerStateSnapshot tempSnap(tempState, metrics); + sorobanConfig = SorobanNetworkConfig::loadFromLedger(tempSnap); + } + return std::make_shared( + liveBL, hotArchiveBL, lcl, has, std::move(sorobanConfig), + std::move(prevState), numHistoricalSnapshots); +} + LedgerStateSnapshot::LedgerStateSnapshot(CompleteConstLedgerStatePtr state, MetricsRegistry& metrics) : mState(state) @@ -421,10 +352,12 @@ LedgerStateSnapshot::getState() const return *mState; } -LedgerHeader const& +LedgerHeaderWrapper LedgerStateSnapshot::getLedgerHeader() const { - return mState->getLastClosedLedgerHeader().header; + // Avoid copying the header by aliasing the lifetime to mState shared_ptr + return LedgerHeaderWrapper(std::shared_ptr( + mState, &mState->getLastClosedLedgerHeader().header)); } uint32_t @@ -433,6 +366,42 @@ LedgerStateSnapshot::getLedgerSeq() const return mState->getLastClosedLedgerHeader().header.ledgerSeq; } +LedgerEntryWrapper +LedgerStateSnapshot::getAccount(AccountID const& account) const +{ + return LedgerEntryWrapper(loadLiveEntry(accountKey(account))); +} + +LedgerEntryWrapper +LedgerStateSnapshot::getAccount(LedgerHeaderWrapper const& header, + TransactionFrame const& tx) const +{ + return getAccount(tx.getSourceID()); +} + +LedgerEntryWrapper +LedgerStateSnapshot::getAccount(LedgerHeaderWrapper const& header, + TransactionFrame const& tx, + AccountID const& AccountID) const +{ + return getAccount(AccountID); +} + +LedgerEntryWrapper +LedgerStateSnapshot::load(LedgerKey const& key) const +{ + return LedgerEntryWrapper(loadLiveEntry(key)); +} + +void +LedgerStateSnapshot::executeWithMaybeInnerSnapshot( + std::function f) const +{ + throw std::runtime_error( + "LedgerStateSnapshot::executeWithMaybeInnerSnapshot is illegal: " + "LedgerStateSnapshot has no nested snapshots"); +} + // === Live BucketList wrapper methods === std::shared_ptr diff --git a/src/ledger/LedgerStateSnapshot.h b/src/ledger/LedgerStateSnapshot.h index 38f0881de1..7f7c682fe7 100644 --- a/src/ledger/LedgerStateSnapshot.h +++ b/src/ledger/LedgerStateSnapshot.h @@ -17,7 +17,7 @@ namespace stellar class Application; class TransactionFrame; -class LedgerSnapshot; +class LedgerReadView; class ApplyLedgerStateSnapshot; class CompleteConstLedgerState; class EvictionStatistics; @@ -60,12 +60,11 @@ class LedgerEntryWrapper // cosmetic for BucketList snapshots, since those are immutable. class LedgerHeaderWrapper { - std::variant> mHeader; + std::variant> mHeader; public: explicit LedgerHeaderWrapper(LedgerTxnHeader&& header); - explicit LedgerHeaderWrapper(std::shared_ptr header); - LedgerHeader& currentToModify(); + explicit LedgerHeaderWrapper(std::shared_ptr header); LedgerHeader const& current() const; LedgerTxnHeader const& getLedgerTxnHeader() const @@ -93,7 +92,7 @@ class AbstractLedgerStateSnapshot // to support the replay of old buggy protocols (<8), see // `TransactionFrame::loadSourceAccount` virtual void executeWithMaybeInnerSnapshot( - std::function f) const = 0; + std::function f) const = 0; }; // A concrete implementation of read-only SQL snapshot wrapper @@ -116,14 +115,14 @@ class LedgerTxnReadOnly : public AbstractLedgerStateSnapshot AccountID const& AccountID) const override; LedgerEntryWrapper load(LedgerKey const& key) const override; void executeWithMaybeInnerSnapshot( - std::function f) const override; + std::function f) const override; }; // A copyable value type that provides searchable access to a // CompleteConstLedgerState. Each instance maintains its own file stream cache // for bucket I/O. Multiple LedgerStateSnapshot instances can safely wrap the // same CompleteConstLedgerState. -class LedgerStateSnapshot +class LedgerStateSnapshot : public virtual AbstractLedgerStateSnapshot { std::shared_ptr mState; SearchableLiveBucketListSnapshot mLiveSnapshot; @@ -131,7 +130,6 @@ class LedgerStateSnapshot std::reference_wrapper mMetrics; friend class CompleteConstLedgerState; - friend class BucketSnapshotState; public: // Construct from CompleteConstLedgerState @@ -139,9 +137,20 @@ class LedgerStateSnapshot MetricsRegistry& metrics); CompleteConstLedgerState const& getState() const; - LedgerHeader const& getLedgerHeader() const; + LedgerHeaderWrapper getLedgerHeader() const override; uint32_t getLedgerSeq() const; + // === AbstractLedgerStateSnapshot overrides === + LedgerEntryWrapper getAccount(AccountID const& account) const override; + LedgerEntryWrapper getAccount(LedgerHeaderWrapper const& header, + TransactionFrame const& tx) const override; + LedgerEntryWrapper getAccount(LedgerHeaderWrapper const& header, + TransactionFrame const& tx, + AccountID const& AccountID) const override; + LedgerEntryWrapper load(LedgerKey const& key) const override; + void executeWithMaybeInnerSnapshot( + std::function f) const override; + // === Live BucketList methods === std::shared_ptr loadLiveEntry(LedgerKey const& k) const; std::vector @@ -179,17 +188,19 @@ class LedgerStateSnapshot // during apply time. This is identical to LedgerStateSnapshot in practice, but // is a distinct type to prevent accidental interchange between apply-time // snapshots and other snapshots (e.g., from mLastClosedLedgerState). -class ApplyLedgerStateSnapshot : private LedgerStateSnapshot +class ApplyLedgerStateSnapshot : private LedgerStateSnapshot, + public virtual AbstractLedgerStateSnapshot { - friend class BucketSnapshotState; - public: explicit ApplyLedgerStateSnapshot(CompleteConstLedgerStatePtr state, MetricsRegistry& metrics); + using LedgerStateSnapshot::executeWithMaybeInnerSnapshot; + using LedgerStateSnapshot::getAccount; using LedgerStateSnapshot::getLedgerHeader; using LedgerStateSnapshot::getLedgerSeq; using LedgerStateSnapshot::getState; + using LedgerStateSnapshot::load; using LedgerStateSnapshot::loadArchiveEntry; using LedgerStateSnapshot::loadArchiveKeys; using LedgerStateSnapshot::loadArchiveKeysFromLedger; @@ -203,58 +214,22 @@ class ApplyLedgerStateSnapshot : private LedgerStateSnapshot using LedgerStateSnapshot::scanLiveEntriesOfType; }; -// A concrete implementation of read-only BucketList snapshot wrapper -class BucketSnapshotState : public AbstractLedgerStateSnapshot -{ - SearchableLiveBucketListSnapshot mLiveSnap; - // Store a copy of the header. This is needed for validation flow where - // for certain validation scenarios the header needs to be modified. - std::shared_ptr mLedgerHeader; - - public: - explicit BucketSnapshotState(LedgerStateSnapshot const& snap); - explicit BucketSnapshotState(ApplyLedgerStateSnapshot const& snap); - BucketSnapshotState( - MetricsRegistry& metrics, - std::shared_ptr const> liveData, - LedgerHeader const& header); - ~BucketSnapshotState() override; - - LedgerHeaderWrapper getLedgerHeader() const override; - LedgerEntryWrapper getAccount(AccountID const& account) const override; - LedgerEntryWrapper getAccount(LedgerHeaderWrapper const& header, - TransactionFrame const& tx) const override; - LedgerEntryWrapper getAccount(LedgerHeaderWrapper const& header, - TransactionFrame const& tx, - AccountID const& AccountID) const override; - LedgerEntryWrapper load(LedgerKey const& key) const override; - void executeWithMaybeInnerSnapshot( - std::function f) const override; -}; - // A helper class to create and query read-only snapshots // Automatically decides whether to create a BucketList (recommended), or SQL // snapshot (deprecated, but currently supported) -// NOTE: LedgerSnapshot is meant to be short-lived, and should not be persisted +// NOTE: LedgerReadView is meant to be short-lived, and should not be persisted // across _different_ ledgers, as the state under the hood might change. Users -// are expected to construct a new LedgerSnapshot each time they want to query +// are expected to construct a new LedgerReadView each time they want to query // ledger state. -class LedgerSnapshot : public NonMovableOrCopyable +class LedgerReadView : public NonMovableOrCopyable { std::unique_ptr mGetter; std::unique_ptr mLegacyLedgerTxn; public: - LedgerSnapshot(AbstractLedgerTxn& ltx); - LedgerSnapshot(Application& app); - explicit LedgerSnapshot(LedgerStateSnapshot const& snap); - explicit LedgerSnapshot(ApplyLedgerStateSnapshot const& snap); - // Construct from a lightweight live bucket snapshot + header, - // without requiring a full CompleteConstLedgerState. - LedgerSnapshot( - MetricsRegistry& metrics, - std::shared_ptr const> liveData, - LedgerHeader const& header); + LedgerReadView(AbstractLedgerTxn& ltx); + LedgerReadView(Application& app); + explicit LedgerReadView(LedgerStateSnapshot const& snap); LedgerHeaderWrapper getLedgerHeader() const; LedgerEntryWrapper getAccount(AccountID const& account) const; LedgerEntryWrapper @@ -275,7 +250,7 @@ class LedgerSnapshot : public NonMovableOrCopyable // to support the replay of old buggy protocols (<8), see // `TransactionFrame::loadSourceAccount` void executeWithMaybeInnerSnapshot( - std::function f) const; + std::function f) const; }; // Immutable wrapper for a complete ledger state snapshot. @@ -331,6 +306,14 @@ class CompleteConstLedgerState : public NonMovableOrCopyable CompleteConstLedgerStatePtr prevState, uint32_t numHistoricalSnapshots); + // Factory: constructs a CompleteConstLedgerState, auto-loading the + // SorobanNetworkConfig from the bucket list when the protocol requires it. + static CompleteConstLedgerStatePtr createAndMaybeLoadConfig( + LiveBucketList const& liveBL, HotArchiveBucketList const& hotArchiveBL, + LedgerHeaderHistoryEntry const& lcl, HistoryArchiveState const& has, + MetricsRegistry& metrics, CompleteConstLedgerStatePtr prevState, + uint32_t numHistoricalSnapshots); + SorobanNetworkConfig const& getSorobanConfig() const; bool hasSorobanConfig() const; LedgerHeaderHistoryEntry const& getLastClosedLedgerHeader() const; diff --git a/src/ledger/NetworkConfig.cpp b/src/ledger/NetworkConfig.cpp index e3e03eed11..882fa08a20 100644 --- a/src/ledger/NetworkConfig.cpp +++ b/src/ledger/NetworkConfig.cpp @@ -1751,7 +1751,7 @@ SorobanNetworkConfig::initializeGenesisLedgerForTesting( } SorobanNetworkConfig -SorobanNetworkConfig::loadFromLedger(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadFromLedger(AbstractLedgerStateSnapshot const& ls) { ZoneScoped; SorobanNetworkConfig config; @@ -1791,8 +1791,8 @@ SorobanNetworkConfig::loadFromLedger(LedgerSnapshot const& ls) SorobanNetworkConfig SorobanNetworkConfig::loadFromLedger(AbstractLedgerTxn& ltx) { - LedgerSnapshot ls(ltx); - return SorobanNetworkConfig::loadFromLedger(ls); + LedgerTxnReadOnly snap(ltx); + return SorobanNetworkConfig::loadFromLedger(snap); } #ifdef BUILD_TESTS @@ -1804,7 +1804,7 @@ SorobanNetworkConfig::emptyConfig() #endif void -SorobanNetworkConfig::loadMaxContractSize(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadMaxContractSize(AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1818,7 +1818,8 @@ SorobanNetworkConfig::loadMaxContractSize(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadMaxContractDataKeySize(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadMaxContractDataKeySize( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1833,7 +1834,8 @@ SorobanNetworkConfig::loadMaxContractDataKeySize(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadMaxContractDataEntrySize(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadMaxContractDataEntrySize( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1848,7 +1850,7 @@ SorobanNetworkConfig::loadMaxContractDataEntrySize(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadComputeSettings(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadComputeSettings(AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1867,7 +1869,8 @@ SorobanNetworkConfig::loadComputeSettings(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadLedgerAccessSettings(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadLedgerAccessSettings( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1914,7 +1917,8 @@ SorobanNetworkConfig::loadLedgerAccessSettings(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadHistoricalSettings(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadHistoricalSettings( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1930,7 +1934,8 @@ SorobanNetworkConfig::loadHistoricalSettings(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadContractEventsSettings(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadContractEventsSettings( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1946,7 +1951,8 @@ SorobanNetworkConfig::loadContractEventsSettings(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadBandwidthSettings(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadBandwidthSettings( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1963,7 +1969,7 @@ SorobanNetworkConfig::loadBandwidthSettings(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadCpuCostParams(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadCpuCostParams(AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1977,7 +1983,7 @@ SorobanNetworkConfig::loadCpuCostParams(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadMemCostParams(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadMemCostParams(AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -1991,7 +1997,8 @@ SorobanNetworkConfig::loadMemCostParams(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadExecutionLanesSettings(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadExecutionLanesSettings( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -2007,7 +2014,8 @@ SorobanNetworkConfig::loadExecutionLanesSettings(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadLiveSorobanStateSizeWindow(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadLiveSorobanStateSizeWindow( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -2037,7 +2045,8 @@ SorobanNetworkConfig::loadLiveSorobanStateSizeWindow(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadEvictionIterator(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadEvictionIterator( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -2050,7 +2059,8 @@ SorobanNetworkConfig::loadEvictionIterator(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadParallelComputeConfig(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadParallelComputeConfig( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; LedgerKey key(CONFIG_SETTING); @@ -2065,7 +2075,8 @@ SorobanNetworkConfig::loadParallelComputeConfig(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadLedgerCostExtConfig(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadLedgerCostExtConfig( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; LedgerKey key(CONFIG_SETTING); @@ -2080,7 +2091,7 @@ SorobanNetworkConfig::loadLedgerCostExtConfig(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadSCPTimingConfig(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadSCPTimingConfig(AbstractLedgerStateSnapshot const& ls) { ZoneScoped; LedgerKey key(CONFIG_SETTING); @@ -2121,7 +2132,8 @@ SorobanNetworkConfig::maxContractDataEntrySizeBytes() const } void -SorobanNetworkConfig::loadStateArchivalSettings(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadStateArchivalSettings( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; @@ -2529,7 +2541,8 @@ SorobanNetworkConfig::isFreezeBypassTx(Hash const& txHash) const } void -SorobanNetworkConfig::loadFrozenLedgerKeys(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadFrozenLedgerKeys( + AbstractLedgerStateSnapshot const& ls) { ZoneScoped; mFrozenLedgerKeys.clear(); @@ -2550,7 +2563,7 @@ SorobanNetworkConfig::loadFrozenLedgerKeys(LedgerSnapshot const& ls) } void -SorobanNetworkConfig::loadFreezeBypassTxs(LedgerSnapshot const& ls) +SorobanNetworkConfig::loadFreezeBypassTxs(AbstractLedgerStateSnapshot const& ls) { ZoneScoped; mFreezeBypassTxs.clear(); diff --git a/src/ledger/NetworkConfig.h b/src/ledger/NetworkConfig.h index 470aa0b5be..f8581ea7c8 100644 --- a/src/ledger/NetworkConfig.h +++ b/src/ledger/NetworkConfig.h @@ -14,8 +14,8 @@ namespace stellar { +class AbstractLedgerStateSnapshot; class Application; -class LedgerSnapshot; // Defines the minimum values allowed for the network configuration // settings during upgrades. An upgrade that does not follow the minimums @@ -261,7 +261,8 @@ class SorobanNetworkConfig { public: // Static factory function to create a SorobanNetworkConfig from ledger - static SorobanNetworkConfig loadFromLedger(LedgerSnapshot const& ls); + static SorobanNetworkConfig + loadFromLedger(AbstractLedgerStateSnapshot const& snap); static SorobanNetworkConfig loadFromLedger(AbstractLedgerTxn& ltx); #ifdef BUILD_TESTS @@ -478,25 +479,25 @@ class SorobanNetworkConfig private: SorobanNetworkConfig() = default; - void loadMaxContractSize(LedgerSnapshot const& ls); - void loadMaxContractDataKeySize(LedgerSnapshot const& ls); - void loadMaxContractDataEntrySize(LedgerSnapshot const& ls); - void loadComputeSettings(LedgerSnapshot const& ls); - void loadLedgerAccessSettings(LedgerSnapshot const& ls); - void loadHistoricalSettings(LedgerSnapshot const& ls); - void loadContractEventsSettings(LedgerSnapshot const& ls); - void loadBandwidthSettings(LedgerSnapshot const& ls); - void loadCpuCostParams(LedgerSnapshot const& ls); - void loadMemCostParams(LedgerSnapshot const& ls); - void loadStateArchivalSettings(LedgerSnapshot const& ls); - void loadExecutionLanesSettings(LedgerSnapshot const& ls); - void loadLiveSorobanStateSizeWindow(LedgerSnapshot const& ls); - void loadEvictionIterator(LedgerSnapshot const& ls); - void loadParallelComputeConfig(LedgerSnapshot const& ls); - void loadLedgerCostExtConfig(LedgerSnapshot const& ls); - void loadSCPTimingConfig(LedgerSnapshot const& ls); - void loadFrozenLedgerKeys(LedgerSnapshot const& ls); - void loadFreezeBypassTxs(LedgerSnapshot const& ls); + void loadMaxContractSize(AbstractLedgerStateSnapshot const& ls); + void loadMaxContractDataKeySize(AbstractLedgerStateSnapshot const& ls); + void loadMaxContractDataEntrySize(AbstractLedgerStateSnapshot const& ls); + void loadComputeSettings(AbstractLedgerStateSnapshot const& ls); + void loadLedgerAccessSettings(AbstractLedgerStateSnapshot const& ls); + void loadHistoricalSettings(AbstractLedgerStateSnapshot const& ls); + void loadContractEventsSettings(AbstractLedgerStateSnapshot const& ls); + void loadBandwidthSettings(AbstractLedgerStateSnapshot const& ls); + void loadCpuCostParams(AbstractLedgerStateSnapshot const& ls); + void loadMemCostParams(AbstractLedgerStateSnapshot const& ls); + void loadStateArchivalSettings(AbstractLedgerStateSnapshot const& ls); + void loadExecutionLanesSettings(AbstractLedgerStateSnapshot const& ls); + void loadLiveSorobanStateSizeWindow(AbstractLedgerStateSnapshot const& ls); + void loadEvictionIterator(AbstractLedgerStateSnapshot const& ls); + void loadParallelComputeConfig(AbstractLedgerStateSnapshot const& ls); + void loadLedgerCostExtConfig(AbstractLedgerStateSnapshot const& ls); + void loadSCPTimingConfig(AbstractLedgerStateSnapshot const& ls); + void loadFrozenLedgerKeys(AbstractLedgerStateSnapshot const& ls); + void loadFreezeBypassTxs(AbstractLedgerStateSnapshot const& ls); void computeRentWriteFee(uint32_t protocolVersion); #ifdef BUILD_TESTS diff --git a/src/main/CommandHandler.cpp b/src/main/CommandHandler.cpp index e4d2cfdf9c..135c22da92 100644 --- a/src/main/CommandHandler.cpp +++ b/src/main/CommandHandler.cpp @@ -641,9 +641,9 @@ CommandHandler::upgrades(std::string const& params, std::string& retStr) decoder::decode_b64(configXdrIter->second, buffer); ConfigUpgradeSetKey key; xdr::xdr_from_opaque(buffer, key); - auto ls = LedgerSnapshot(mApp); + auto lrv = LedgerReadView(mApp); - auto ptr = ConfigUpgradeSetFrame::makeFromKey(ls, key); + auto ptr = ConfigUpgradeSetFrame::makeFromKey(lrv, key); if (!ptr || ptr->isValidForApply() != Upgrades::UpgradeValidity::VALID) @@ -810,9 +810,9 @@ CommandHandler::dumpProposedSettings(std::string const& params, decoder::decode_b64(blob, buffer); ConfigUpgradeSetKey key; xdr::xdr_from_opaque(buffer, key); - auto ls = LedgerSnapshot(mApp); + auto lrv = LedgerReadView(mApp); - auto ptr = ConfigUpgradeSetFrame::makeFromKey(ls, key); + auto ptr = ConfigUpgradeSetFrame::makeFromKey(lrv, key); if (!ptr || ptr->isValidForApply() != Upgrades::UpgradeValidity::VALID) { @@ -1041,12 +1041,12 @@ CommandHandler::sorobanInfo(std::string const& params, std::string& retStr) } else if (format == "detailed") { - LedgerSnapshot lsg(mApp); + LedgerReadView lrv(mApp); xdr::xvector entries; for (auto c : xdr::xdr_traits::enum_values()) { auto entry = - lsg.load(configSettingKey(static_cast(c))); + lrv.load(configSettingKey(static_cast(c))); if (!entry) { continue; @@ -1058,7 +1058,7 @@ CommandHandler::sorobanInfo(std::string const& params, std::string& retStr) } else if (format == "upgrade_xdr") { - LedgerSnapshot lsg(mApp); + LedgerReadView lrv(mApp); ConfigUpgradeSet upgradeSet; for (auto c : xdr::xdr_traits::enum_values()) @@ -1069,7 +1069,7 @@ CommandHandler::sorobanInfo(std::string const& params, std::string& retStr) { continue; } - auto entry = lsg.load(configSettingKey(configSettingID)); + auto entry = lrv.load(configSettingKey(configSettingID)); if (!entry) { continue; @@ -1513,8 +1513,8 @@ CommandHandler::testAcc(std::string const& params, std::string& retStr) key = getAccount(accName->second.c_str()); } - LedgerSnapshot lsg(mApp); - auto acc = lsg.load(accountKey(key.getPublicKey())); + LedgerReadView lrv(mApp); + auto acc = lrv.load(accountKey(key.getPublicKey())); if (acc) { auto const& ae = acc.current().data.account(); diff --git a/src/overlay/Peer.cpp b/src/overlay/Peer.cpp index 439034a9df..4ad1a937f1 100644 --- a/src/overlay/Peer.cpp +++ b/src/overlay/Peer.cpp @@ -72,19 +72,17 @@ populateSignatureCache(AppConnector& app, TransactionFrameBaseConstPtr tx) auto& snapshot = app.getOverlayThreadSnapshot(); app.maybeUpdateLedgerStateSnapshot(snapshot); - LedgerSnapshot ledgerSnapshot(snapshot); + LedgerReadView lrv(snapshot); - // Use ledgerSnapshot to check all transactions in `tx`. We use a lambda to + // Use lrv to check all transactions in `tx`. We use a lambda to // simplify checking of both outer and inner transactions in the case of fee // bumps. - auto const checkTxSignatures = [&ledgerSnapshot]( - TransactionFrameBaseConstPtr tx) { + auto const checkTxSignatures = [&lrv](TransactionFrameBaseConstPtr tx) { auto const& hash = tx->getContentsHash(); auto const& signatures = txbridge::getSignatures(tx->getEnvelope()); SignatureChecker signatureChecker( - ledgerSnapshot.getLedgerHeader().current().ledgerVersion, hash, - signatures); + lrv.getLedgerHeader().current().ledgerVersion, hash, signatures); // Do not report signature cache metrics during background validation. // This allows us to more accurately measure the impact of background @@ -94,8 +92,7 @@ populateSignatureCache(AppConnector& app, TransactionFrameBaseConstPtr tx) // NOTE: Use getFeeSourceID so that this works for both TransactionFrame // and FeeBumpTransactionFrame - auto const sourceAccount = - ledgerSnapshot.getAccount(tx->getFeeSourceID()); + auto const sourceAccount = lrv.getAccount(tx->getFeeSourceID()); if (!sourceAccount) { @@ -116,10 +113,10 @@ populateSignatureCache(AppConnector& app, TransactionFrameBaseConstPtr tx) // Check all transaction signatures tx->checkAllTransactionSignatures( signatureChecker, sourceAccount, - ledgerSnapshot.getLedgerHeader().current().ledgerVersion); + lrv.getLedgerHeader().current().ledgerVersion); // Check all operation signatures. - tx->checkOperationSignatures(signatureChecker, ledgerSnapshot, nullptr); + tx->checkOperationSignatures(signatureChecker, lrv, nullptr); }; checkTxSignatures(tx); diff --git a/src/overlay/test/OverlayTests.cpp b/src/overlay/test/OverlayTests.cpp index ea0d3074d3..52b682fc03 100644 --- a/src/overlay/test/OverlayTests.cpp +++ b/src/overlay/test/OverlayTests.cpp @@ -3419,10 +3419,10 @@ TEST_CASE("populateSignatureCache tests", "[overlay]") REQUIRE(!isValid); // Verify it fails with bad auth, not other reasons - auto ls = LedgerSnapshot(ltx); + auto lrv = LedgerReadView(ltx); auto diagnostics = DiagnosticEventManager::createDisabled(); - auto result = paymentTx->checkValid(app->getAppConnector(), ls, 0, 0, 0, - diagnostics); + auto result = paymentTx->checkValid(app->getAppConnector(), lrv, 0, 0, + 0, diagnostics); REQUIRE(result->getResultCode() == txBAD_AUTH); // We expect a single cache miss at this point from the application of diff --git a/src/simulation/ApplyLoad.cpp b/src/simulation/ApplyLoad.cpp index 57ebbad5c6..3aadf26282 100644 --- a/src/simulation/ApplyLoad.cpp +++ b/src/simulation/ApplyLoad.cpp @@ -16,6 +16,7 @@ #include "ledger/InMemorySorobanState.h" #include "ledger/LedgerManager.h" #include "ledger/LedgerManagerImpl.h" +#include "ledger/LedgerStateSnapshot.h" #include "main/Application.h" #include "main/CommandLine.h" #include "simulation/TxGenerator.h" @@ -889,11 +890,11 @@ ApplyLoad::applyConfigUpgrade(SorobanUpgradeConfig const& upgradeConfig) upgradeBytes, mUpgradeCodeKey, mUpgradeInstanceKey, std::nullopt, resources); { - LedgerSnapshot ls(mApp); + LedgerReadView lrv(mApp); auto diagnostics = DiagnosticEventManager::createForValidation(mApp.getConfig()); - auto validationRes = invokeTx->checkValid(mApp.getAppConnector(), ls, 0, - 0, 0, diagnostics); + auto validationRes = invokeTx->checkValid(mApp.getAppConnector(), lrv, + 0, 0, 0, diagnostics); if (!validationRes->isSuccess()) { if (validationRes->getResultCode() == txSOROBAN_INVALID) @@ -1525,12 +1526,12 @@ ApplyLoad::benchmarkLimitsIteration() stellar::shuffle(std::begin(shuffledAccounts), std::end(shuffledAccounts), getGlobalRandomEngine()); - LedgerSnapshot ls(mApp); + LedgerReadView lrv(mApp); auto appConnector = mApp.getAppConnector(); - auto addTx = [&ls, &appConnector, &txs](TransactionFrameBasePtr tx) { + auto addTx = [&lrv, &appConnector, &txs](TransactionFrameBasePtr tx) { auto diagnostics = DiagnosticEventManager::createDisabled(); - auto res = tx->checkValid(appConnector, ls, 0, 0, 0, diagnostics); + auto res = tx->checkValid(appConnector, lrv, 0, 0, 0, diagnostics); releaseAssert(res && res->isSuccess()); txs.emplace_back(tx); }; @@ -1997,7 +1998,7 @@ ApplyLoad::generateClassicPayments(std::vector& txs, releaseAssert(accounts.size() >= startAccountIdx + config.APPLY_LOAD_CLASSIC_TXS_PER_LEDGER); - LedgerSnapshot ls(mApp); + LedgerReadView lrv(mApp); auto appConnector = mApp.getAppConnector(); auto diagnostics = DiagnosticEventManager::createDisabled(); @@ -2010,7 +2011,7 @@ ApplyLoad::generateClassicPayments(std::vector& txs, auto [_, tx] = mTxGenerator.paymentTransaction( mNumAccounts, 0, lm.getLastClosedLedgerNum() + 1, it->first, 1, std::nullopt); - auto res = tx->checkValid(appConnector, ls, 0, 0, 0, diagnostics); + auto res = tx->checkValid(appConnector, lrv, 0, 0, 0, diagnostics); releaseAssert(res && res->isSuccess()); txs.emplace_back(tx); } @@ -2092,7 +2093,7 @@ ApplyLoad::generateSacPayments(std::vector& txs, txs.push_back(tx.second); } } - LedgerSnapshot ls(mApp); + LedgerReadView lrv(mApp); auto diag = DiagnosticEventManager::createDisabled(); // Validate all the generated transactions. This serves 2 purposes: // - ensure that the tx generator works as expected @@ -2103,7 +2104,7 @@ ApplyLoad::generateSacPayments(std::vector& txs, // more realistic than including it. for (auto const& tx : txs) { - releaseAssert(tx->checkValid(mApp.getAppConnector(), ls, 0, 0, 0, diag) + releaseAssert(tx->checkValid(mApp.getAppConnector(), lrv, 0, 0, 0, diag) ->isSuccess()); } } @@ -2292,11 +2293,11 @@ ApplyLoad::generateTokenTransfers(std::vector& txs, txs.push_back(tx.second); } - LedgerSnapshot ls(mApp); + LedgerReadView lrv(mApp); auto diag = DiagnosticEventManager::createDisabled(); for (auto const& tx : txs) { - releaseAssert(tx->checkValid(mApp.getAppConnector(), ls, 0, 0, 0, diag) + releaseAssert(tx->checkValid(mApp.getAppConnector(), lrv, 0, 0, 0, diag) ->isSuccess()); } } diff --git a/src/simulation/LoadGenerator.cpp b/src/simulation/LoadGenerator.cpp index 4de568f89b..f9e107f9d6 100644 --- a/src/simulation/LoadGenerator.cpp +++ b/src/simulation/LoadGenerator.cpp @@ -1119,16 +1119,16 @@ LoadGenerator::checkSorobanStateSynced(Application& app, } std::vector result; - LedgerSnapshot lsg(mApp); + LedgerReadView lrv(mApp); for (auto const& lk : mContractInstanceKeys) { - if (!lsg.load(lk)) + if (!lrv.load(lk)) { result.emplace_back(lk); } } - if (mCodeKey && !lsg.load(*mCodeKey)) + if (mCodeKey && !lrv.load(*mCodeKey)) { result.emplace_back(*mCodeKey); } diff --git a/src/simulation/TxGenerator.cpp b/src/simulation/TxGenerator.cpp index d4cecd4b20..a5a5abb511 100644 --- a/src/simulation/TxGenerator.cpp +++ b/src/simulation/TxGenerator.cpp @@ -48,11 +48,11 @@ sampleDiscrete(std::vector const& values, uint64_t footprintSize(Application& app, xdr::xvector const& keys) { - LedgerSnapshot lsg(app); + LedgerReadView lrv(app); uint64_t total = 0; for (auto const& key : keys) { - auto entry = lsg.load(key); + auto entry = lrv.load(key); if (entry) { total += xdr::xdr_size(entry.current()); @@ -86,8 +86,8 @@ TxGenerator::updateMinBalance() bool TxGenerator::isLive(LedgerKey const& lk, uint32_t ledgerNum) const { - LedgerSnapshot lsg(mApp); - auto ttlEntryPtr = lsg.load(getTTLKey(lk)); + LedgerReadView lrv(mApp); + auto ttlEntryPtr = lrv.load(getTTLKey(lk)); return ttlEntryPtr && stellar::isLive(ttlEntryPtr.current(), ledgerNum); } @@ -127,8 +127,8 @@ TxGenerator::generateFee(std::optional maxGeneratedFeeRate, bool TxGenerator::loadAccount(TestAccount& account) { - LedgerSnapshot lsg(mApp); - auto const entry = lsg.getAccount(account.getPublicKey()); + LedgerReadView lrv(mApp); + auto const entry = lrv.getAccount(account.getPublicKey()); if (!entry) { return false; @@ -944,7 +944,7 @@ TxGenerator::getConfigUpgradeSetFromLoadConfig( { xdr::xvector updatedEntries; - LedgerSnapshot lsg(mApp); + LedgerReadView lrv(mApp); for (auto t : xdr::xdr_traits::enum_values()) { auto type = static_cast(t); @@ -983,7 +983,7 @@ TxGenerator::getConfigUpgradeSetFromLoadConfig( continue; } - auto entryPtr = lsg.load(configSettingKey(type)); + auto entryPtr = lrv.load(configSettingKey(type)); // This could happen if we have not yet upgraded if ((t == CONFIG_SETTING_CONTRACT_PARALLEL_COMPUTE_V0 || t == CONFIG_SETTING_CONTRACT_LEDGER_COST_EXT_V0 || diff --git a/src/test/FuzzerImpl.cpp b/src/test/FuzzerImpl.cpp index 3b5ab2fd5a..85bbaeff06 100644 --- a/src/test/FuzzerImpl.cpp +++ b/src/test/FuzzerImpl.cpp @@ -936,7 +936,7 @@ class FuzzTransactionFrame : public TransactionFrame // Do not track metrics related to background signature verification in // the fuzzer. signatureChecker.disableCacheMetricsTracking(); - LedgerSnapshot ltxStmt(ltx); + LedgerReadView ltxStmt(ltx); // if any ill-formed Operations, do not attempt transaction application auto isInvalidOperation = [&](auto const& op, auto& opResult) { auto diagnostics = diff --git a/src/test/TestAccount.cpp b/src/test/TestAccount.cpp index 6f225ce4af..22d8472cc4 100644 --- a/src/test/TestAccount.cpp +++ b/src/test/TestAccount.cpp @@ -33,8 +33,8 @@ TestAccount::updateSequenceNumber() { if (mSn == 0) { - LedgerSnapshot lsg(mApp); - auto const entry = lsg.load(accountKey(getPublicKey())); + LedgerReadView lrv(mApp); + auto const entry = lrv.load(accountKey(getPublicKey())); if (entry) { mSn = entry.current().data.account().seqNum; @@ -45,8 +45,8 @@ TestAccount::updateSequenceNumber() uint32_t TestAccount::getTrustlineFlags(Asset const& asset) const { - LedgerSnapshot lsg(mApp); - auto const trust = lsg.load(trustlineKey(getPublicKey(), asset)); + LedgerReadView lrv(mApp); + auto const trust = lrv.load(trustlineKey(getPublicKey(), asset)); REQUIRE(trust); return trust.current().data.trustLine().flags; } @@ -63,10 +63,10 @@ TestAccount::getTrustlineBalance(Asset const& asset) const int64_t TestAccount::getTrustlineBalance(PoolID const& poolID) const { - LedgerSnapshot lsg(mApp); + LedgerReadView lrv(mApp); TrustLineAsset asset(ASSET_TYPE_POOL_SHARE); asset.liquidityPoolID() = poolID; - auto const trustLine = lsg.load(trustlineKey(getPublicKey(), asset)); + auto const trustLine = lrv.load(trustlineKey(getPublicKey(), asset)); REQUIRE(trustLine); return trustLine.current().data.trustLine().balance; } @@ -74,25 +74,25 @@ TestAccount::getTrustlineBalance(PoolID const& poolID) const int64_t TestAccount::getBalance() const { - LedgerSnapshot lsg(mApp); - auto const entry = lsg.getAccount(getPublicKey()); + LedgerReadView lrv(mApp); + auto const entry = lrv.getAccount(getPublicKey()); return entry.current().data.account().balance; } int64_t TestAccount::getAvailableBalance() const { - LedgerSnapshot lsg(mApp); - auto const entry = lsg.getAccount(getPublicKey()); - return stellar::getAvailableBalance(lsg.getLedgerHeader().current(), + LedgerReadView lrv(mApp); + auto const entry = lrv.getAccount(getPublicKey()); + return stellar::getAvailableBalance(lrv.getLedgerHeader().current(), entry.current()); } uint32_t TestAccount::getNumSubEntries() const { - LedgerSnapshot lsg(mApp); - auto const entry = lsg.getAccount(getPublicKey()); + LedgerReadView lrv(mApp); + auto const entry = lrv.getAccount(getPublicKey()); return entry.current().data.account().numSubEntries; } @@ -146,8 +146,8 @@ TestAccount::create(SecretKey const& secretKey, uint64_t initialBalance) std::unique_ptr destBefore; { - LedgerSnapshot lsg(mApp); - auto const entry = lsg.getAccount(publicKey); + LedgerReadView lrv(mApp); + auto const entry = lrv.getAccount(publicKey); if (entry) { destBefore = std::make_unique(entry.current()); @@ -160,8 +160,8 @@ TestAccount::create(SecretKey const& secretKey, uint64_t initialBalance) } catch (...) { - LedgerSnapshot lsg(mApp); - auto const destAfter = lsg.getAccount(publicKey); + LedgerReadView lrv(mApp); + auto const destAfter = lrv.getAccount(publicKey); // check that the target account didn't change REQUIRE(!!destBefore == !!destAfter); if (destBefore && destAfter) @@ -172,8 +172,8 @@ TestAccount::create(SecretKey const& secretKey, uint64_t initialBalance) } { - LedgerSnapshot lsg(mApp); - REQUIRE(lsg.getAccount(publicKey)); + LedgerReadView lrv(mApp); + REQUIRE(lrv.getAccount(publicKey)); } return TestAccount{mApp, secretKey}; } @@ -190,10 +190,10 @@ TestAccount::createBatch(std::vector const& secretKeys, } applyOpsBatch(ops); std::vector accounts; - LedgerSnapshot ls(mApp); + LedgerReadView lrv(mApp); for (auto const& secretKey : secretKeys) { - REQUIRE(ls.getAccount(secretKey.getPublicKey())); + REQUIRE(lrv.getAccount(secretKey.getPublicKey())); accounts.emplace_back(mApp, secretKey); } return accounts; @@ -222,9 +222,9 @@ TestAccount::merge(PublicKey const& into) { applyTx(tx({accountMerge(into)}), mApp); - LedgerSnapshot lsg(mApp); - REQUIRE(lsg.getAccount(into)); - REQUIRE(!lsg.getAccount(getPublicKey())); + LedgerReadView lrv(mApp); + REQUIRE(lrv.getAccount(into)); + REQUIRE(!lrv.getAccount(getPublicKey())); } void @@ -339,11 +339,11 @@ TestAccount::loadTrustLine(Asset const& asset) const TrustLineEntry TestAccount::loadTrustLine(TrustLineAsset const& asset) const { - LedgerSnapshot lsg(mApp); + LedgerReadView lrv(mApp); LedgerKey key(TRUSTLINE); key.trustLine().accountID = getPublicKey(); key.trustLine().asset = asset; - return lsg.load(key).current().data.trustLine(); + return lrv.load(key).current().data.trustLine(); } bool @@ -355,11 +355,11 @@ TestAccount::hasTrustLine(Asset const& asset) const bool TestAccount::hasTrustLine(TrustLineAsset const& asset) const { - LedgerSnapshot lsg(mApp); + LedgerReadView lrv(mApp); LedgerKey key(TRUSTLINE); key.trustLine().accountID = getPublicKey(); key.trustLine().asset = asset; - return static_cast(lsg.load(key)); + return static_cast(lrv.load(key)); } void @@ -373,8 +373,8 @@ TestAccount::manageData(std::string const& name, DataValue* value) { applyTx(tx({txtest::manageData(name, value)}), mApp); - LedgerTxn ls(mApp.getLedgerTxnRoot()); - auto data = stellar::loadData(ls, getPublicKey(), name); + LedgerTxn lrv(mApp.getLedgerTxnRoot()); + auto data = stellar::loadData(lrv, getPublicKey(), name); if (value) { REQUIRE(data); @@ -391,18 +391,18 @@ TestAccount::bumpSequence(SequenceNumber to) { applyTx(tx({txtest::bumpSequence(to)}), mApp, false); - LedgerSnapshot lsg(mApp); - if (protocolVersionStartsFrom(lsg.getLedgerHeader().current().ledgerVersion, + LedgerReadView lrv(mApp); + if (protocolVersionStartsFrom(lrv.getLedgerHeader().current().ledgerVersion, ProtocolVersion::V_19)) { - auto const account = lsg.getAccount(getPublicKey()); + auto const account = lrv.getAccount(getPublicKey()); REQUIRE(account); auto const& v3 = getAccountEntryExtensionV3(account.current().data.account()); - REQUIRE(v3.seqLedger == lsg.getLedgerHeader().current().ledgerSeq); + REQUIRE(v3.seqLedger == lrv.getLedgerHeader().current().ledgerSeq); REQUIRE(v3.seqTime == - lsg.getLedgerHeader().current().scpValue.closeTime); + lrv.getLedgerHeader().current().scpValue.closeTime); } } @@ -502,8 +502,8 @@ TestAccount::pay(PublicKey const& destination, int64_t amount) { std::unique_ptr toAccount; { - LedgerSnapshot lsg(mApp); - auto const toAccountEntry = lsg.getAccount(destination); + LedgerReadView lrv(mApp); + auto const toAccountEntry = lrv.getAccount(destination); toAccount = toAccountEntry ? std::make_unique(toAccountEntry.current()) @@ -514,7 +514,7 @@ TestAccount::pay(PublicKey const& destination, int64_t amount) } else { - REQUIRE(lsg.getAccount(getPublicKey())); + REQUIRE(lrv.getAccount(getPublicKey())); } } @@ -526,8 +526,8 @@ TestAccount::pay(PublicKey const& destination, int64_t amount) } catch (...) { - LedgerSnapshot lsg(mApp); - auto const toAccountAfter = lsg.getAccount(destination); + LedgerReadView lrv(mApp); + auto const toAccountAfter = lrv.getAccount(destination); // check that the target account didn't change REQUIRE(!!toAccount == !!toAccountAfter); if (toAccount && toAccountAfter && @@ -539,8 +539,8 @@ TestAccount::pay(PublicKey const& destination, int64_t amount) throw; } - LedgerSnapshot lsg(mApp); - auto const toAccountAfter = lsg.getAccount(destination); + LedgerReadView lrv(mApp); + auto const toAccountAfter = lrv.getAccount(destination); REQUIRE(toAccount); REQUIRE(toAccountAfter); } diff --git a/src/test/TxTests.cpp b/src/test/TxTests.cpp index 32342ca029..34e331ae80 100644 --- a/src/test/TxTests.cpp +++ b/src/test/TxTests.cpp @@ -711,14 +711,14 @@ loadAccount(AbstractLedgerTxn& ltx, PublicKey const& k, bool mustExist) bool doesAccountExist(Application& app, PublicKey const& k) { - LedgerSnapshot lss(app); + LedgerReadView lss(app); return (bool)lss.getAccount(k); } xdr::xvector getAccountSigners(PublicKey const& k, Application& app) { - LedgerSnapshot lss(app); + LedgerReadView lss(app); auto account = lss.getAccount(k); return account.current().data.account().signers; } @@ -2048,8 +2048,8 @@ makeConfigUpgradeSet(AbstractLedgerTxn& ltx, ConfigUpgradeSet configUpgradeSet, ltx.create(InternalLedgerEntry(ttl)); auto upgradeKey = ConfigUpgradeSetKey{contractID, hashOfUpgradeSet}; - LedgerSnapshot lsg(ltx); - return ConfigUpgradeSetFrame::makeFromKey(lsg, upgradeKey); + LedgerReadView lrv(ltx); + return ConfigUpgradeSetFrame::makeFromKey(lrv, upgradeKey); } LedgerUpgrade diff --git a/src/transactions/FeeBumpTransactionFrame.cpp b/src/transactions/FeeBumpTransactionFrame.cpp index ab80153ab6..02f0647098 100644 --- a/src/transactions/FeeBumpTransactionFrame.cpp +++ b/src/transactions/FeeBumpTransactionFrame.cpp @@ -245,7 +245,7 @@ FeeBumpTransactionFrame::checkSignature(SignatureChecker& signatureChecker, bool FeeBumpTransactionFrame::checkOperationSignatures( - SignatureChecker& signatureChecker, LedgerSnapshot const& ls, + SignatureChecker& signatureChecker, LedgerReadView const& lrv, MutableTransactionResultBase* txResult) const { // Fee bumps do not contain explicit operations, so this check trivially @@ -270,9 +270,10 @@ FeeBumpTransactionFrame::checkAllTransactionSignatures( MutableTxResultPtr FeeBumpTransactionFrame::checkValid( - AppConnector& app, LedgerSnapshot const& ls, SequenceNumber current, + AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, - DiagnosticEventManager& diagnosticEvents) const + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq) const { if (!xdr::check_xdr_depth(mEnvelope, 500) || !XDRProvidesValidFee()) { @@ -283,15 +284,16 @@ FeeBumpTransactionFrame::checkValid( // the fees that would end up being applied. However, this is what Core // used to return for a while, and some users may rely on this, so we // maintain this logic for the time being. - int64_t minBaseFee = ls.getLedgerHeader().current().baseFee; - auto feeCharged = getFee(ls.getLedgerHeader().current(), minBaseFee, false); + int64_t minBaseFee = lrv.getLedgerHeader().current().baseFee; + auto feeCharged = + getFee(lrv.getLedgerHeader().current(), minBaseFee, false); auto txResult = FeeBumpMutableTransactionResult::createSuccess( *mInnerTx, feeCharged, 0); - auto ledgerVersion = ls.getLedgerHeader().current().ledgerVersion; + auto ledgerVersion = lrv.getLedgerHeader().current().ledgerVersion; SignatureChecker signatureChecker{ledgerVersion, getContentsHash(), mEnvelope.feeBump().signatures}; - if (commonValid(signatureChecker, ls, false, *txResult) != + if (commonValid(signatureChecker, lrv, false, *txResult) != ValidationType::kFullyValid) { return txResult; @@ -321,9 +323,9 @@ FeeBumpTransactionFrame::checkValid( } mInnerTx->checkValidWithOptionallyChargedFee( - app, ls, current, false, lowerBoundCloseTimeOffset, + app, lrv, current, false, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, getContentsHash(), *txResult, - diagnosticEvents); + diagnosticEvents, validationLedgerSeq); return txResult; } @@ -339,12 +341,12 @@ FeeBumpTransactionFrame::checkSorobanResources( std::optional FeeBumpTransactionFrame::commonValidPreSeqNum( - LedgerSnapshot const& ls, MutableTransactionResultBase& txResult) const + LedgerReadView const& lrv, MutableTransactionResultBase& txResult) const { // this function does validations that are independent of the account state // (stay true regardless of other side effects) - auto header = ls.getLedgerHeader(); + auto header = lrv.getLedgerHeader(); if (protocolVersionIsBefore(header.current().ledgerVersion, ProtocolVersion::V_13)) { @@ -405,7 +407,7 @@ FeeBumpTransactionFrame::commonValidPreSeqNum( } } - auto feeSource = ls.getAccount(getFeeSourceID()); + auto feeSource = lrv.getAccount(getFeeSourceID()); if (!feeSource) { txResult.setError(txNO_ACCOUNT); @@ -417,14 +419,14 @@ FeeBumpTransactionFrame::commonValidPreSeqNum( FeeBumpTransactionFrame::ValidationType FeeBumpTransactionFrame::commonValid( - SignatureChecker& signatureChecker, LedgerSnapshot const& ls, bool applying, - MutableTransactionResultBase& txResult) const + SignatureChecker& signatureChecker, LedgerReadView const& lrv, + bool applying, MutableTransactionResultBase& txResult) const { ValidationType res = ValidationType::kInvalid; // Get the fee source account during commonValidPreSeqNum to avoid redundant // account loading - auto feeSource = commonValidPreSeqNum(ls, txResult); + auto feeSource = commonValidPreSeqNum(lrv, txResult); if (!feeSource) { return res; @@ -432,7 +434,7 @@ FeeBumpTransactionFrame::commonValid( if (!checkAllTransactionSignatures( signatureChecker, *feeSource, - ls.getLedgerHeader().current().ledgerVersion)) + lrv.getLedgerHeader().current().ledgerVersion)) { txResult.setError(txBAD_AUTH); return res; @@ -440,7 +442,7 @@ FeeBumpTransactionFrame::commonValid( res = ValidationType::kInvalidPostAuth; - auto header = ls.getLedgerHeader(); + auto header = lrv.getLedgerHeader(); // if we are in applying mode fee was already deduced from signing account // balance, if not, we need to check if after that deduction this account // will still have minimum balance diff --git a/src/transactions/FeeBumpTransactionFrame.h b/src/transactions/FeeBumpTransactionFrame.h index 77596327ff..d71cd7834f 100644 --- a/src/transactions/FeeBumpTransactionFrame.h +++ b/src/transactions/FeeBumpTransactionFrame.h @@ -34,7 +34,7 @@ class FeeBumpTransactionFrame : public TransactionFrameBase int32_t neededWeight) const override; bool checkOperationSignatures( - SignatureChecker& signatureChecker, LedgerSnapshot const& ls, + SignatureChecker& signatureChecker, LedgerReadView const& lrv, MutableTransactionResultBase* txResult) const override; bool checkAllTransactionSignatures(SignatureChecker& signatureChecker, @@ -44,7 +44,7 @@ class FeeBumpTransactionFrame : public TransactionFrameBase // If check passes, returns the fee source account. Otherwise returns // nullopt. std::optional - commonValidPreSeqNum(LedgerSnapshot const& ls, + commonValidPreSeqNum(LedgerReadView const& lrv, MutableTransactionResultBase& txResult) const; enum ValidationType @@ -56,7 +56,7 @@ class FeeBumpTransactionFrame : public TransactionFrameBase }; ValidationType commonValid(SignatureChecker& signatureChecker, - LedgerSnapshot const& ls, bool applying, + LedgerReadView const& lrv, bool applying, MutableTransactionResultBase& txResult) const; void removeOneTimeSignerKeyFromFeeSource(AbstractLedgerTxn& ltx) const; @@ -109,11 +109,13 @@ class FeeBumpTransactionFrame : public TransactionFrameBase MutableTransactionResultBase& txResult, TxEventManager& txEventManager) const override; - MutableTxResultPtr - checkValid(AppConnector& app, LedgerSnapshot const& ls, - SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset, - DiagnosticEventManager& diagnosticEvents) const override; + MutableTxResultPtr checkValid(AppConnector& app, LedgerReadView const& lrv, + SequenceNumber current, + uint64_t lowerBoundCloseTimeOffset, + uint64_t upperBoundCloseTimeOffset, + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq = + std::nullopt) const override; bool checkSorobanResources( SorobanNetworkConfig const& cfg, uint32_t ledgerVersion, DiagnosticEventManager& diagnosticEvents) const override; diff --git a/src/transactions/OperationFrame.cpp b/src/transactions/OperationFrame.cpp index ccd8448165..a6e762bee6 100644 --- a/src/transactions/OperationFrame.cpp +++ b/src/transactions/OperationFrame.cpp @@ -148,7 +148,7 @@ OperationFrame::apply( ZoneScoped; CLOG_TRACE(Tx, "{}", xdrToCerealString(mOperation, "Operation")); - LedgerSnapshot ltxState(ltx); + LedgerReadView ltxState(ltx); bool applyRes = checkValid( app, signatureChecker, sorobanConfig ? &sorobanConfig.value() : nullptr, ltxState, true, res, opMeta.getDiagnosticEventManager()); @@ -215,12 +215,12 @@ OperationFrame::isOpSupported(LedgerHeader const&) const bool OperationFrame::checkSignature(SignatureChecker& signatureChecker, - LedgerSnapshot const& ls, OperationResult* res, + LedgerReadView const& lrv, OperationResult* res, bool forApply) const { ZoneScoped; - auto header = ls.getLedgerHeader(); - auto sourceAccount = ls.getAccount(header, mParentTx, getSourceID()); + auto header = lrv.getLedgerHeader(); + auto sourceAccount = lrv.getAccount(header, mParentTx, getSourceID()); if (sourceAccount) { auto neededThreshold = @@ -282,7 +282,7 @@ bool OperationFrame::checkValid(AppConnector& app, SignatureChecker& signatureChecker, SorobanNetworkConfig const* cfg, - LedgerSnapshot const& ls, bool forApply, + LedgerReadView const& lrv, bool forApply, OperationResult& res, DiagnosticEventManager& diagnosticEvents) const { @@ -290,19 +290,19 @@ OperationFrame::checkValid(AppConnector& app, bool validationResult = false; auto validate = [this, &res, forApply, &signatureChecker, &app, &diagnosticEvents, &validationResult, - &cfg](LedgerSnapshot const& ls) { - if (!isOpSupported(ls.getLedgerHeader().current())) + &cfg](LedgerReadView const& lrv) { + if (!isOpSupported(lrv.getLedgerHeader().current())) { res.code(opNOT_SUPPORTED); validationResult = false; return; } - auto ledgerVersion = ls.getLedgerHeader().current().ledgerVersion; + auto ledgerVersion = lrv.getLedgerHeader().current().ledgerVersion; if (!forApply || protocolVersionIsBefore(ledgerVersion, ProtocolVersion::V_10)) { - if (!checkSignature(signatureChecker, ls, &res, forApply)) + if (!checkSignature(signatureChecker, lrv, &res, forApply)) { validationResult = false; return; @@ -319,7 +319,8 @@ OperationFrame::checkValid(AppConnector& app, // If we're applying, it's possible an earlier op modified the TX // source, so we need to check again. if ((mOperation.sourceAccount || forApply) && - !ls.getAccount(ls.getLedgerHeader(), mParentTx, getSourceID())) + !lrv.getAccount(lrv.getLedgerHeader(), mParentTx, + getSourceID())) { res.code(opNO_ACCOUNT); validationResult = false; @@ -343,16 +344,16 @@ OperationFrame::checkValid(AppConnector& app, // Older protocol versions contain buggy account loading code, // so preserve nested LedgerTxn to avoid writing to the ledger - if (protocolVersionIsBefore(ls.getLedgerHeader().current().ledgerVersion, + if (protocolVersionIsBefore(lrv.getLedgerHeader().current().ledgerVersion, ProtocolVersion::V_8) && forApply) { - ls.executeWithMaybeInnerSnapshot(validate); + lrv.executeWithMaybeInnerSnapshot(validate); } else { // Validate using read-only snapshot - validate(ls); + validate(lrv); } return validationResult; diff --git a/src/transactions/OperationFrame.h b/src/transactions/OperationFrame.h index 709b96daf1..c6747cc503 100644 --- a/src/transactions/OperationFrame.h +++ b/src/transactions/OperationFrame.h @@ -97,14 +97,14 @@ class OperationFrame // to `nullptr` if they do not directly need the result of signature // validation (such as in the case of background signature validation). bool checkSignature(SignatureChecker& signatureChecker, - LedgerSnapshot const& ls, OperationResult* res, + LedgerReadView const& lrv, OperationResult* res, bool forApply) const; AccountID getSourceID() const; MuxedAccount getSourceAccount() const; bool checkValid(AppConnector& app, SignatureChecker& signatureChecker, - SorobanNetworkConfig const* cfg, LedgerSnapshot const& ls, + SorobanNetworkConfig const* cfg, LedgerReadView const& lrv, bool forApply, OperationResult& res, DiagnosticEventManager& diagnosticEvents) const; diff --git a/src/transactions/TransactionFrame.cpp b/src/transactions/TransactionFrame.cpp index 45ce0ec6c9..539bcbee00 100644 --- a/src/transactions/TransactionFrame.cpp +++ b/src/transactions/TransactionFrame.cpp @@ -553,7 +553,7 @@ TransactionFrame::checkExtraSigners(SignatureChecker& signatureChecker) const bool TransactionFrame::checkOperationSignatures( - SignatureChecker& signatureChecker, LedgerSnapshot const& ls, + SignatureChecker& signatureChecker, LedgerReadView const& lrv, MutableTransactionResultBase* txResult) const { ZoneScoped; @@ -562,7 +562,7 @@ TransactionFrame::checkOperationSignatures( { auto const& op = mOperations[i]; auto opResult = txResult ? &txResult->getOpResultAt(i) : nullptr; - if (!op->checkSignature(signatureChecker, ls, opResult, false)) + if (!op->checkSignature(signatureChecker, lrv, opResult, false)) { allOpsValid = false; } @@ -1219,13 +1219,13 @@ TransactionFrame::computePreApplySorobanResourceFee( } bool -TransactionFrame::isTooEarly(LedgerHeaderWrapper const& header, +TransactionFrame::isTooEarly(uint32_t ledgerVersion, uint64_t closeTime, + uint32_t ledgerSeq, uint64_t lowerBoundCloseTimeOffset) const { auto const tb = getTimeBounds(); if (tb) { - uint64 closeTime = header.current().scpValue.closeTime; if (tb->minTime && (tb->minTime > (closeTime + lowerBoundCloseTimeOffset))) { @@ -1233,18 +1233,18 @@ TransactionFrame::isTooEarly(LedgerHeaderWrapper const& header, } } - if (protocolVersionStartsFrom(header.current().ledgerVersion, - ProtocolVersion::V_19)) + if (protocolVersionStartsFrom(ledgerVersion, ProtocolVersion::V_19)) { auto const lb = getLedgerBounds(); - return lb && lb->minLedger > header.current().ledgerSeq; + return lb && lb->minLedger > ledgerSeq; } return false; } bool -TransactionFrame::isTooLate(LedgerHeaderWrapper const& header, +TransactionFrame::isTooLate(uint32_t ledgerVersion, uint64_t closeTime, + uint32_t ledgerSeq, uint64_t upperBoundCloseTimeOffset) const { auto const tb = getTimeBounds(); @@ -1253,7 +1253,6 @@ TransactionFrame::isTooLate(LedgerHeaderWrapper const& header, // Prior to consensus, we can pass in an upper bound estimate on when we // expect the ledger to close so we don't accept transactions that will // expire by the time they are applied - uint64 closeTime = header.current().scpValue.closeTime; if (tb->maxTime && (tb->maxTime < (closeTime + upperBoundCloseTimeOffset))) { @@ -1261,23 +1260,21 @@ TransactionFrame::isTooLate(LedgerHeaderWrapper const& header, } } - if (protocolVersionStartsFrom(header.current().ledgerVersion, - ProtocolVersion::V_19)) + if (protocolVersionStartsFrom(ledgerVersion, ProtocolVersion::V_19)) { auto const lb = getLedgerBounds(); - return lb && lb->maxLedger != 0 && - lb->maxLedger <= header.current().ledgerSeq; + return lb && lb->maxLedger != 0 && lb->maxLedger <= ledgerSeq; } return false; } bool -TransactionFrame::isTooEarlyForAccount(LedgerHeaderWrapper const& header, +TransactionFrame::isTooEarlyForAccount(uint32_t ledgerVersion, + uint64_t closeTime, uint32_t ledgerSeq, LedgerEntryWrapper const& sourceAccount, uint64_t lowerBoundCloseTimeOffset) const { - if (protocolVersionIsBefore(header.current().ledgerVersion, - ProtocolVersion::V_19)) + if (protocolVersionIsBefore(ledgerVersion, ProtocolVersion::V_19)) { return false; } @@ -1291,8 +1288,7 @@ TransactionFrame::isTooEarlyForAccount(LedgerHeaderWrapper const& header, : 0; auto minSeqAge = getMinSeqAge(); - auto lowerBoundCloseTime = - header.current().scpValue.closeTime + lowerBoundCloseTimeOffset; + auto lowerBoundCloseTime = closeTime + lowerBoundCloseTimeOffset; if (minSeqAge > lowerBoundCloseTime || lowerBoundCloseTime - minSeqAge < accSeqTime) { @@ -1305,7 +1301,6 @@ TransactionFrame::isTooEarlyForAccount(LedgerHeaderWrapper const& header, : 0; auto minSeqLedgerGap = getMinSeqLedgerGap(); - auto ledgerSeq = header.current().ledgerSeq; if (minSeqLedgerGap > ledgerSeq || ledgerSeq - minSeqLedgerGap < accSeqLedger) { @@ -1318,17 +1313,18 @@ TransactionFrame::isTooEarlyForAccount(LedgerHeaderWrapper const& header, std::optional TransactionFrame::commonValidPreSeqNum( AppConnector& app, SorobanNetworkConfig const* cfg, - LedgerSnapshot const& ls, bool chargeFee, + LedgerReadView const& lrv, bool chargeFee, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, Hash const& envelopeContentsHash, std::optional sorobanResourceFee, MutableTransactionResultBase& txResult, - DiagnosticEventManager& diagnosticEvents) const + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq) const { ZoneScoped; // this function does validations that are independent of the account state // (stay true regardless of other side effects) - uint32_t ledgerVersion = ls.getLedgerHeader().current().ledgerVersion; + uint32_t ledgerVersion = lrv.getLedgerHeader().current().ledgerVersion; if ((protocolVersionIsBefore(ledgerVersion, ProtocolVersion::V_13) && (mEnvelope.type() == ENVELOPE_TYPE_TX || hasMuxedAccount(mEnvelope))) || @@ -1389,7 +1385,7 @@ TransactionFrame::commonValidPreSeqNum( } if (protocolVersionStartsFrom( - ls.getLedgerHeader().current().ledgerVersion, + lrv.getLedgerHeader().current().ledgerVersion, ProtocolVersion::V_25)) { if (!validateSorobanMemo()) @@ -1512,13 +1508,22 @@ TransactionFrame::commonValidPreSeqNum( } } - auto header = ls.getLedgerHeader(); - if (isTooEarly(header, lowerBoundCloseTimeOffset)) + auto header = lrv.getLedgerHeader(); + + // If we have an overriding ledger sequence for validation (like when tx + // queue is accepting TXs for the next ledger), use that for time-based + // checks instead of the ledgerSeq from the header. + auto ledgerSeq = validationLedgerSeq.value_or(header.current().ledgerSeq); + auto closeTime = header.current().scpValue.closeTime; + + if (isTooEarly(ledgerVersion, closeTime, ledgerSeq, + lowerBoundCloseTimeOffset)) { txResult.setInnermostError(txTOO_EARLY); return std::nullopt; } - if (isTooLate(header, upperBoundCloseTimeOffset)) + if (isTooLate(ledgerVersion, closeTime, ledgerSeq, + upperBoundCloseTimeOffset)) { txResult.setInnermostError(txTOO_LATE); return std::nullopt; @@ -1537,7 +1542,7 @@ TransactionFrame::commonValidPreSeqNum( return std::nullopt; } - auto sourceAccount = ls.getAccount(header, *this); + auto sourceAccount = lrv.getAccount(header, *this); if (!sourceAccount) { txResult.setInnermostError(txNO_ACCOUNT); @@ -1614,8 +1619,9 @@ TransactionFrame::processSignatures( if (auto code = txResult.getInnermostResultCode(); code == txSUCCESS || code == txFAILED) { - LedgerSnapshot ls(ltxOuter); - allOpsValid = checkOperationSignatures(signatureChecker, ls, &txResult); + LedgerReadView lrv(ltxOuter); + allOpsValid = + checkOperationSignatures(signatureChecker, lrv, &txResult); } removeOneTimeSignerFromAllSourceAccounts(ltxOuter); @@ -1665,12 +1671,13 @@ TransactionFrame::isBadSeq(LedgerHeaderWrapper const& header, TransactionFrame::ValidationType TransactionFrame::commonValid( AppConnector& app, SorobanNetworkConfig const* cfg, - SignatureChecker& signatureChecker, LedgerSnapshot const& ls, + SignatureChecker& signatureChecker, LedgerReadView const& lrv, SequenceNumber current, bool applying, bool chargeFee, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, Hash const& envelopeContentsHash, std::optional sorobanResourceFee, MutableTransactionResultBase& txResult, - DiagnosticEventManager& diagnosticEvents) const + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq) const { ZoneScoped; ValidationType res = ValidationType::kInvalid; @@ -1679,7 +1686,8 @@ TransactionFrame::commonValid( lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, &app, chargeFee, sorobanResourceFee, &txResult, &diagnosticEvents, ¤t, &res, &cfg, - &envelopeContentsHash](LedgerSnapshot const& ls) { + &envelopeContentsHash, + validationLedgerSeq](LedgerReadView const& lrv) { if (applying && (lowerBoundCloseTimeOffset != 0 || upperBoundCloseTimeOffset != 0)) { @@ -1690,16 +1698,16 @@ TransactionFrame::commonValid( // Get the source account during commonValidPreSeqNum to avoid // redundant account loading auto sourceAccount = commonValidPreSeqNum( - app, cfg, ls, chargeFee, lowerBoundCloseTimeOffset, + app, cfg, lrv, chargeFee, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, envelopeContentsHash, sorobanResourceFee, - txResult, diagnosticEvents); + txResult, diagnosticEvents, validationLedgerSeq); if (!sourceAccount) { return; } - auto header = ls.getLedgerHeader(); + auto header = lrv.getLedgerHeader(); // in older versions, the account's sequence number is updated when // taking fees @@ -1720,7 +1728,11 @@ TransactionFrame::commonValid( res = ValidationType::kInvalidUpdateSeqNum; - if (isTooEarlyForAccount(header, *sourceAccount, + auto ledgerSeq = + validationLedgerSeq.value_or(header.current().ledgerSeq); + auto closeTime = header.current().scpValue.closeTime; + if (isTooEarlyForAccount(header.current().ledgerVersion, closeTime, + ledgerSeq, *sourceAccount, lowerBoundCloseTimeOffset)) { txResult.setInnermostError(txBAD_MIN_SEQ_AGE_OR_GAP); @@ -1759,16 +1771,16 @@ TransactionFrame::commonValid( // Older protocol versions contain buggy account loading code, // so preserve nested LedgerTxn to avoid writing to the ledger - if (protocolVersionIsBefore(ls.getLedgerHeader().current().ledgerVersion, + if (protocolVersionIsBefore(lrv.getLedgerHeader().current().ledgerVersion, ProtocolVersion::V_8) && applying) { - ls.executeWithMaybeInnerSnapshot(validate); + lrv.executeWithMaybeInnerSnapshot(validate); } else { // Validate using read-only snapshot - validate(ls); + validate(lrv); } return res; } @@ -1892,22 +1904,23 @@ TransactionFrame::removeAccountSigner(AbstractLedgerTxn& ltxOuter, void TransactionFrame::checkValidWithOptionallyChargedFee( - AppConnector& app, LedgerSnapshot const& ls, SequenceNumber current, + AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, bool chargeFee, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, Hash const& envelopeContentsHash, MutableTransactionResultBase& txResult, - DiagnosticEventManager& diagnosticEvents) const + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq) const { ZoneScoped; mCachedAccountPreProtocol8.reset(); SignatureChecker signatureChecker{ - ls.getLedgerHeader().current().ledgerVersion, getContentsHash(), + lrv.getLedgerHeader().current().ledgerVersion, getContentsHash(), getSignatures(mEnvelope)}; std::optional sorobanResourceFee; SorobanNetworkConfig const* sorobanConfig = nullptr; - auto ledgerVersion = ls.getLedgerHeader().current().ledgerVersion; + auto ledgerVersion = lrv.getLedgerHeader().current().ledgerVersion; // Load sorobanConfig for all transactions at protocol >= V20. if (protocolVersionStartsFrom(ledgerVersion, SOROBAN_PROTOCOL_VERSION)) { @@ -1919,11 +1932,11 @@ TransactionFrame::checkValidWithOptionallyChargedFee( ledgerVersion, *sorobanConfig, app.getConfig()); } } - if (commonValid(app, sorobanConfig, signatureChecker, ls, current, false, + if (commonValid(app, sorobanConfig, signatureChecker, lrv, current, false, chargeFee, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, envelopeContentsHash, - sorobanResourceFee, txResult, - diagnosticEvents) != ValidationType::kMaybeValid) + sorobanResourceFee, txResult, diagnosticEvents, + validationLedgerSeq) != ValidationType::kMaybeValid) { return; } @@ -1933,7 +1946,7 @@ TransactionFrame::checkValidWithOptionallyChargedFee( auto const& op = mOperations[i]; auto& opResult = txResult.getOpResultAt(i); - if (!op->checkValid(app, signatureChecker, sorobanConfig, ls, false, + if (!op->checkValid(app, signatureChecker, sorobanConfig, lrv, false, opResult, diagnosticEvents)) { // it's OK to just fast fail here and not try to call @@ -1951,11 +1964,12 @@ TransactionFrame::checkValidWithOptionallyChargedFee( } MutableTxResultPtr -TransactionFrame::checkValid(AppConnector& app, LedgerSnapshot const& ls, +TransactionFrame::checkValid(AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, - DiagnosticEventManager& diagnosticEvents) const + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq) const { #ifdef BUILD_TESTS if (app.getRunInOverlayOnlyMode()) @@ -1982,13 +1996,14 @@ TransactionFrame::checkValid(AppConnector& app, LedgerSnapshot const& ls, // aren't the fees that would end up being applied. However, this is // what Core used to return for a while, and some users may rely on // this, so we maintain this logic for the time being. - int64_t minBaseFee = ls.getLedgerHeader().current().baseFee; - auto feeCharged = getFee(ls.getLedgerHeader().current(), minBaseFee, false); + int64_t minBaseFee = lrv.getLedgerHeader().current().baseFee; + auto feeCharged = + getFee(lrv.getLedgerHeader().current(), minBaseFee, false); auto txResult = MutableTransactionResult::createSuccess(*this, feeCharged); checkValidWithOptionallyChargedFee( - app, ls, current, true, lowerBoundCloseTimeOffset, + app, lrv, current, true, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, getContentsHash(), *txResult, - diagnosticEvents); + diagnosticEvents, validationLedgerSeq); return txResult; } @@ -2085,12 +2100,16 @@ TransactionFrame::commonPreApply(bool chargeFee, AppConnector& app, sorobanResourceFee->non_refundable_fee; txResult.initializeRefundableFeeTracker(initialFeeRefund); } + + // Pass in nullopt, we always use the header ledgerSeq in the apply path for + // validation. LedgerTxn ltxTx(ltx); - LedgerSnapshot lsTx(ltxTx); + LedgerReadView lsTx(ltxTx); auto cv = commonValid(app, sorobanConfig, *signatureChecker, lsTx, 0, true, chargeFee, 0, 0, envelopeContentsHash, sorobanResourceFee, - txResult, meta.getDiagnosticEventManager()); + txResult, meta.getDiagnosticEventManager(), + /*validationLedgerSeq=*/std::nullopt); if (cv >= ValidationType::kInvalidUpdateSeqNum) { processSeqNum(ltxTx); diff --git a/src/transactions/TransactionFrame.h b/src/transactions/TransactionFrame.h index b73b70cfa5..771ffb42a4 100644 --- a/src/transactions/TransactionFrame.h +++ b/src/transactions/TransactionFrame.h @@ -88,40 +88,44 @@ class TransactionFrame : public TransactionFrameBase kMaybeValid }; - virtual bool isTooEarly(LedgerHeaderWrapper const& header, + virtual bool isTooEarly(uint32_t ledgerVersion, uint64_t closeTime, + uint32_t ledgerSeq, uint64_t lowerBoundCloseTimeOffset) const; - virtual bool isTooLate(LedgerHeaderWrapper const& header, + virtual bool isTooLate(uint32_t ledgerVersion, uint64_t closeTime, + uint32_t ledgerSeq, uint64_t upperBoundCloseTimeOffset) const; - bool isTooEarlyForAccount(LedgerHeaderWrapper const& header, + bool isTooEarlyForAccount(uint32_t ledgerVersion, uint64_t closeTime, + uint32_t ledgerSeq, LedgerEntryWrapper const& sourceAccount, uint64_t lowerBoundCloseTimeOffset) const; // If check passes, returns the source account. Otherwise returns nullopt. std::optional commonValidPreSeqNum(AppConnector& app, SorobanNetworkConfig const* cfg, - LedgerSnapshot const& ls, bool chargeFee, + LedgerReadView const& lrv, bool chargeFee, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, Hash const& envelopeContentsHash, std::optional sorobanResourceFee, MutableTransactionResultBase& txResult, - DiagnosticEventManager& diagnosticEvents) const; + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq) const; virtual bool isBadSeq(LedgerHeaderWrapper const& header, int64_t seqNum) const; - ValidationType commonValid(AppConnector& app, - SorobanNetworkConfig const* cfg, - SignatureChecker& signatureChecker, - LedgerSnapshot const& ls, SequenceNumber current, - bool applying, bool chargeFee, - uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset, - Hash const& envelopeContentsHash, - std::optional sorobanResourceFee, - MutableTransactionResultBase& txResult, - DiagnosticEventManager& diagnosticEvents) const; + ValidationType + commonValid(AppConnector& app, SorobanNetworkConfig const* cfg, + SignatureChecker& signatureChecker, LedgerReadView const& lrv, + SequenceNumber current, bool applying, bool chargeFee, + uint64_t lowerBoundCloseTimeOffset, + uint64_t upperBoundCloseTimeOffset, + Hash const& envelopeContentsHash, + std::optional sorobanResourceFee, + MutableTransactionResultBase& txResult, + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq) const; void removeOneTimeSignerFromAllSourceAccounts(AbstractLedgerTxn& ltx) const; @@ -236,20 +240,23 @@ class TransactionFrame : public TransactionFrameBase uint32_t ledgerVersion) const override; bool checkOperationSignatures( - SignatureChecker& signatureChecker, LedgerSnapshot const& ls, + SignatureChecker& signatureChecker, LedgerReadView const& lrv, MutableTransactionResultBase* txResult) const override; void checkValidWithOptionallyChargedFee( - AppConnector& app, LedgerSnapshot const& ls, SequenceNumber current, + AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, bool chargeFee, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, Hash const& envelopeContentsHash, MutableTransactionResultBase& result, - DiagnosticEventManager& diagnosticEvents) const; - MutableTxResultPtr - checkValid(AppConnector& app, LedgerSnapshot const& ls, - SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset, - DiagnosticEventManager& diagnosticEvents) const override; + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq = std::nullopt) const; + MutableTxResultPtr checkValid(AppConnector& app, LedgerReadView const& lrv, + SequenceNumber current, + uint64_t lowerBoundCloseTimeOffset, + uint64_t upperBoundCloseTimeOffset, + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq = + std::nullopt) const override; bool checkSorobanResources( SorobanNetworkConfig const& cfg, uint32_t ledgerVersion, DiagnosticEventManager& diagnosticEvents) const override; diff --git a/src/transactions/TransactionFrameBase.h b/src/transactions/TransactionFrameBase.h index f12f3db2c6..fc5f422b20 100644 --- a/src/transactions/TransactionFrameBase.h +++ b/src/transactions/TransactionFrameBase.h @@ -172,11 +172,16 @@ class TransactionFrameBase SorobanMetrics& sorobanMetrics, Hash const& sorobanBasePrngSeed, TxEffects& effects) const = 0; - virtual MutableTxResultPtr - checkValid(AppConnector& app, LedgerSnapshot const& ls, - SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset, - DiagnosticEventManager& diagnosticEvents) const = 0; + // When validationLedgerSeq is set, ledger sequence precondition + // checks use this value instead of the + // ledgerSeq from the snapshot header. This is used for pre-consensus + // validation where the snapshot reflects LCL but checks must evaluate + // against the next ledger. + virtual MutableTxResultPtr checkValid( + AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, + uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq = std::nullopt) const = 0; virtual bool checkSorobanResources(SorobanNetworkConfig const& cfg, uint32_t ledgerVersion, @@ -198,7 +203,7 @@ class TransactionFrameBase // populating signature cache in the background). virtual bool checkOperationSignatures(SignatureChecker& signatureChecker, - LedgerSnapshot const& ls, + LedgerReadView const& lrv, MutableTransactionResultBase* txResult) const = 0; // Validate all transaction-level signatures diff --git a/src/transactions/test/FrozenLedgerKeysTests.cpp b/src/transactions/test/FrozenLedgerKeysTests.cpp index b1d7773cb0..ebd67c0112 100644 --- a/src/transactions/test/FrozenLedgerKeysTests.cpp +++ b/src/transactions/test/FrozenLedgerKeysTests.cpp @@ -97,9 +97,9 @@ bypassAndUnbypassTxHashes(Application& app, std::vector const& toBypass, UnorderedSet loadFrozenKeysFromLedger(Application& app) { - LedgerSnapshot ls(app); + LedgerReadView lrv(app); auto configKey = configSettingKey(CONFIG_SETTING_FROZEN_LEDGER_KEYS); - auto entry = ls.load(configKey); + auto entry = lrv.load(configKey); REQUIRE(entry); auto const& frozenKeys = @@ -122,9 +122,9 @@ loadFrozenKeysFromLedger(Application& app) UnorderedSet loadFreezeBypassTxsFromLedger(Application& app) { - LedgerSnapshot ls(app); + LedgerReadView lrv(app); auto configKey = configSettingKey(CONFIG_SETTING_FREEZE_BYPASS_TXS); - auto entry = ls.load(configKey); + auto entry = lrv.load(configKey); REQUIRE(entry); auto const& bypassTxs = @@ -152,9 +152,9 @@ TEST_CASE("frozen ledger keys config setting does not exist prior to p26", static_cast(ProtocolVersion::V_25); auto app = createTestApplication(clock, cfg); auto root = app->getRoot(); - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); auto configKey = configSettingKey(CONFIG_SETTING_FROZEN_LEDGER_KEYS); - auto entry = ls.load(configKey); + auto entry = lrv.load(configKey); REQUIRE(!entry); } @@ -168,9 +168,9 @@ TEST_CASE("freeze bypass txs config setting does not exist prior to p26", static_cast(ProtocolVersion::V_25); auto app = createTestApplication(clock, cfg); auto root = app->getRoot(); - LedgerSnapshot ls(*app); + LedgerReadView lrv(*app); auto configKey = configSettingKey(CONFIG_SETTING_FREEZE_BYPASS_TXS); - auto entry = ls.load(configKey); + auto entry = lrv.load(configKey); REQUIRE(!entry); } @@ -539,8 +539,8 @@ TEST_CASE("freeze bypass tx hash allows frozen key access at validation time", auto checkFrozen = [&](TransactionTestFramePtr& tx, bool expectInnerFrozenResult) { - LedgerSnapshot ls(*app); - auto result = tx->checkValid(app->getAppConnector(), ls, 0, 0, 0); + LedgerReadView lrv(*app); + auto result = tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0); REQUIRE(!result->isSuccess()); if (expectInnerFrozenResult) { @@ -556,8 +556,8 @@ TEST_CASE("freeze bypass tx hash allows frozen key access at validation time", }; auto checkValid = [&](TransactionTestFramePtr& tx) { - LedgerSnapshot ls(*app); - auto result = tx->checkValid(app->getAppConnector(), ls, 0, 0, 0); + LedgerReadView lrv(*app); + auto result = tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0); REQUIRE(result->isSuccess()); }; @@ -709,8 +709,8 @@ TEST_CASE("frozen ledger keys in Soroban footprint", auto tx = createUploadWasmTx(*app, a1, 1000, DEFAULT_TEST_RESOURCE_FEE, resources); - LedgerSnapshot ls(*app); - auto result = tx->checkValid(app->getAppConnector(), ls, 0, 0, 0); + LedgerReadView lrv(*app); + auto result = tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0); REQUIRE(!result->isSuccess()); REQUIRE(result->getResultCode() == txFROZEN_KEY_ACCESSED); @@ -732,8 +732,8 @@ TEST_CASE("source account frozen", "[frozenledgerkeys][tx]") root->create("A2", lm.getLastMinBalance(10) + 10 * lm.getLastTxFee()); auto checkTx = [&](TransactionTestFramePtr& tx) { - LedgerSnapshot ls(*app); - auto result = tx->checkValid(app->getAppConnector(), ls, 0, 0, 0); + LedgerReadView lrv(*app); + auto result = tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0); REQUIRE(!result->isSuccess()); REQUIRE(result->getResultCode() == txFROZEN_KEY_ACCESSED); }; @@ -867,8 +867,8 @@ TEST_CASE("source account frozen", "[frozenledgerkeys][tx]") unfreezeKey(*app, a1Key); - LedgerSnapshot ls(*app); - auto result = tx->checkValid(app->getAppConnector(), ls, 0, 0, 0); + LedgerReadView lrv(*app); + auto result = tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0); REQUIRE(result->isSuccess()); } } @@ -903,8 +903,8 @@ TEST_CASE("source trustline frozen", "[frozenledgerkeys][tx]") auto checkAccessesFrozenKey = [&](Operation const& op) { auto tx = transactionFromOperations(*app, a1.getSecretKey(), a1.nextSequenceNumber(), {op}); - LedgerSnapshot ls(*app); - auto result = tx->checkValid(app->getAppConnector(), ls, 0, 0, 0); + LedgerReadView lrv(*app); + auto result = tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0); REQUIRE(!result->isSuccess()); REQUIRE(result->getResultCode() == txFROZEN_KEY_ACCESSED); }; @@ -1018,8 +1018,8 @@ TEST_CASE("operation destination frozen", "[frozenledgerkeys][tx]") auto tx = transactionFromOperations(*app, sourceAccount.getSecretKey(), sourceAccount.nextSequenceNumber(), {op}); - LedgerSnapshot ls(*app); - auto result = tx->checkValid(app->getAppConnector(), ls, 0, 0, 0); + LedgerReadView lrv(*app); + auto result = tx->checkValid(app->getAppConnector(), lrv, 0, 0, 0); REQUIRE(!result->isSuccess()); REQUIRE(result->getResultCode() == txFROZEN_KEY_ACCESSED); }; @@ -2227,9 +2227,9 @@ TEST_CASE("frozen offers are transparent to DEX matching - randomized", tx->addSignature(taker.getSecretKey()); { - LedgerSnapshot ls(*app); - auto result = - tx->checkValid(app->getAppConnector(), ls, 0, 0, 0); + LedgerReadView lrv(*app); + auto result = tx->checkValid(app->getAppConnector(), + lrv, 0, 0, 0); REQUIRE(result->isSuccess()); } diff --git a/src/transactions/test/InvokeHostFunctionTests.cpp b/src/transactions/test/InvokeHostFunctionTests.cpp index 74e00bd98f..bb61651e90 100644 --- a/src/transactions/test/InvokeHostFunctionTests.cpp +++ b/src/transactions/test/InvokeHostFunctionTests.cpp @@ -2210,10 +2210,10 @@ TEST_CASE("resource fee exceeds uint32", "[tx][soroban][feebump]") txEnvelope.v1()); auto tx = TransactionFrameBase::makeTransactionFromWire( test.getApp().getNetworkID(), txEnvelope); - LedgerSnapshot ls(test.getApp()); + LedgerReadView lrv(test.getApp()); auto diagnostics = DiagnosticEventManager::createDisabled(); auto innerCheckValidResult = tx->checkValid( - test.getApp().getAppConnector(), ls, 0, 0, 0, diagnostics); + test.getApp().getAppConnector(), lrv, 0, 0, 0, diagnostics); int64_t feeBumpFullFee = resourceFee + inclusionFee; auto feeBumpTx = feeBump(test.getApp(), feeBumper, tx, feeBumpFullFee, @@ -2222,7 +2222,7 @@ TEST_CASE("resource fee exceeds uint32", "[tx][soroban][feebump]") REQUIRE(feeBumpTx->getInclusionFee() == inclusionFee); auto checkValidResult = feeBumpTx->checkValid( - test.getApp().getAppConnector(), ls, 0, 0, 0, diagnostics); + test.getApp().getAppConnector(), lrv, 0, 0, 0, diagnostics); if (!checkValidResult->isSuccess()) { return checkValidResult->getResultCode(); @@ -8725,8 +8725,8 @@ TEST_CASE_VERSIONS("merge account then SAC payment scenarios", checkTx(1, r, txFAILED); // Verify that a1 no longer exists after the merge - LedgerSnapshot ls(test.getApp()); - REQUIRE(!ls.getAccount(a1.getPublicKey())); + LedgerReadView lrv(test.getApp()); + REQUIRE(!lrv.getAccount(a1.getPublicKey())); // Verify that b1 received a1's balance (minus merge fee) auto expectedBalance = @@ -8757,8 +8757,8 @@ TEST_CASE_VERSIONS("merge account then SAC payment scenarios", checkTx(1, r, txFAILED); // Verify that a1 no longer exists after the merge - LedgerSnapshot ls(test.getApp()); - REQUIRE(!ls.getAccount(a1.getPublicKey())); + LedgerReadView lrv(test.getApp()); + REQUIRE(!lrv.getAccount(a1.getPublicKey())); // Verify that b1 received a1's balance (minus merge fee) auto expectedBalance = @@ -8794,8 +8794,8 @@ TEST_CASE_VERSIONS("merge account then SAC payment scenarios", checkTx(1, r, txNO_ACCOUNT); // Verify that a1 no longer exists after the merge - LedgerSnapshot ls(test.getApp()); - REQUIRE(!ls.getAccount(a1.getPublicKey())); + LedgerReadView lrv(test.getApp()); + REQUIRE(!lrv.getAccount(a1.getPublicKey())); // Verify that b1 received a1's balance (minus the soroban // transactions fee which a1 paid before it was merged). @@ -9057,7 +9057,7 @@ TEST_CASE("apply generated parallel tx sets", "[soroban][parallelapply]") { std::vector sorobanTxs; auto resources = lm.maxLedgerResources(true); - LedgerSnapshot ls(app); + LedgerReadView lrv(app); for (int txId = 0; txId < MAX_TRANSACTIONS_PER_LEDGER; ++txId) { auto account = txtest::getGenesisAccount(app, accountId++); @@ -9098,7 +9098,7 @@ TEST_CASE("apply generated parallel tx sets", "[soroban][parallelapply]") auto tx = invocation.withExactNonRefundableResourceFee().createTx( &account); - REQUIRE(tx->checkValid(app.getAppConnector(), ls, 0, 0, 0) + REQUIRE(tx->checkValid(app.getAppConnector(), lrv, 0, 0, 0) ->isSuccess()); if (!anyGreater(tx->getResources(false, test.getLedgerVersion()), resources)) @@ -9488,8 +9488,8 @@ TEST_CASE("in-memory state size tracking", "[soroban]") { auto ledgerKey = client.getContract().getDataKey( makeSymbolSCVal(key), durability); - LedgerSnapshot ls(test.getApp()); - auto le = ls.load(ledgerKey); + LedgerReadView lrv(test.getApp()); + auto le = lrv.load(ledgerKey); if (le) { // We only deal with the data entries here, so no need to use @@ -9700,9 +9700,9 @@ TEST_CASE("readonly ttl bumps across threads and stages", auto startingTTL = test.getTTL(lk); // Capture the TTL entry's lastModifiedLedgerSeq before tx execution - LedgerSnapshot ls(test.getApp()); + LedgerReadView lrv(test.getApp()); auto ttlKey = getTTLKey(lk); - auto ttlEntry = ls.load(ttlKey); + auto ttlEntry = lrv.load(ttlKey); REQUIRE(ttlEntry); uint32_t ttlLastModifiedBeforeTx = ttlEntry.current().lastModifiedLedgerSeq; @@ -9749,9 +9749,9 @@ TEST_CASE("readonly ttl bumps across threads and stages", auto startingTTL = test.getTTL(lk); // Capture the TTL entry's lastModifiedLedgerSeq before tx execution - LedgerSnapshot ls(test.getApp()); + LedgerReadView lrv(test.getApp()); auto ttlKey = getTTLKey(lk); - auto ttlEntry = ls.load(ttlKey); + auto ttlEntry = lrv.load(ttlKey); REQUIRE(ttlEntry); uint32_t ttlLastModifiedBeforeTx = ttlEntry.current().lastModifiedLedgerSeq; @@ -9803,9 +9803,9 @@ TEST_CASE("readonly ttl bumps across threads and stages", auto startingTTL = test.getTTL(lk); // Capture the TTL entry's lastModifiedLedgerSeq before tx execution - LedgerSnapshot ls(test.getApp()); + LedgerReadView lrv(test.getApp()); auto ttlKey = getTTLKey(lk); - auto ttlEntry = ls.load(ttlKey); + auto ttlEntry = lrv.load(ttlKey); REQUIRE(ttlEntry); uint32_t ttlLastModifiedBeforeTx = ttlEntry.current().lastModifiedLedgerSeq; @@ -10192,8 +10192,8 @@ TEST_CASE_VERSIONS("fee bump inner account merged then used as inner account " REQUIRE(innerRes.result.code() == txNO_ACCOUNT); // Verify that innerAccount no longer exists after the merge - LedgerSnapshot ls(test.getApp()); - REQUIRE(!ls.getAccount(innerAccount.getPublicKey())); + LedgerReadView lrv(test.getApp()); + REQUIRE(!lrv.getAccount(innerAccount.getPublicKey())); auto expectedDestinationBalance = startingBalance + startingBalance; REQUIRE(destination.getBalance() == expectedDestinationBalance); diff --git a/src/transactions/test/ParallelApplyTest.cpp b/src/transactions/test/ParallelApplyTest.cpp index 71201a15d2..699b31e9fd 100644 --- a/src/transactions/test/ParallelApplyTest.cpp +++ b/src/transactions/test/ParallelApplyTest.cpp @@ -1052,16 +1052,16 @@ applyTestTransactions(TestConfig const& testConfig, uint32_t protocolVersion, auto allTxs = classicTxs; allTxs.insert(allTxs.end(), sorobanTxs.begin(), sorobanTxs.end()); { - LedgerSnapshot ls(test.getApp()); + LedgerReadView lrv(test.getApp()); auto diag = DiagnosticEventManager::createDisabled(); for (auto const& tx : allTxs) { - bool isValid = tx->checkValid(test.getApp().getAppConnector(), ls, + bool isValid = tx->checkValid(test.getApp().getAppConnector(), lrv, 0, 0, 0, diag) ->isSuccess(); if (!isValid) { - tx->checkValid(test.getApp().getAppConnector(), ls, 0, 0, 0, + tx->checkValid(test.getApp().getAppConnector(), lrv, 0, 0, 0, diag); } REQUIRE(isValid); @@ -1120,14 +1120,14 @@ applyTestTransactions(TestConfig const& testConfig, uint32_t protocolVersion, std::vector, std::optional>>> finalEntries; - LedgerSnapshot ls(test.getApp()); + LedgerReadView lrv(test.getApp()); auto archiveSnap = test.getApp().getLedgerManager().copyLedgerStateSnapshot(); for (auto const& k : allKeys) { std::optional liveEntry; std::optional archivedEntry; - if (auto e = ls.load(k)) + if (auto e = lrv.load(k)) { liveEntry = e.current(); // All the entries that were in the live state and were @@ -1154,7 +1154,7 @@ applyTestTransactions(TestConfig const& testConfig, uint32_t protocolVersion, { LedgerKey ttlKey = getTTLKey(k); std::optional liveTtlEntry; - if (auto e = ls.load(ttlKey)) + if (auto e = lrv.load(ttlKey)) { liveTtlEntry = e.current(); } diff --git a/src/transactions/test/PaymentTests.cpp b/src/transactions/test/PaymentTests.cpp index 63ddb1d13c..dfedec54bd 100644 --- a/src/transactions/test/PaymentTests.cpp +++ b/src/transactions/test/PaymentTests.cpp @@ -1510,11 +1510,11 @@ TEST_CASE_VERSIONS("payment", "[tx][payment]") // Since a1 has a trustline, and there is only 1 trustline, we know // that gateway has no trustlines. - LedgerSnapshot lsg(*app); + LedgerReadView lrv(*app); LedgerKey trustKey(TRUSTLINE); trustKey.trustLine().accountID = gateway.getPublicKey(); trustKey.trustLine().asset = assetToTrustLineAsset(idr); - REQUIRE(!lsg.load(trustKey)); + REQUIRE(!lrv.load(trustKey)); }); } SECTION("authorize flag") diff --git a/src/transactions/test/SorobanTxTestUtils.cpp b/src/transactions/test/SorobanTxTestUtils.cpp index 66567be391..16725e00d9 100644 --- a/src/transactions/test/SorobanTxTestUtils.cpp +++ b/src/transactions/test/SorobanTxTestUtils.cpp @@ -1369,10 +1369,10 @@ SorobanTest::createRestoreTx(SorobanResources const& resources, bool SorobanTest::isTxValid(TransactionFrameBaseConstPtr tx) { - LedgerSnapshot ls(getApp()); + LedgerReadView lrv(getApp()); auto diagnostics = DiagnosticEventManager::createDisabled(); auto ret = - tx->checkValid(getApp().getAppConnector(), ls, 0, 0, 0, diagnostics); + tx->checkValid(getApp().getAppConnector(), lrv, 0, 0, 0, diagnostics); return ret->isSuccess(); } @@ -1381,10 +1381,10 @@ SorobanTest::invokeTx(TransactionFrameBaseConstPtr tx) { { auto diagnostics = DiagnosticEventManager::createDisabled(); - LedgerSnapshot ls(getApp()); - REQUIRE( - tx->checkValid(getApp().getAppConnector(), ls, 0, 0, 0, diagnostics) - ->isSuccess()); + LedgerReadView lrv(getApp()); + REQUIRE(tx->checkValid(getApp().getAppConnector(), lrv, 0, 0, 0, + diagnostics) + ->isSuccess()); } auto resultSet = closeLedger(*mApp, {tx}); @@ -1435,10 +1435,10 @@ ExpirationStatus SorobanTest::getEntryExpirationStatus(LedgerKey const& key) { auto ttlKey = getTTLKey(key); - LedgerSnapshot ls(getApp()); - if (auto lse = ls.load(ttlKey)) + LedgerReadView lrv(getApp()); + if (auto le = lrv.load(ttlKey)) { - if (lse.current().data.ttl().liveUntilLedgerSeq <= getLCLSeq()) + if (le.current().data.ttl().liveUntilLedgerSeq <= getLCLSeq()) { return ExpirationStatus::EXPIRED_IN_LIVE_STATE; } diff --git a/src/transactions/test/TransactionTestFrame.cpp b/src/transactions/test/TransactionTestFrame.cpp index 62358e7cae..45cc823ead 100644 --- a/src/transactions/test/TransactionTestFrame.cpp +++ b/src/transactions/test/TransactionTestFrame.cpp @@ -86,35 +86,36 @@ TransactionTestFrame::checkValid(AppConnector& app, AbstractLedgerTxn& ltxOuter, uint64_t upperBoundCloseTimeOffset) const { LedgerTxn ltx(ltxOuter); - auto ls = LedgerSnapshot(ltx); + auto lrv = LedgerReadView(ltx); auto diagnostics = DiagnosticEventManager::createDisabled(); mTransactionTxResult = mTransactionFrame->checkValid( - app, ls, current, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, + app, lrv, current, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, diagnostics); return mTransactionTxResult->clone(); } MutableTxResultPtr -TransactionTestFrame::checkValid(AppConnector& app, LedgerSnapshot const& ls, - SequenceNumber current, - uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset) const +TransactionTestFrame::checkValid( + AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, + uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, + std::optional validationLedgerSeq) const { auto diagnostics = DiagnosticEventManager::createDisabled(); - return checkValid(app, ls, current, lowerBoundCloseTimeOffset, - upperBoundCloseTimeOffset, diagnostics); + return checkValid(app, lrv, current, lowerBoundCloseTimeOffset, + upperBoundCloseTimeOffset, diagnostics, + validationLedgerSeq); } MutableTxResultPtr -TransactionTestFrame::checkValid(AppConnector& app, LedgerSnapshot const& ls, - SequenceNumber current, - uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset, - DiagnosticEventManager& diagnosticEvents) const +TransactionTestFrame::checkValid( + AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, + uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq) const { mTransactionTxResult = mTransactionFrame->checkValid( - app, ls, current, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, - diagnosticEvents); + app, lrv, current, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, + diagnosticEvents, validationLedgerSeq); return mTransactionTxResult->clone(); } @@ -238,10 +239,10 @@ TransactionTestFrame::checkSignature(SignatureChecker& signatureChecker, bool TransactionTestFrame::checkOperationSignatures( - SignatureChecker& signatureChecker, LedgerSnapshot const& ls, + SignatureChecker& signatureChecker, LedgerReadView const& lrv, MutableTransactionResultBase* txResult) const { - return mTransactionFrame->checkOperationSignatures(signatureChecker, ls, + return mTransactionFrame->checkOperationSignatures(signatureChecker, lrv, txResult); } diff --git a/src/transactions/test/TransactionTestFrame.h b/src/transactions/test/TransactionTestFrame.h index 72f6a451e4..f3384c86de 100644 --- a/src/transactions/test/TransactionTestFrame.h +++ b/src/transactions/test/TransactionTestFrame.h @@ -68,15 +68,17 @@ class TransactionTestFrame : public TransactionFrameBase SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset) const; - MutableTxResultPtr checkValid(AppConnector& app, LedgerSnapshot const& ls, + MutableTxResultPtr checkValid( + AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, + uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, + std::optional validationLedgerSeq = std::nullopt) const; + MutableTxResultPtr checkValid(AppConnector& app, LedgerReadView const& lrv, SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset) const; - MutableTxResultPtr - checkValid(AppConnector& app, LedgerSnapshot const& ls, - SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset, - DiagnosticEventManager& diagnosticEvents) const override; + uint64_t upperBoundCloseTimeOffset, + DiagnosticEventManager& diagnosticEvents, + std::optional validationLedgerSeq = + std::nullopt) const override; bool checkSorobanResources( SorobanNetworkConfig const& cfg, uint32_t ledgerVersion, DiagnosticEventManager& diagnosticEvents) const override; @@ -113,7 +115,7 @@ class TransactionTestFrame : public TransactionFrameBase int32_t neededWeight) const override; bool checkOperationSignatures( - SignatureChecker& signatureChecker, LedgerSnapshot const& ls, + SignatureChecker& signatureChecker, LedgerReadView const& lrv, MutableTransactionResultBase* txResult) const override; bool checkAllTransactionSignatures(SignatureChecker& signatureChecker,