diff --git a/src/herder/TransactionQueue.cpp b/src/herder/TransactionQueue.cpp index 31e884d6bf..84df5d971f 100644 --- a/src/herder/TransactionQueue.cpp +++ b/src/herder/TransactionQueue.cpp @@ -326,7 +326,8 @@ TransactionQueue::canAdd(TransactionFrameBasePtr tx, { auto txResult = tx->createSuccessResult(); if (!tx->checkSorobanResourceAndSetError( - mApp, + mApp.getLedgerManager().getSorobanNetworkConfig(), + mApp.getConfig(), mApp.getLedgerManager() .getLastClosedLedgerHeader() .header.ledgerVersion, diff --git a/src/ledger/LedgerManager.h b/src/ledger/LedgerManager.h index a34dbb38ae..228dc1f01c 100644 --- a/src/ledger/LedgerManager.h +++ b/src/ledger/LedgerManager.h @@ -126,9 +126,12 @@ class LedgerManager virtual void updateNetworkConfig(AbstractLedgerTxn& ltx) = 0; // Return the network config for Soroban. // The config is automatically refreshed on protocol upgrades. - // Ledger txn here is needed for the sake of lazy load; it won't be - // used most of the time. virtual SorobanNetworkConfig const& getSorobanNetworkConfig() = 0; + + // Returns a pointer the network config for Soroban, or nullptr if + // ledgerVersion < Protocol 20. + virtual SorobanNetworkConfig const* + maybeGetSorobanNetworkConfigPtr(uint32_t ledgerVersion) = 0; virtual bool hasSorobanNetworkConfig() const = 0; #ifdef BUILD_TESTS diff --git a/src/ledger/LedgerManagerImpl.cpp b/src/ledger/LedgerManagerImpl.cpp index 79728a996c..54003742e0 100644 --- a/src/ledger/LedgerManagerImpl.cpp +++ b/src/ledger/LedgerManagerImpl.cpp @@ -561,6 +561,17 @@ LedgerManagerImpl::getSorobanNetworkConfig() return getSorobanNetworkConfigInternal(); } +SorobanNetworkConfig const* +LedgerManagerImpl::maybeGetSorobanNetworkConfigPtr(uint32_t ledgerVersion) +{ + if (protocolVersionStartsFrom(ledgerVersion, SOROBAN_PROTOCOL_VERSION)) + { + return &getSorobanNetworkConfigInternal(); + } + + return nullptr; +} + bool LedgerManagerImpl::hasSorobanNetworkConfig() const { diff --git a/src/ledger/LedgerManagerImpl.h b/src/ledger/LedgerManagerImpl.h index 3d53a066a5..516826cb61 100644 --- a/src/ledger/LedgerManagerImpl.h +++ b/src/ledger/LedgerManagerImpl.h @@ -150,6 +150,8 @@ class LedgerManagerImpl : public LedgerManager uint32_t getLastTxFee() const override; uint32_t getLastClosedLedgerNum() const override; SorobanNetworkConfig const& getSorobanNetworkConfig() override; + SorobanNetworkConfig const* + maybeGetSorobanNetworkConfigPtr(uint32_t ledgerVersion) override; bool hasSorobanNetworkConfig() const override; #ifdef BUILD_TESTS diff --git a/src/test/FuzzerImpl.cpp b/src/test/FuzzerImpl.cpp index e3f08b75b7..9eda55d2bd 100644 --- a/src/test/FuzzerImpl.cpp +++ b/src/test/FuzzerImpl.cpp @@ -925,8 +925,10 @@ class FuzzTransactionFrame : public TransactionFrame mEnvelope.v1().signatures}; // if any ill-formed Operations, do not attempt transaction application auto isInvalidOperation = [&](auto const& op, auto& opResult) { - return !op->checkValid(app, signatureChecker, ltx, false, opResult, - mTxResult->getSorobanData()); + return !op->checkValid( + &app.getLedgerManager().getSorobanNetworkConfig(), + app.getConfig(), signatureChecker, ltx, false, opResult, + mTxResult->getSorobanData()); }; auto const& ops = getOperations(); @@ -944,7 +946,7 @@ class FuzzTransactionFrame : public TransactionFrame // while the following method's result is not captured, regardless, for // protocols < 8, this triggered buggy caching, and potentially may do // so in the future - loadSourceAccount(ltx, ltx.loadHeader()); + loadSourceAccount(ltx, ltx.loadHeader().current()); processSeqNum(ltx); TransactionMetaFrame tm(2); applyOperations(signatureChecker, app, ltx, tm, *mTxResult, Hash{}); diff --git a/src/transactions/FeeBumpTransactionFrame.cpp b/src/transactions/FeeBumpTransactionFrame.cpp index 6c7f6e1667..66fcb9cc3c 100644 --- a/src/transactions/FeeBumpTransactionFrame.cpp +++ b/src/transactions/FeeBumpTransactionFrame.cpp @@ -132,8 +132,7 @@ FeeBumpTransactionFrame::processPostApply(Application& app, // Note that we are not calling TransactionFrame::processPostApply, so if // any logic is added there, we would have to reason through if that logic // should also be reflected here. - int64_t refund = - mInnerTx->processRefund(app, ltx, meta, getFeeSourceID(), *txResult); + mInnerTx->processRefund(app, ltx, meta, getFeeSourceID(), *txResult); } bool @@ -187,8 +186,14 @@ FeeBumpTransactionFrame::checkValid(Application& app, return txResult; } + auto& cfg = app.getConfig(); + + auto header = ltx.loadHeader().current(); + auto sorobanCfg = app.getLedgerManager().maybeGetSorobanNetworkConfigPtr( + header.ledgerVersion); + auto innerTxResult = mInnerTx->checkValidWithOptionallyChargedFee( - app, ltx, current, false, lowerBoundCloseTimeOffset, + ltx, cfg, sorobanCfg, header, current, false, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset); auto finalTxResult = createSuccessResultWithNewInnerTx( std::move(txResult), std::move(innerTxResult), mInnerTx); @@ -198,10 +203,11 @@ FeeBumpTransactionFrame::checkValid(Application& app, bool FeeBumpTransactionFrame::checkSorobanResourceAndSetError( - Application& app, uint32_t ledgerVersion, MutableTxResultPtr txResult) const + SorobanNetworkConfig const& sorobanConfig, Config const& cfg, + uint32_t ledgerVersion, MutableTxResultPtr txResult) const { - return mInnerTx->checkSorobanResourceAndSetError(app, ledgerVersion, - txResult); + return mInnerTx->checkSorobanResourceAndSetError(sorobanConfig, cfg, + ledgerVersion, txResult); } bool diff --git a/src/transactions/FeeBumpTransactionFrame.h b/src/transactions/FeeBumpTransactionFrame.h index 03e635e072..abc558fb7c 100644 --- a/src/transactions/FeeBumpTransactionFrame.h +++ b/src/transactions/FeeBumpTransactionFrame.h @@ -81,7 +81,8 @@ class FeeBumpTransactionFrame : public TransactionFrameBase SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset) const override; bool - checkSorobanResourceAndSetError(Application& app, uint32_t ledgerVersion, + checkSorobanResourceAndSetError(SorobanNetworkConfig const& sorobanConfig, + Config const& cfg, uint32_t ledgerVersion, MutableTxResultPtr txResult) const override; MutableTxResultPtr createSuccessResult() const override; diff --git a/src/transactions/OperationFrame.cpp b/src/transactions/OperationFrame.cpp index 25787c38b0..406e9abec4 100644 --- a/src/transactions/OperationFrame.cpp +++ b/src/transactions/OperationFrame.cpp @@ -142,8 +142,15 @@ OperationFrame::apply(Application& app, SignatureChecker& signatureChecker, { ZoneScoped; CLOG_TRACE(Tx, "{}", xdrToCerealString(mOperation, "Operation")); - bool applyRes = - checkValid(app, signatureChecker, ltx, true, res, sorobanData); + + SorobanNetworkConfig const* sorobanCfg = nullptr; + if (isSoroban()) + { + sorobanCfg = &app.getLedgerManager().getSorobanNetworkConfig(); + } + + bool applyRes = checkValid(sorobanCfg, app.getConfig(), signatureChecker, + ltx, true, res, sorobanData); if (applyRes) { if (isSoroban()) @@ -197,7 +204,7 @@ OperationFrame::checkSignature(SignatureChecker& signatureChecker, { auto neededThreshold = getNeededThreshold(sourceAccount, getThresholdLevel()); - if (!mParentTx.checkSignature(signatureChecker, sourceAccount, + if (!mParentTx.checkSignature(signatureChecker, sourceAccount.current(), neededThreshold)) { res.code(opBAD_AUTH); @@ -235,7 +242,9 @@ OperationFrame::getSourceID() const // make sure sig is correct // verifies that the operation is well formed (operation specific) bool -OperationFrame::checkValid(Application& app, SignatureChecker& signatureChecker, +OperationFrame::checkValid(SorobanNetworkConfig const* const sorobanCfg, + Config const& cfg, + SignatureChecker& signatureChecker, AbstractLedgerTxn& ltxOuter, bool forApply, OperationResult& res, std::shared_ptr sorobanData) const @@ -274,12 +283,10 @@ OperationFrame::checkValid(Application& app, SignatureChecker& signatureChecker, if (protocolVersionStartsFrom(ledgerVersion, SOROBAN_PROTOCOL_VERSION) && isSoroban()) { + releaseAssertOrThrow(sorobanCfg); releaseAssertOrThrow(sorobanData); - auto const& sorobanConfig = - app.getLedgerManager().getSorobanNetworkConfig(); - - return doCheckValidForSoroban(sorobanConfig, app.getConfig(), - ledgerVersion, res, *sorobanData); + return doCheckValidForSoroban(*sorobanCfg, cfg, ledgerVersion, res, + *sorobanData); } else { @@ -302,7 +309,7 @@ OperationFrame::loadSourceAccount(AbstractLedgerTxn& ltx, LedgerTxnHeader const& header) const { ZoneScoped; - return mParentTx.loadAccount(ltx, header, getSourceID()); + return mParentTx.loadAccount(ltx, header.current(), getSourceID()); } void diff --git a/src/transactions/OperationFrame.h b/src/transactions/OperationFrame.h index f161f1ca0e..20160df2c9 100644 --- a/src/transactions/OperationFrame.h +++ b/src/transactions/OperationFrame.h @@ -85,7 +85,8 @@ class OperationFrame AccountID getSourceID() const; - bool checkValid(Application& app, SignatureChecker& signatureChecker, + bool checkValid(SorobanNetworkConfig const* const sorobanCfg, + Config const& cfg, SignatureChecker& signatureChecker, AbstractLedgerTxn& ltxOuter, bool forApply, OperationResult& res, std::shared_ptr sorobanData) const; diff --git a/src/transactions/TransactionFrame.cpp b/src/transactions/TransactionFrame.cpp index dfdc55f00f..672266c694 100644 --- a/src/transactions/TransactionFrame.cpp +++ b/src/transactions/TransactionFrame.cpp @@ -265,11 +265,11 @@ TransactionFrame::getFee(LedgerHeader const& header, bool TransactionFrame::checkSignature(SignatureChecker& signatureChecker, - LedgerTxnEntry const& account, + LedgerEntry const& account, int32_t neededWeight) const { ZoneScoped; - auto& acc = account.current().data.account(); + auto& acc = account.data.account(); std::vector signers; if (acc.thresholds[0]) { @@ -320,12 +320,11 @@ TransactionFrame::checkExtraSigners(SignatureChecker& signatureChecker) const LedgerTxnEntry TransactionFrame::loadSourceAccount(AbstractLedgerTxn& ltx, - LedgerTxnHeader const& header) const + LedgerHeader const& header) const { ZoneScoped; auto res = loadAccount(ltx, header, getSourceID()); - if (protocolVersionIsBefore(header.current().ledgerVersion, - ProtocolVersion::V_8)) + if (protocolVersionIsBefore(header.ledgerVersion, ProtocolVersion::V_8)) { // this is buggy caching that existed in old versions of the protocol if (res) @@ -343,12 +342,11 @@ TransactionFrame::loadSourceAccount(AbstractLedgerTxn& ltx, LedgerTxnEntry TransactionFrame::loadAccount(AbstractLedgerTxn& ltx, - LedgerTxnHeader const& header, + LedgerHeader const& header, AccountID const& accountID) const { ZoneScoped; - if (protocolVersionIsBefore(header.current().ledgerVersion, - ProtocolVersion::V_8) && + if (protocolVersionIsBefore(header.ledgerVersion, ProtocolVersion::V_8) && mCachedAccountPreProtocol8 && mCachedAccountPreProtocol8->ledgerEntry().data.account().accountID == accountID) @@ -679,7 +677,7 @@ TransactionFrame::refundSorobanFee(AbstractLedgerTxn& ltxOuter, auto header = ltx.loadHeader(); // The fee source could be from a Fee-bump, so it needs to be forwarded here // instead of using TransactionFrame's getFeeSource() method - auto feeSourceAccount = loadAccount(ltx, header, feeSource); + auto feeSourceAccount = loadAccount(ltx, header.current(), feeSource); if (!feeSourceAccount) { // Account was merged (shouldn't be possible) @@ -775,13 +773,13 @@ TransactionFrame::computePreApplySorobanResourceFee( } bool -TransactionFrame::isTooEarly(LedgerTxnHeader const& header, +TransactionFrame::isTooEarly(LedgerHeader const& header, uint64_t lowerBoundCloseTimeOffset) const { auto const tb = getTimeBounds(); if (tb) { - uint64 closeTime = header.current().scpValue.closeTime; + uint64 closeTime = header.scpValue.closeTime; if (tb->minTime && (tb->minTime > (closeTime + lowerBoundCloseTimeOffset))) { @@ -789,18 +787,17 @@ TransactionFrame::isTooEarly(LedgerTxnHeader const& header, } } - if (protocolVersionStartsFrom(header.current().ledgerVersion, - ProtocolVersion::V_19)) + if (protocolVersionStartsFrom(header.ledgerVersion, ProtocolVersion::V_19)) { auto const lb = getLedgerBounds(); - return lb && lb->minLedger > header.current().ledgerSeq; + return lb && lb->minLedger > header.ledgerSeq; } return false; } bool -TransactionFrame::isTooLate(LedgerTxnHeader const& header, +TransactionFrame::isTooLate(LedgerHeader const& header, uint64_t upperBoundCloseTimeOffset) const { auto const tb = getTimeBounds(); @@ -809,7 +806,7 @@ TransactionFrame::isTooLate(LedgerTxnHeader 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; + uint64 closeTime = header.scpValue.closeTime; if (tb->maxTime && (tb->maxTime < (closeTime + upperBoundCloseTimeOffset))) { @@ -817,29 +814,26 @@ TransactionFrame::isTooLate(LedgerTxnHeader const& header, } } - if (protocolVersionStartsFrom(header.current().ledgerVersion, - ProtocolVersion::V_19)) + if (protocolVersionStartsFrom(header.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 <= header.ledgerSeq; } return false; } bool -TransactionFrame::isTooEarlyForAccount(LedgerTxnHeader const& header, - LedgerTxnEntry const& sourceAccount, +TransactionFrame::isTooEarlyForAccount(LedgerHeader const& header, + LedgerEntry const& sourceAccount, uint64_t lowerBoundCloseTimeOffset) const { - if (protocolVersionIsBefore(header.current().ledgerVersion, - ProtocolVersion::V_19)) + if (protocolVersionIsBefore(header.ledgerVersion, ProtocolVersion::V_19)) { return false; } auto accountEntry = [&]() -> AccountEntry const& { - return sourceAccount.current().data.account(); + return sourceAccount.data.account(); }; auto accSeqTime = hasAccountEntryExtV3(accountEntry()) @@ -848,7 +842,7 @@ TransactionFrame::isTooEarlyForAccount(LedgerTxnHeader const& header, auto minSeqAge = getMinSeqAge(); auto lowerBoundCloseTime = - header.current().scpValue.closeTime + lowerBoundCloseTimeOffset; + header.scpValue.closeTime + lowerBoundCloseTimeOffset; if (minSeqAge > lowerBoundCloseTime || lowerBoundCloseTime - minSeqAge < accSeqTime) { @@ -861,7 +855,7 @@ TransactionFrame::isTooEarlyForAccount(LedgerTxnHeader const& header, : 0; auto minSeqLedgerGap = getMinSeqLedgerGap(); - auto ledgerSeq = header.current().ledgerSeq; + auto ledgerSeq = header.ledgerSeq; if (minSeqLedgerGap > ledgerSeq || ledgerSeq - minSeqLedgerGap < accSeqLedger) { @@ -873,8 +867,10 @@ TransactionFrame::isTooEarlyForAccount(LedgerTxnHeader const& header, bool TransactionFrame::commonValidPreSeqNum( - Application& app, AbstractLedgerTxn& ltx, bool chargeFee, - uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, + AbstractLedgerTxn& ltx, Config const& cfg, + SorobanNetworkConfig const* const sorobanCfg, LedgerHeader const& header, + bool chargeFee, uint64_t lowerBoundCloseTimeOffset, + uint64_t upperBoundCloseTimeOffset, std::optional sorobanResourceFee, MutableTxResultPtr txResult) const { @@ -883,7 +879,7 @@ TransactionFrame::commonValidPreSeqNum( // this function does validations that are independent of the account state // (stay true regardless of other side effects) - uint32_t ledgerVersion = ltx.loadHeader().current().ledgerVersion; + uint32_t ledgerVersion = header.ledgerVersion; if ((protocolVersionIsBefore(ledgerVersion, ProtocolVersion::V_13) && (mEnvelope.type() == ENVELOPE_TYPE_TX || hasMuxedAccount(mEnvelope))) || @@ -943,7 +939,9 @@ TransactionFrame::commonValidPreSeqNum( return false; } - if (!checkSorobanResourceAndSetError(app, ledgerVersion, txResult)) + releaseAssertOrThrow(sorobanCfg); + if (!checkSorobanResourceAndSetError(*sorobanCfg, cfg, ledgerVersion, + txResult)) { return false; } @@ -953,7 +951,7 @@ TransactionFrame::commonValidPreSeqNum( if (sorobanData.resourceFee > getFullFee()) { sorobanTxData.pushValidationTimeDiagnosticError( - app.getConfig(), SCE_STORAGE, SCEC_EXCEEDED_LIMIT, + cfg, SCE_STORAGE, SCEC_EXCEEDED_LIMIT, "transaction `sorobanData.resourceFee` is higher than the " "full transaction fee", {makeU64SCVal(sorobanData.resourceFee), @@ -967,7 +965,7 @@ TransactionFrame::commonValidPreSeqNum( INT64_MAX - sorobanResourceFee->non_refundable_fee) { sorobanTxData.pushValidationTimeDiagnosticError( - app.getConfig(), SCE_STORAGE, SCEC_INVALID_INPUT, + cfg, SCE_STORAGE, SCEC_INVALID_INPUT, "transaction resource fees cannot be added", {makeU64SCVal(sorobanResourceFee->refundable_fee), makeU64SCVal(sorobanResourceFee->non_refundable_fee)}); @@ -980,7 +978,7 @@ TransactionFrame::commonValidPreSeqNum( if (sorobanData.resourceFee < resourceFees) { sorobanTxData.pushValidationTimeDiagnosticError( - app.getConfig(), SCE_STORAGE, SCEC_EXCEEDED_LIMIT, + cfg, SCE_STORAGE, SCEC_EXCEEDED_LIMIT, "transaction `sorobanData.resourceFee` is lower than the " "actual Soroban resource fee", {makeU64SCVal(sorobanData.resourceFee), @@ -999,7 +997,7 @@ TransactionFrame::commonValidPreSeqNum( if (!set.emplace(lk).second) { sorobanTxData.pushValidationTimeDiagnosticError( - app.getConfig(), SCE_STORAGE, SCEC_INVALID_INPUT, + cfg, SCE_STORAGE, SCEC_INVALID_INPUT, "Found duplicate key in the Soroban footprint; every " "key across read-only and read-write footprints has to " "be unique.", @@ -1031,7 +1029,6 @@ TransactionFrame::commonValidPreSeqNum( } } - auto header = ltx.loadHeader(); if (isTooEarly(header, lowerBoundCloseTimeOffset)) { txResult->setInnermostResultCode(txTOO_EARLY); @@ -1043,8 +1040,7 @@ TransactionFrame::commonValidPreSeqNum( return false; } - if (chargeFee && - getInclusionFee() < getMinInclusionFee(*this, header.current())) + if (chargeFee && getInclusionFee() < getMinInclusionFee(*this, header)) { txResult->setInnermostResultCode(txINSUFFICIENT_FEE); return false; @@ -1072,7 +1068,7 @@ TransactionFrame::processSeqNum(AbstractLedgerTxn& ltx) const if (protocolVersionStartsFrom(header.current().ledgerVersion, ProtocolVersion::V_10)) { - auto sourceAccount = loadSourceAccount(ltx, header); + auto sourceAccount = loadSourceAccount(ltx, header.current()); if (sourceAccount.current().data.account().seqNum > getSeqNum()) { throw std::runtime_error("unexpected sequence number"); @@ -1149,9 +1145,9 @@ TransactionFrame::processSignatures( } bool -TransactionFrame::isBadSeq(LedgerTxnHeader const& header, int64_t seqNum) const +TransactionFrame::isBadSeq(LedgerHeader const& header, int64_t seqNum) const { - if (getSeqNum() == getStartingSequenceNumber(header)) + if (getSeqNum() == getStartingSequenceNumber(header.ledgerSeq)) { return true; } @@ -1159,8 +1155,7 @@ TransactionFrame::isBadSeq(LedgerTxnHeader const& header, int64_t seqNum) const // If seqNum == INT64_MAX, seqNum >= getSeqNum() is guaranteed to be true // because SequenceNumber is int64, so isBadSeq will always return true in // that case. - if (protocolVersionStartsFrom(header.current().ledgerVersion, - ProtocolVersion::V_19)) + if (protocolVersionStartsFrom(header.ledgerVersion, ProtocolVersion::V_19)) { // Check if we need to relax sequence number checking auto minSeqNum = getMinSeqNum(); @@ -1175,15 +1170,14 @@ TransactionFrame::isBadSeq(LedgerTxnHeader const& header, int64_t seqNum) const } TransactionFrame::ValidationType -TransactionFrame::commonValid(Application& app, - SignatureChecker& signatureChecker, - AbstractLedgerTxn& ltxOuter, - SequenceNumber current, bool applying, - bool chargeFee, - uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset, - std::optional sorobanResourceFee, - MutableTxResultPtr txResult) const +TransactionFrame::commonValid( + Config const& cfg, SorobanNetworkConfig const* const sorobanCfg, + LedgerHeader const& header, SignatureChecker& signatureChecker, + AbstractLedgerTxn& ltxOuter, SequenceNumber current, bool applying, + bool chargeFee, uint64_t lowerBoundCloseTimeOffset, + uint64_t upperBoundCloseTimeOffset, + std::optional sorobanResourceFee, + MutableTxResultPtr txResult) const { ZoneScoped; releaseAssertOrThrow(txResult); @@ -1197,19 +1191,18 @@ TransactionFrame::commonValid(Application& app, "Applying transaction with non-current closeTime"); } - if (!commonValidPreSeqNum(app, ltx, chargeFee, lowerBoundCloseTimeOffset, - upperBoundCloseTimeOffset, sorobanResourceFee, - txResult)) + if (!commonValidPreSeqNum( + ltx, cfg, sorobanCfg, header, chargeFee, lowerBoundCloseTimeOffset, + upperBoundCloseTimeOffset, sorobanResourceFee, txResult)) { return res; } - auto header = ltx.loadHeader(); auto sourceAccount = loadSourceAccount(ltx, header); // in older versions, the account's sequence number is updated when taking // fees - if (protocolVersionStartsFrom(header.current().ledgerVersion, + if (protocolVersionStartsFrom(header.ledgerVersion, ProtocolVersion::V_10) || !applying) { @@ -1226,21 +1219,22 @@ TransactionFrame::commonValid(Application& app, res = ValidationType::kInvalidUpdateSeqNum; - if (isTooEarlyForAccount(header, sourceAccount, lowerBoundCloseTimeOffset)) + if (isTooEarlyForAccount(header, sourceAccount.current(), + lowerBoundCloseTimeOffset)) { txResult->setInnermostResultCode(txBAD_MIN_SEQ_AGE_OR_GAP); return res; } if (!checkSignature( - signatureChecker, sourceAccount, + signatureChecker, sourceAccount.current(), sourceAccount.current().data.account().thresholds[THRESHOLD_LOW])) { txResult->setInnermostResultCode(txBAD_AUTH); return res; } - if (protocolVersionStartsFrom(header.current().ledgerVersion, + if (protocolVersionStartsFrom(header.ledgerVersion, ProtocolVersion::V_19) && !checkExtraSigners(signatureChecker)) { @@ -1254,13 +1248,14 @@ TransactionFrame::commonValid(Application& app, // balance, if not, we need to check if after that deduction this account // will still have minimum balance uint32_t feeToPay = - (applying && protocolVersionStartsFrom(header.current().ledgerVersion, - ProtocolVersion::V_9)) + (applying && + protocolVersionStartsFrom(header.ledgerVersion, ProtocolVersion::V_9)) ? 0 : static_cast(getFullFee()); // don't let the account go below the reserve after accounting for // liabilities - if (chargeFee && getAvailableBalance(header, sourceAccount) < feeToPay) + if (chargeFee && + getAvailableBalance(header, sourceAccount.current()) < feeToPay) { txResult->setInnermostResultCode(txINSUFFICIENT_BALANCE); return res; @@ -1281,7 +1276,7 @@ TransactionFrame::processFeeSeqNum(AbstractLedgerTxn& ltx, createSuccessResultWithFeeCharged(header.current(), baseFee, true); releaseAssert(txResult); - auto sourceAccount = loadSourceAccount(ltx, header); + auto sourceAccount = loadSourceAccount(ltx, header.current()); if (!sourceAccount) { throw std::runtime_error("Unexpected database state"); @@ -1384,8 +1379,9 @@ TransactionFrame::removeAccountSigner(AbstractLedgerTxn& ltxOuter, MutableTxResultPtr TransactionFrame::checkValidWithOptionallyChargedFee( - Application& app, AbstractLedgerTxn& ltxOuter, SequenceNumber current, - bool chargeFee, uint64_t lowerBoundCloseTimeOffset, + AbstractLedgerTxn& ltxOuter, Config const& cfg, + SorobanNetworkConfig const* const sorobanCfg, LedgerHeader const& header, + SequenceNumber current, bool chargeFee, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset) const { ZoneScoped; @@ -1399,30 +1395,29 @@ TransactionFrame::checkValidWithOptionallyChargedFee( } LedgerTxn ltx(ltxOuter); - int64_t minBaseFee = ltx.loadHeader().current().baseFee; + int64_t minBaseFee = header.baseFee; if (!chargeFee) { minBaseFee = 0; } - auto txResult = createSuccessResultWithFeeCharged( - ltx.loadHeader().current(), minBaseFee, false); + auto txResult = + createSuccessResultWithFeeCharged(header, minBaseFee, false); releaseAssert(txResult); - SignatureChecker signatureChecker{ltx.loadHeader().current().ledgerVersion, - getContentsHash(), + SignatureChecker signatureChecker{header.ledgerVersion, getContentsHash(), getSignatures(mEnvelope)}; std::optional sorobanResourceFee; - if (protocolVersionStartsFrom(ltx.loadHeader().current().ledgerVersion, + if (protocolVersionStartsFrom(header.ledgerVersion, SOROBAN_PROTOCOL_VERSION) && isSoroban()) { + releaseAssertOrThrow(sorobanCfg); sorobanResourceFee = computePreApplySorobanResourceFee( - ltx.loadHeader().current().ledgerVersion, - app.getLedgerManager().getSorobanNetworkConfig(), app.getConfig()); + header.ledgerVersion, *sorobanCfg, cfg); } - bool res = commonValid(app, signatureChecker, ltx, current, false, - chargeFee, lowerBoundCloseTimeOffset, + bool res = commonValid(cfg, sorobanCfg, header, signatureChecker, ltx, + current, false, chargeFee, lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset, sorobanResourceFee, txResult) == ValidationType::kMaybeValid; if (res) @@ -1432,8 +1427,8 @@ TransactionFrame::checkValidWithOptionallyChargedFee( auto const& op = mOperations[i]; auto& opResult = txResult->getOpResultAt(i); - if (!op->checkValid(app, signatureChecker, ltx, false, opResult, - txResult->getSorobanData())) + if (!op->checkValid(sorobanCfg, cfg, signatureChecker, ltx, false, + opResult, txResult->getSorobanData())) { // it's OK to just fast fail here and not try to call // checkValid on all operations as the resulting object @@ -1459,18 +1454,21 @@ TransactionFrame::checkValid(Application& app, AbstractLedgerTxn& ltxOuter, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset) const { - return checkValidWithOptionallyChargedFee(app, ltxOuter, current, true, - lowerBoundCloseTimeOffset, - upperBoundCloseTimeOffset); + auto& header = ltxOuter.loadHeader().current(); + auto sorobanCfg = app.getLedgerManager().maybeGetSorobanNetworkConfigPtr( + header.ledgerVersion); + + return checkValidWithOptionallyChargedFee( + ltxOuter, app.getConfig(), sorobanCfg, header, current, true, + lowerBoundCloseTimeOffset, upperBoundCloseTimeOffset); } bool TransactionFrame::checkSorobanResourceAndSetError( - Application& app, uint32_t ledgerVersion, MutableTxResultPtr txResult) const + SorobanNetworkConfig const& sorobanConfig, Config const& cfg, + uint32_t ledgerVersion, MutableTxResultPtr txResult) const { - auto const& sorobanConfig = - app.getLedgerManager().getSorobanNetworkConfig(); - if (!validateSorobanResources(sorobanConfig, app.getConfig(), ledgerVersion, + if (!validateSorobanResources(sorobanConfig, cfg, ledgerVersion, *txResult->getSorobanData())) { txResult->setInnermostResultCode(txSOROBAN_INVALID); @@ -1726,7 +1724,8 @@ TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx, try { mCachedAccountPreProtocol8.reset(); - uint32_t ledgerVersion = ltx.loadHeader().current().ledgerVersion; + auto& header = ltx.loadHeader().current(); + uint32_t ledgerVersion = header.ledgerVersion; SignatureChecker signatureChecker{ledgerVersion, getContentsHash(), getSignatures(mEnvelope)}; @@ -1734,13 +1733,16 @@ TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx, // we'll skip trying to apply operations but we'll still // process the sequence number if needed std::optional sorobanResourceFee; + auto sorobanCfg = + app.getLedgerManager().maybeGetSorobanNetworkConfigPtr( + header.ledgerVersion); + if (protocolVersionStartsFrom(ledgerVersion, SOROBAN_PROTOCOL_VERSION) && isSoroban()) { sorobanResourceFee = computePreApplySorobanResourceFee( - ledgerVersion, app.getLedgerManager().getSorobanNetworkConfig(), - app.getConfig()); + ledgerVersion, *sorobanCfg, app.getConfig()); auto& sorobanData = *txResult->getSorobanData(); sorobanData.setSorobanConsumedNonRefundableFee( @@ -1750,8 +1752,9 @@ TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx, sorobanResourceFee->non_refundable_fee); } LedgerTxn ltxTx(ltx); - auto cv = commonValid(app, signatureChecker, ltxTx, 0, true, chargeFee, - 0, 0, sorobanResourceFee, txResult); + auto cv = commonValid(app.getConfig(), sorobanCfg, header, + signatureChecker, ltxTx, 0, true, chargeFee, 0, 0, + sorobanResourceFee, txResult); if (cv >= ValidationType::kInvalidUpdateSeqNum) { processSeqNum(ltxTx); diff --git a/src/transactions/TransactionFrame.h b/src/transactions/TransactionFrame.h index 97b1b0613f..8b04d3137b 100644 --- a/src/transactions/TransactionFrame.h +++ b/src/transactions/TransactionFrame.h @@ -71,7 +71,7 @@ class TransactionFrame : public TransactionFrameBase std::vector> mOperations; LedgerTxnEntry loadSourceAccount(AbstractLedgerTxn& ltx, - LedgerTxnHeader const& header) const; + LedgerHeader const& header) const; enum ValidationType { @@ -83,33 +83,34 @@ class TransactionFrame : public TransactionFrameBase kMaybeValid }; - virtual bool isTooEarly(LedgerTxnHeader const& header, + virtual bool isTooEarly(LedgerHeader const& header, uint64_t lowerBoundCloseTimeOffset) const; - virtual bool isTooLate(LedgerTxnHeader const& header, + virtual bool isTooLate(LedgerHeader const& header, uint64_t upperBoundCloseTimeOffset) const; - bool isTooEarlyForAccount(LedgerTxnHeader const& header, - LedgerTxnEntry const& sourceAccount, + bool isTooEarlyForAccount(LedgerHeader const& header, + LedgerEntry const& sourceAccount, uint64_t lowerBoundCloseTimeOffset) const; - bool commonValidPreSeqNum(Application& app, AbstractLedgerTxn& ltx, - bool chargeFee, + bool commonValidPreSeqNum(AbstractLedgerTxn& ltx, Config const& cfg, + SorobanNetworkConfig const* const sorobanCfg, + LedgerHeader const& header, bool chargeFee, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset, std::optional sorobanResourceFee, MutableTxResultPtr txResult) const; - virtual bool isBadSeq(LedgerTxnHeader const& header, int64_t seqNum) const; + virtual bool isBadSeq(LedgerHeader const& header, int64_t seqNum) const; - ValidationType commonValid(Application& app, - SignatureChecker& signatureChecker, - AbstractLedgerTxn& ltxOuter, - SequenceNumber current, bool applying, - bool chargeFee, - uint64_t lowerBoundCloseTimeOffset, - uint64_t upperBoundCloseTimeOffset, - std::optional sorobanResourceFee, - MutableTxResultPtr txResult) const; + ValidationType + commonValid(Config const& cfg, SorobanNetworkConfig const* const sorobanCfg, + LedgerHeader const& header, SignatureChecker& signatureChecker, + AbstractLedgerTxn& ltxOuter, SequenceNumber current, + bool applying, bool chargeFee, + uint64_t lowerBoundCloseTimeOffset, + uint64_t upperBoundCloseTimeOffset, + std::optional sorobanResourceFee, + MutableTxResultPtr txResult) const; void removeOneTimeSignerFromAllSourceAccounts(AbstractLedgerTxn& ltx) const; @@ -198,23 +199,26 @@ class TransactionFrame : public TransactionFrameBase bool applying) const override; bool checkSignature(SignatureChecker& signatureChecker, - LedgerTxnEntry const& account, - int32_t neededWeight) const; + LedgerEntry const& account, int32_t neededWeight) const; bool checkSignatureNoAccount(SignatureChecker& signatureChecker, AccountID const& accountID) const; bool checkExtraSigners(SignatureChecker& signatureChecker) const; MutableTxResultPtr checkValidWithOptionallyChargedFee( - Application& app, AbstractLedgerTxn& ltxOuter, SequenceNumber current, - bool chargeFee, uint64_t lowerBoundCloseTimeOffset, + AbstractLedgerTxn& ltxOuter, Config const& cfg, + SorobanNetworkConfig const* const sorobanCfg, + LedgerHeader const& header, SequenceNumber current, bool chargeFee, + uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset) const; MutableTxResultPtr checkValid(Application& app, AbstractLedgerTxn& ltxOuter, SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset) const override; + bool - checkSorobanResourceAndSetError(Application& app, uint32_t ledgerVersion, + checkSorobanResourceAndSetError(SorobanNetworkConfig const& sorobanConfig, + Config const& cfg, uint32_t ledgerVersion, MutableTxResultPtr txResult) const override; MutableTxResultPtr createSuccessResult() const override; @@ -266,7 +270,7 @@ class TransactionFrame : public TransactionFrameBase std::shared_ptr toStellarMessage() const override; LedgerTxnEntry loadAccount(AbstractLedgerTxn& ltx, - LedgerTxnHeader const& header, + LedgerHeader const& header, AccountID const& accountID) const; std::optional const getMinSeqNum() const override; diff --git a/src/transactions/TransactionFrameBase.h b/src/transactions/TransactionFrameBase.h index b7553b2cae..4e1f1ac0db 100644 --- a/src/transactions/TransactionFrameBase.h +++ b/src/transactions/TransactionFrameBase.h @@ -49,7 +49,8 @@ class TransactionFrameBase SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset) const = 0; virtual bool - checkSorobanResourceAndSetError(Application& app, uint32_t ledgerVersion, + checkSorobanResourceAndSetError(SorobanNetworkConfig const& sorobanConfig, + Config const& cfg, uint32_t ledgerVersion, MutableTxResultPtr txResult) const = 0; virtual MutableTxResultPtr createSuccessResult() const = 0; diff --git a/src/transactions/test/TransactionTestFrame.cpp b/src/transactions/test/TransactionTestFrame.cpp index db7496c48d..7193c949a8 100644 --- a/src/transactions/test/TransactionTestFrame.cpp +++ b/src/transactions/test/TransactionTestFrame.cpp @@ -129,10 +129,11 @@ TransactionTestFrame::checkValidForTesting(Application& app, bool TransactionTestFrame::checkSorobanResourceAndSetError( - Application& app, uint32_t ledgerVersion, MutableTxResultPtr txResult) const + SorobanNetworkConfig const& sorobanConfig, Config const& cfg, + uint32_t ledgerVersion, MutableTxResultPtr txResult) const { auto ret = mTransactionFrame->checkSorobanResourceAndSetError( - app, ledgerVersion, txResult); + sorobanConfig, cfg, ledgerVersion, txResult); mTransactionTxResult = txResult; return ret; } diff --git a/src/transactions/test/TransactionTestFrame.h b/src/transactions/test/TransactionTestFrame.h index 8729a8eaef..9cad80f051 100644 --- a/src/transactions/test/TransactionTestFrame.h +++ b/src/transactions/test/TransactionTestFrame.h @@ -66,7 +66,8 @@ class TransactionTestFrame : public TransactionFrameBase SequenceNumber current, uint64_t lowerBoundCloseTimeOffset, uint64_t upperBoundCloseTimeOffset) const override; bool - checkSorobanResourceAndSetError(Application& app, uint32_t ledgerVersion, + checkSorobanResourceAndSetError(SorobanNetworkConfig const& sorobanConfig, + Config const& cfg, uint32_t ledgerVersion, MutableTxResultPtr txResult) const override; MutableTxResultPtr createSuccessResult() const override;