From 363ca1a424afdc4642c2b957f24e9591a8fa9e7a Mon Sep 17 00:00:00 2001 From: Dmytro Kozhevin Date: Mon, 16 Dec 2024 18:57:25 -0500 Subject: [PATCH] Some Soroban loadgen/test fixes. - Increase the refundable fee for Wasm uploads - Revert the accidental default instructions change - Add some fixes to the loadgen test to (hopefully) ensure there are no failures --- Builds/VisualStudio/stellar-core.vcxproj | 8 +-- .../VisualStudio/stellar-core.vcxproj.filters | 24 +++---- src/simulation/TxGenerator.cpp | 29 ++++---- src/simulation/test/LoadGeneratorTests.cpp | 72 ++----------------- 4 files changed, 37 insertions(+), 96 deletions(-) diff --git a/Builds/VisualStudio/stellar-core.vcxproj b/Builds/VisualStudio/stellar-core.vcxproj index d7641cdd7e..7f2ecfb9c4 100644 --- a/Builds/VisualStudio/stellar-core.vcxproj +++ b/Builds/VisualStudio/stellar-core.vcxproj @@ -616,8 +616,6 @@ exit /b 0 - - @@ -639,6 +637,8 @@ exit /b 0 + + @@ -1068,8 +1068,6 @@ exit /b 0 - - @@ -1085,6 +1083,8 @@ exit /b 0 + + diff --git a/Builds/VisualStudio/stellar-core.vcxproj.filters b/Builds/VisualStudio/stellar-core.vcxproj.filters index 4ef8433844..bafcf17ed5 100644 --- a/Builds/VisualStudio/stellar-core.vcxproj.filters +++ b/Builds/VisualStudio/stellar-core.vcxproj.filters @@ -900,12 +900,6 @@ ledger - - ledger - - - ledger - ledger @@ -1401,6 +1395,12 @@ bucket + + ledger\tests + + + ledger\tests + @@ -2096,12 +2096,6 @@ ledger - - ledger - - - ledger - ledger @@ -2449,6 +2443,12 @@ bucket + + ledger\tests + + + ledger\tests + diff --git a/src/simulation/TxGenerator.cpp b/src/simulation/TxGenerator.cpp index f00578628b..ac327bddb2 100644 --- a/src/simulation/TxGenerator.cpp +++ b/src/simulation/TxGenerator.cpp @@ -19,7 +19,7 @@ constexpr uint32_t DEFAULT_WASM_BYTES = 35 * 1024; constexpr uint32_t DEFAULT_NUM_DATA_ENTRIES = 2; constexpr uint32_t DEFAULT_IO_KILOBYTES = 1; constexpr uint32_t DEFAULT_TX_SIZE_BYTES = 256; -constexpr uint64_t DEFAULT_INSTRUCTIONS = 28'000'000; +constexpr uint32_t DEFAULT_INSTRUCTIONS = 28'000'000; // Sample from a discrete distribution of `values` with weights `weights`. // Returns `defaultValue` if `values` is empty. @@ -373,16 +373,16 @@ TxGenerator::invokeSorobanLoadTransaction( // instruction count is not perfect. Some TXs will fail due to exceeding // resource limitations, but failures will be rare and those failures // will happen at apply time, so they will still generate significant load. - uint64_t const baseInstructionCount = 1'500'000; - uint64_t const instructionsPerGuestCycle = 80; - uint64_t const instructionsPerHostCycle = 5030; + uint32_t const baseInstructionCount = 1'500'000; + uint32_t const instructionsPerGuestCycle = 80; + uint32_t const instructionsPerHostCycle = 5030; // Very rough estimates. - uint64_t const instructionsPerKbWritten = 50000; + uint32_t const instructionsPerKbWritten = 50000; // instructionsPerPaddingByte is just a value we know works. We use an auth // payload as padding, so it consumes instructions on the host side. - uint64_t const instructionsPerPaddingByte = 100; + uint32_t const instructionsPerPaddingByte = 100; SorobanResources resources; resources.footprint.readOnly = instance.readOnlyKeys; @@ -451,9 +451,10 @@ TxGenerator::invokeSorobanLoadTransaction( instructionsPerPaddingByte * paddingBytes; // Pick random number of cycles between bounds - uint64_t targetInstructions = sampleDiscrete( - appCfg.LOADGEN_INSTRUCTIONS_FOR_TESTING, - appCfg.LOADGEN_INSTRUCTIONS_DISTRIBUTION_FOR_TESTING, 0u); + uint32_t targetInstructions = + sampleDiscrete(appCfg.LOADGEN_INSTRUCTIONS_FOR_TESTING, + appCfg.LOADGEN_INSTRUCTIONS_DISTRIBUTION_FOR_TESTING, + DEFAULT_INSTRUCTIONS); // Factor in instructions for storage targetInstructions = baseInstructionCount + instructionsForStorageAndAuth >= @@ -463,12 +464,12 @@ TxGenerator::invokeSorobanLoadTransaction( instructionsForStorageAndAuth; // Randomly select a number of guest cycles - uint64_t guestCyclesMax = targetInstructions / instructionsPerGuestCycle; - uint64_t guestCycles = rand_uniform(0, guestCyclesMax); + uint32_t guestCyclesMax = targetInstructions / instructionsPerGuestCycle; + uint32_t guestCycles = rand_uniform(0, guestCyclesMax); // Rest of instructions consumed by host cycles targetInstructions -= guestCycles * instructionsPerGuestCycle; - uint64_t hostCycles = targetInstructions / instructionsPerHostCycle; + uint32_t hostCycles = targetInstructions / instructionsPerHostCycle; auto guestCyclesU64 = makeU64(guestCycles); auto hostCyclesU64 = makeU64(hostCycles); @@ -490,7 +491,7 @@ TxGenerator::invokeSorobanLoadTransaction( increaseOpSize(op, paddingBytes); - int64_t instructionCount = + uint32_t instructionCount = baseInstructionCount + hostCycles * instructionsPerHostCycle + guestCycles * instructionsPerGuestCycle + instructionsForStorageAndAuth; resources.instructions = instructionCount; @@ -995,7 +996,7 @@ TxGenerator::sorobanRandomWasmTransaction(uint32_t ledgerNum, int64_t resourceFee = sorobanResourceFee( mApp, resources, 5000 + static_cast(wasmSize), 100); // Roughly cover the rent fee. - resourceFee += 100000; + resourceFee += 1'000'000; auto tx = sorobanTransactionFrameFromOps(mApp.getNetworkID(), *account, {uploadOp}, {}, resources, inclusionFee, resourceFee); diff --git a/src/simulation/test/LoadGeneratorTests.cpp b/src/simulation/test/LoadGeneratorTests.cpp index 5cc05ee820..276e2000b8 100644 --- a/src/simulation/test/LoadGeneratorTests.cpp +++ b/src/simulation/test/LoadGeneratorTests.cpp @@ -456,7 +456,7 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") cfg.mTxMaxSizeBytes * cfg.mLedgerMaxTxCount; }, simulation); - auto const numInstances = 10; + auto const numInstances = nAccounts; auto const numSorobanTxs = 100; numTxsBefore = getSuccessfulTxCount(); @@ -490,8 +490,7 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") /* txRate */ 1); invokeLoadCfg.getMutSorobanConfig().nInstances = numInstances; - constexpr int maxInvokeFail = 10; - invokeLoadCfg.setMinSorobanPercentSuccess(100 - maxInvokeFail); + invokeLoadCfg.setMinSorobanPercentSuccess(100); loadGen.generateLoad(invokeLoadCfg); completeCount = complete.count(); @@ -506,15 +505,8 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") {"ledger", "apply-soroban", "success"}); auto& txsFailed = node->getMetrics().NewCounter( {"ledger", "apply-soroban", "failure"}); - - // Because we can't preflight TXs, some invocations will fail due to too - // few resources. This is expected, as our instruction counts are - // approximations. The following checks will make sure all set up - // phases succeeded, so only the invoke phase may have acceptable failed - // TXs - REQUIRE(txsSucceeded.count() > - numTxsBefore + numSorobanTxs - maxInvokeFail); - REQUIRE(txsFailed.count() < maxInvokeFail); + REQUIRE(txsSucceeded.count() == numTxsBefore + numSorobanTxs); + REQUIRE(txsFailed.count() == 0); } auto instanceKeys = loadGen.getContractInstanceKeysForTesting(); @@ -576,16 +568,7 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") constexpr uint32_t uploadWeight = 5; mixCfg.sorobanUploadWeight = uploadWeight; - // Because we can't preflight TXs, some invocations will fail due to too - // few resources. This is expected, as our instruction counts are - // approximations. Additionally, many upload transactions will fail as - // they are likely to generate invalid wasm. Therefore, we check that - // all but `maxInvokeFail + 1.5 * uploadWeight` transactions succeed. In - // case the random sampling produces more upload transactions than - // expected, we allow for a 50% margin of error on the number of upload - // transactions. - constexpr int maxSorobanFail = 1.5 * uploadWeight + maxInvokeFail; - mixLoadCfg.setMinSorobanPercentSuccess(100 - maxSorobanFail); + mixLoadCfg.setMinSorobanPercentSuccess(100); loadGen.generateLoad(mixLoadCfg); auto numSuccessBefore = getSuccessfulTxCount(); @@ -601,54 +584,11 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") // Check results for (auto node : nodes) { - auto& totalSucceeded = - node->getMetrics().NewCounter({"ledger", "apply", "success"}); auto& totalFailed = node->getMetrics().NewCounter({"ledger", "apply", "failure"}); - auto& sorobanSucceeded = node->getMetrics().NewCounter( - {"ledger", "apply-soroban", "success"}); - auto& sorobanFailed = node->getMetrics().NewCounter( - {"ledger", "apply-soroban", "failure"}); - - // Total number of classic transactions - int64_t classicTotal = - totalSucceeded.count() + totalFailed.count() - - sorobanSucceeded.count() - sorobanFailed.count(); - - // All classic transaction should succeed - REQUIRE(totalSucceeded.count() - sorobanSucceeded.count() == - classicTotal); - // All failures should be soroban failures) - REQUIRE(totalFailed.count() == sorobanFailed.count()); - - // Check soroban results - REQUIRE(sorobanSucceeded.count() > numSuccessBefore + numMixedTxs - - classicTotal - - maxSorobanFail); - REQUIRE(sorobanFailed.count() <= maxSorobanFail + numFailedBefore); + REQUIRE(totalFailed.count() == 0); } } - - // Test minimum percent success with too many transactions that fail to - // apply by requiring a 100% success rate for SOROBAN_UPLOAD mode - SECTION("Too many failed transactions") - { - auto uploadFailCfg = GeneratedLoadConfig::txLoad( - LoadGenMode::SOROBAN_UPLOAD, nAccounts, numSorobanTxs, - /* txRate */ 1); - - // Set success percentage to 100% and leave other parameters at default. - uploadFailCfg.setMinSorobanPercentSuccess(100); - - // LoadGen should fail - loadGen.generateLoad(uploadFailCfg); - auto& fail = - app.getMetrics().NewMeter({"loadgen", "run", "failed"}, "run"); - auto failCount = fail.count(); - simulation->crankUntil([&]() { return fail.count() == failCount + 1; }, - 300 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, - false); - } } TEST_CASE("Multi-op pretend transactions are valid", "[loadgen]")