Skip to content

Commit 427aa39

Browse files
dmkozhbboston7
authored andcommitted
Cleanup
1 parent e78c97e commit 427aa39

12 files changed

Lines changed: 175 additions & 118 deletions

File tree

src/herder/TxSetFrame.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ addWireTxsToList(Hash const& networkID,
419419
for (auto const& env : xdrTxs)
420420
{
421421
auto tx = TransactionFrameBase::makeTransactionFromWire(networkID, env);
422-
if (!tx->XDRProvidesValidFee())
422+
if (!tx->XDRProvidesValidFee() || tx->getInclusionFee() <= 0)
423423
{
424424
return false;
425425
}
@@ -1504,7 +1504,8 @@ TxSetPhaseFrame::makeFromWire(TxSetPhase phase, Hash const& networkID,
15041504
{
15051505
auto tx = TransactionFrameBase::makeTransactionFromWire(
15061506
networkID, env);
1507-
if (!tx->XDRProvidesValidFee())
1507+
if (!tx->XDRProvidesValidFee() ||
1508+
tx->getInclusionFee() <= 0)
15081509
{
15091510
CLOG_DEBUG(Herder, "Got bad generalized txSet: "
15101511
"transaction has invalid XDR");
@@ -1566,7 +1567,7 @@ TxSetPhaseFrame::makeFromWireLegacy(
15661567
CLOG_DEBUG(
15671568
Herder,
15681569
"Got bad legacy txSet: transactions are not ordered correctly "
1569-
"or contain invalid phase transactions");
1570+
"or contain invalid transactions");
15701571
return std::nullopt;
15711572
}
15721573
auto inclusionFeeMapPtr = std::make_shared<InclusionFeeMap>();

src/herder/test/HerderTests.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,62 @@ testTxSet(uint32 protocolVersion)
478478
TxSetValidationResult::TX_VALIDATION_FAILED);
479479
}
480480
}
481+
SECTION("negative inclusion fee tx")
482+
{
483+
auto sorobanTx =
484+
createUploadWasmTx(*app, *root, 100, 1000, SorobanResources{});
485+
auto negFeeSorobanTxEnvelope = sorobanTx->getEnvelope();
486+
negFeeSorobanTxEnvelope.v1().tx.fee = 1;
487+
auto negFeeBump = feeBump(*app, *root, sorobanTx, 1,
488+
/* useInclusionAsFullFee */ true);
489+
auto lclHeader =
490+
app->getLedgerManager().getLastClosedLedgerHeader();
491+
SECTION("legacy tx set")
492+
{
493+
// This is a regression test - legacy tx sets are not allowed in
494+
// new protocols, but Core still accepts them and it does some
495+
// tx-related validation before reaching the
496+
// `GENERALIZED_TXSET_MISMATCH` check.
497+
TransactionSet txSet;
498+
txSet.previousLedgerHash = lclHeader.hash;
499+
txSet.txs.push_back(negFeeSorobanTxEnvelope);
500+
auto applicableTxSet =
501+
TxSetXDRFrame::makeFromWire(txSet)->prepareForApply(
502+
*app, lclHeader.header);
503+
REQUIRE(applicableTxSet == nullptr);
504+
505+
txSet.txs[0] = negFeeBump->getEnvelope();
506+
auto applicableTxSet2 =
507+
TxSetXDRFrame::makeFromWire(txSet)->prepareForApply(
508+
*app, lclHeader.header);
509+
REQUIRE(applicableTxSet2 == nullptr);
510+
}
511+
SECTION("generalized tx set")
512+
{
513+
auto txSet =
514+
testtxset::makeNonValidatedGeneralizedTxSet(
515+
{{},
516+
{std::make_pair(
517+
std::nullopt,
518+
std::vector<TransactionFrameBasePtr>{
519+
TransactionFrameBase::makeTransactionFromWire(
520+
app->getNetworkID(),
521+
negFeeSorobanTxEnvelope)})}},
522+
*app, lclHeader.hash)
523+
.second;
524+
REQUIRE(txSet == nullptr);
525+
526+
auto txSet2 =
527+
testtxset::makeNonValidatedGeneralizedTxSet(
528+
{{},
529+
{std::make_pair(std::nullopt,
530+
std::vector<TransactionFrameBasePtr>{
531+
negFeeBump})}},
532+
*app, lclHeader.hash)
533+
.second;
534+
REQUIRE(txSet2 == nullptr);
535+
}
536+
}
481537
}
482538
}
483539

src/herder/test/TxSetTests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ TEST_CASE("generalized tx set XDR validation", "[txset]")
8383
txEnv.v1().tx.operations.emplace_back();
8484
// The fee is actually not relevant for XDR validation, we just use
8585
// it to have different tx envelopes.
86-
txEnv.v1().tx.fee = 100 + txId;
86+
txEnv.v1().tx.fee = 10000 + txId;
8787
++txId;
8888
txEnv.v1().tx.operations.back().body.type(
8989
isSoroban ? OperationType::INVOKE_HOST_FUNCTION

src/overlay/test/OverlayTests.cpp

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3371,7 +3371,7 @@ TEST_CASE("populateSignatureCache tests", "[overlay]")
33713371
REQUIRE(finalMisses == 0);
33723372
}
33733373

3374-
SECTION("Ed25519 signed payload signer skipped in overlay validation")
3374+
SECTION("Ed25519 signed payload signer cached during overlay validation")
33753375
{
33763376
// Add an ed25519 signed payload signer to testAccount and remove the
33773377
// master key, so the account can only be authorized via the payload
@@ -3404,18 +3404,19 @@ TEST_CASE("populateSignatureCache tests", "[overlay]")
34043404

34053405
resetCache();
34063406

3407-
// populateSignatureCache runs with isOverlayValidation=true, which
3408-
// skips ed25519 signed payload signers. So no cache entries should
3409-
// be produced.
34103407
invokePopulateSignatureCache(payTx);
34113408

34123409
uint64_t hits, misses;
34133410
PubKeyUtils::flushVerifySigCacheCounts(hits, misses);
3414-
REQUIRE(hits == 0);
3415-
REQUIRE(misses == 0);
3411+
REQUIRE(misses == 1);
3412+
// `populateSignatureCache` verifies the payload signature at the
3413+
// transaction level (cache miss, added to cache) and again at the
3414+
// operation level (cache hit from the first check within the same
3415+
// call).
3416+
REQUIRE(hits == 1);
34163417

3417-
// Now call checkValid (normal path), which DOES check payload
3418-
// signers. Since the cache was not populated, we should see a miss.
3418+
// checkValid now sees the cache already populated: both tx-level
3419+
// and op-level signed-payload lookups are pure cache hits.
34193420
LedgerTxn ltx(app->getLedgerTxnRoot());
34203421
auto ls = LedgerSnapshot(ltx);
34213422
auto diagnostics = DiagnosticEventManager::createDisabled();
@@ -3424,16 +3425,8 @@ TEST_CASE("populateSignatureCache tests", "[overlay]")
34243425
REQUIRE(result->isSuccess());
34253426

34263427
PubKeyUtils::flushVerifySigCacheCounts(hits, misses);
3427-
// The payload signer was not cached by populateSignatureCache, so
3428-
// checkValid must produce a cache miss for the payload signature.
3429-
// This contrasts with the "Normal transaction" test where
3430-
// populateSignatureCache caches the ed25519 signature and
3431-
// checkValid sees only cache hits (misses == 0).
3432-
REQUIRE(misses == 1);
3433-
// checkValid verifies the payload signature at the transaction
3434-
// level (cache miss, added to cache) and again at the operation
3435-
// level (cache hit from the first check within the same call).
3436-
REQUIRE(hits == 1);
3428+
REQUIRE(misses == 0);
3429+
REQUIRE(hits == 2);
34373430
}
34383431

34393432
SECTION("Signature cache invalidation after signer removal")

src/overlay/test/SurveyManagerTests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ TEST_CASE("Time sliced dynamic topology survey", "[overlay][survey][topology]")
811811
[&simulation, nLedgers]() {
812812
return simulation->haveAllExternalized(nLedgers + 1, 1);
813813
},
814-
10 * nLedgers * simulation->getExpectedLedgerCloseTime(), false);
814+
20 * nLedgers * simulation->getExpectedLedgerCloseTime(), false);
815815

816816
REQUIRE(simulation->haveAllExternalized(nLedgers + 1, 1));
817817

src/transactions/FeeBumpTransactionFrame.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,7 @@ FeeBumpTransactionFrame::checkSignature(SignatureChecker& signatureChecker,
240240
}
241241
signers.insert(signers.end(), acc.signers.begin(), acc.signers.end());
242242

243-
return signatureChecker.checkSignature(
244-
signers, neededWeight, !signatureChecker.isOverlayValidation());
243+
return signatureChecker.checkSignature(signers, neededWeight);
245244
}
246245

247246
bool

src/transactions/SignatureChecker.cpp

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,16 @@ SignatureChecker::isOverlayValidation() const
3939
return mIsOverlayValidation;
4040
}
4141

42+
bool
43+
SignatureChecker::isOverVerificationBudget() const
44+
{
45+
return mIsOverlayValidation &&
46+
mTxEd25519Verifications >= OVERLAY_TX_ED25519_VERIFY_BUDGET;
47+
}
48+
4249
bool
4350
SignatureChecker::checkSignature(std::vector<Signer> const& signersV,
44-
int neededWeight,
45-
bool checkEd25519SignedPayload)
51+
int neededWeight)
4652
{
4753
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
return true;
@@ -127,6 +133,10 @@ SignatureChecker::checkSignature(std::vector<Signer> const& signersV,
127133
verified =
128134
verifyAll(signers[SIGNER_KEY_TYPE_ED25519],
129135
[&](DecoratedSignature const& sig, Signer const& signerKey) {
136+
if (isOverVerificationBudget())
137+
{
138+
return false;
139+
}
130140
auto [valid, cacheLookupRes] = SignatureUtils::verify(
131141
sig, signerKey.key, mContentsHash);
132142
updateTxSigCacheMetrics(cacheLookupRes);
@@ -136,26 +146,26 @@ SignatureChecker::checkSignature(std::vector<Signer> const& signersV,
136146
{
137147
return true;
138148
}
139-
140-
if (checkEd25519SignedPayload)
149+
if (isOverVerificationBudget())
141150
{
142-
verified = verifyAll(
143-
signers[SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD],
144-
[&](DecoratedSignature const& sig, Signer const& signerKey) {
145-
auto [valid, cacheLookupRes] =
146-
SignatureUtils::verifyEd25519SignedPayload(sig,
147-
signerKey.key);
148-
updateTxSigCacheMetrics(cacheLookupRes);
149-
return valid;
150-
});
151-
if (verified)
152-
{
153-
return true;
154-
}
151+
return false;
155152
}
156-
else
153+
154+
verified = verifyAll(
155+
signers[SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD],
156+
[&](DecoratedSignature const& sig, Signer const& signerKey) {
157+
if (isOverVerificationBudget())
158+
{
159+
return false;
160+
}
161+
auto [valid, cacheLookupRes] =
162+
SignatureUtils::verifyEd25519SignedPayload(sig, signerKey.key);
163+
updateTxSigCacheMetrics(cacheLookupRes);
164+
return valid;
165+
});
166+
if (verified)
157167
{
158-
releaseAssert(mIsOverlayValidation);
168+
return true;
159169
}
160170

161171
return false;
@@ -204,6 +214,11 @@ void
204214
SignatureChecker::updateTxSigCacheMetrics(
205215
PubKeyUtils::VerifySigCacheLookupResult cacheLookupRes)
206216
{
217+
if (cacheLookupRes != PubKeyUtils::VerifySigCacheLookupResult::NO_LOOKUP)
218+
{
219+
++mTxEd25519Verifications;
220+
}
221+
207222
if (!mTrackCacheMetrics)
208223
{
209224
return;

src/transactions/SignatureChecker.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include "xdr/Stellar-transaction.h"
1010
#include "xdr/Stellar-types.h"
1111

12-
#include <map>
1312
#include <set>
1413
#include <stdint.h>
1514
#include <vector>
@@ -26,8 +25,7 @@ class SignatureChecker
2625
bool isOverlayValidation = false);
2726
#ifdef BUILD_TESTS
2827
virtual bool checkSignature(std::vector<Signer> const& signersV,
29-
int32_t neededWeight,
30-
bool checkEd25519SignedPayload = true);
28+
int32_t neededWeight);
3129
virtual bool checkAllSignaturesUsed() const;
3230
virtual ~SignatureChecker() = default;
3331

@@ -37,8 +35,7 @@ class SignatureChecker
3735
virtual void disableCacheMetricsTracking();
3836
#else
3937
bool checkSignature(std::vector<Signer> const& signersV,
40-
int32_t neededWeight,
41-
bool checkEd25519SignedPayload = true);
38+
int32_t neededWeight);
4239
bool checkAllSignaturesUsed() const;
4340

4441
// Do not record signature cache metrics for this instance. This should be
@@ -47,6 +44,7 @@ class SignatureChecker
4744
#endif // BUILD_TESTS
4845

4946
bool isOverlayValidation() const;
47+
static constexpr uint32_t OVERLAY_TX_ED25519_VERIFY_BUDGET = 1000;
5048

5149
// Reset and return the counts of signature checks performed as part of
5250
// transaction `checkValid` or apply flow. The first element of the pair is
@@ -62,6 +60,9 @@ class SignatureChecker
6260
bool mIsOverlayValidation{false};
6361

6462
std::vector<bool> mUsedSignatures;
63+
uint32_t mTxEd25519Verifications{0};
64+
65+
bool isOverVerificationBudget() const;
6566

6667
// Static fields for tracking signature verification cache performance
6768
// during the `checkValid` or apply flow
@@ -90,7 +91,7 @@ class AlwaysValidSignatureChecker : public SignatureChecker
9091
}
9192

9293
bool
93-
checkSignature(std::vector<Signer> const&, int32_t, bool) override
94+
checkSignature(std::vector<Signer> const&, int32_t) override
9495
{
9596
return true;
9697
}

src/transactions/TransactionFrame.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -511,8 +511,7 @@ TransactionFrame::checkSignature(SignatureChecker& signatureChecker,
511511
}
512512
signers.insert(signers.end(), acc.signers.begin(), acc.signers.end());
513513

514-
return signatureChecker.checkSignature(
515-
signers, neededWeight, !signatureChecker.isOverlayValidation());
514+
return signatureChecker.checkSignature(signers, neededWeight);
516515
}
517516

518517
bool
@@ -547,7 +546,7 @@ TransactionFrame::checkExtraSigners(SignatureChecker& signatureChecker) const
547546
// we assign a weight of 1 to each key, and set the neededWeight to the
548547
// number of extraSigners
549548
return signatureChecker.checkSignature(
550-
signers, static_cast<int32_t>(signers.size()), true);
549+
signers, static_cast<int32_t>(signers.size()));
551550
}
552551
return true;
553552
}

src/transactions/test/TxEnvelopeTests.cpp

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,7 +2478,7 @@ TEST_CASE_VERSIONS("txenvelope", "[tx][envelope]")
24782478
}
24792479
}
24802480

2481-
TEST_CASE_VERSIONS("overlay validation skips ed25519 signed payload signers",
2481+
TEST_CASE_VERSIONS("overlay validation handles ed25519 signed payload signers",
24822482
"[tx][envelope][overlay]")
24832483
{
24842484
Config cfg = getTestConfig(0, Config::TESTDB_IN_MEMORY);
@@ -2489,9 +2489,8 @@ TEST_CASE_VERSIONS("overlay validation skips ed25519 signed payload signers",
24892489

24902490
int64_t const paymentAmount = app->getLedgerManager().getLastReserve() * 10;
24912491

2492-
// This test validates that checkValidForOverlay skips
2493-
// SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD verification, while checkValid
2494-
// (used during txset validation and apply) does not.
2492+
// This test validates that checkValidForOverlay verifies
2493+
// SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD signers normally
24952494
for_versions_from(19, *app, [&] {
24962495
auto a1 = root->create("a1", paymentAmount);
24972496

@@ -2537,18 +2536,14 @@ TEST_CASE_VERSIONS("overlay validation skips ed25519 signed payload signers",
25372536
REQUIRE(tx->getResultCode() == txSUCCESS);
25382537
}
25392538

2540-
SECTION("checkValidForOverlay rejects ed25519 signed payload signer")
2539+
SECTION("checkValidForOverlay accepts ed25519 signed payload signer")
25412540
{
2542-
// Overlay validation skips payload signer checking, so a tx
2543-
// authorized only via payload signer should fail overlay
2544-
// validation
25452541
LedgerTxn ltx(app->getLedgerTxnRoot());
25462542
auto ls = LedgerSnapshot(ltx);
25472543
auto diagnostics = DiagnosticEventManager::createDisabled();
25482544
auto result = tx->checkValidForOverlay(app->getAppConnector(), ls,
25492545
0, 0, 0, diagnostics);
2550-
REQUIRE(!result->isSuccess());
2551-
REQUIRE(result->getResultCode() == txBAD_AUTH);
2546+
REQUIRE(result->isSuccess());
25522547
}
25532548

25542549
SECTION("fee bump with ed25519 signed payload signer on inner tx")
@@ -2567,16 +2562,14 @@ TEST_CASE_VERSIONS("overlay validation skips ed25519 signed payload signers",
25672562
REQUIRE(result->isSuccess());
25682563
}
25692564

2570-
SECTION("checkValidForOverlay rejects fee bump")
2565+
SECTION("checkValidForOverlay accepts fee bump")
25712566
{
25722567
LedgerTxn ltx(app->getLedgerTxnRoot());
25732568
auto ls = LedgerSnapshot(ltx);
25742569
auto diagnostics = DiagnosticEventManager::createDisabled();
25752570
auto result = feeBumpTx->checkValidForOverlay(
25762571
app->getAppConnector(), ls, 0, 0, 0, diagnostics);
2577-
REQUIRE(!result->isSuccess());
2578-
// Fee bump wraps the inner failure
2579-
REQUIRE(result->getResultCode() == txFEE_BUMP_INNER_FAILED);
2572+
REQUIRE(result->isSuccess());
25802573
}
25812574
}
25822575
});

0 commit comments

Comments
 (0)