diff --git a/src/bucket/test/BucketIndexTests.cpp b/src/bucket/test/BucketIndexTests.cpp index 3365bdbb92..1955fa9ab4 100644 --- a/src/bucket/test/BucketIndexTests.cpp +++ b/src/bucket/test/BucketIndexTests.cpp @@ -111,7 +111,9 @@ class BucketIndexTest runHistoricalSnapshotTest() { uint32_t ledger = 0; - auto canonicalEntry = LedgerTestUtils::generateValidLedgerEntry(); + auto canonicalEntry = + LedgerTestUtils::generateValidLedgerEntryWithExclusions( + {LedgerEntryType::CONFIG_SETTING}); canonicalEntry.lastModifiedLedgerSeq = 0; do diff --git a/src/herder/TransactionQueue.h b/src/herder/TransactionQueue.h index a58573a1a3..4d531a68f2 100644 --- a/src/herder/TransactionQueue.h +++ b/src/herder/TransactionQueue.h @@ -259,6 +259,14 @@ class SorobanTransactionQueue : public TransactionQueue } size_t getMaxQueueSizeOps() const override; +#ifdef BUILD_TESTS + void + clearBroadcastCarryover() + { + mBroadcastOpCarryover.clear(); + mBroadcastOpCarryover.resize(1, Resource::makeEmptySoroban()); + } +#endif private: virtual std::pair> diff --git a/src/herder/Upgrades.h b/src/herder/Upgrades.h index b182d5b7ef..4fcfaca646 100644 --- a/src/herder/Upgrades.h +++ b/src/herder/Upgrades.h @@ -159,6 +159,8 @@ class ConfigUpgradeSetFrame static ConfigUpgradeSetFrameConstPtr makeFromKey(AbstractLedgerTxn& ltx, ConfigUpgradeSetKey const& key); + static LedgerKey getLedgerKey(ConfigUpgradeSetKey const& upgradeKey); + ConfigUpgradeSet const& toXDR() const; ConfigUpgradeSetKey const& getKey() const; @@ -182,8 +184,6 @@ class ConfigUpgradeSetFrame ConfigUpgradeSetKey const& key, uint32_t ledgerVersion); - static LedgerKey getLedgerKey(ConfigUpgradeSetKey const& upgradeKey); - bool isValidXDR(ConfigUpgradeSet const& upgradeSetXDR, ConfigUpgradeSetKey const& key) const; diff --git a/src/herder/test/HerderTests.cpp b/src/herder/test/HerderTests.cpp index b0c37e1b13..cd302b8242 100644 --- a/src/herder/test/HerderTests.cpp +++ b/src/herder/test/HerderTests.cpp @@ -3213,24 +3213,22 @@ TEST_CASE("soroban txs each parameter surge priced", "[soroban][herder]") }); simulation->startAllNodes(); auto nodes = simulation->getNodes(); - for (auto& node : nodes) - { - overrideSorobanNetworkConfigForTest(*node); - modifySorobanNetworkConfig( - *node, [&tweakSorobanConfig](SorobanNetworkConfig& cfg) { - auto mx = std::numeric_limits::max(); - // Set all Soroban resources to maximum initially; each - // section will adjust the config as desired - cfg.mLedgerMaxTxCount = mx; - cfg.mLedgerMaxInstructions = mx; - cfg.mLedgerMaxTransactionsSizeBytes = mx; - cfg.mLedgerMaxReadLedgerEntries = mx; - cfg.mLedgerMaxReadBytes = mx; - cfg.mLedgerMaxWriteLedgerEntries = mx; - cfg.mLedgerMaxWriteBytes = mx; - tweakSorobanConfig(cfg); - }); - } + upgradeSorobanNetworkConfig( + [&tweakSorobanConfig](SorobanNetworkConfig& cfg) { + setSorobanNetworkConfigForTest(cfg); + auto mx = std::numeric_limits::max(); + // Set all Soroban resources to maximum initially; each + // section will adjust the config as desired + cfg.mLedgerMaxTxCount = mx; + cfg.mLedgerMaxInstructions = mx; + cfg.mLedgerMaxTransactionsSizeBytes = mx; + cfg.mLedgerMaxReadLedgerEntries = mx; + cfg.mLedgerMaxReadBytes = mx; + cfg.mLedgerMaxWriteLedgerEntries = mx; + cfg.mLedgerMaxWriteBytes = mx; + tweakSorobanConfig(cfg); + }, + simulation); auto& loadGen = nodes[0]->getLoadGenerator(); // Generate some accounts @@ -3513,20 +3511,19 @@ TEST_CASE("overlay parallel processing") uint32_t desiredTxRate = 1; uint32_t ledgerWideLimit = static_cast( desiredTxRate * Herder::EXP_LEDGER_TIMESPAN_SECONDS.count() * 2); - uint32_t const numAccounts = 100; - for (auto& node : nodes) - { - overrideSorobanNetworkConfigForTest(*node); - modifySorobanNetworkConfig(*node, [&](SorobanNetworkConfig& cfg) { + upgradeSorobanNetworkConfig( + [&](SorobanNetworkConfig& cfg) { + setSorobanNetworkConfigForTest(cfg); cfg.mLedgerMaxTxCount = ledgerWideLimit; - }); - } + }, + simulation); auto& loadGen = nodes[0]->getLoadGenerator(); // Generate some accounts auto& loadGenDone = nodes[0]->getMetrics().NewMeter({"loadgen", "run", "complete"}, "run"); auto currLoadGenCount = loadGenDone.count(); + uint32_t const numAccounts = 100; loadGen.generateLoad( GeneratedLoadConfig::createAccountsLoad(numAccounts, desiredTxRate)); simulation->crankUntil( @@ -3583,13 +3580,13 @@ TEST_CASE("soroban txs accepted by the network", uint32_t ledgerWideLimit = static_cast( desiredTxRate * Herder::EXP_LEDGER_TIMESPAN_SECONDS.count() * 2); uint32_t const numAccounts = 100; - for (auto& node : nodes) - { - overrideSorobanNetworkConfigForTest(*node); - modifySorobanNetworkConfig(*node, [&](SorobanNetworkConfig& cfg) { + upgradeSorobanNetworkConfig( + [&](SorobanNetworkConfig& cfg) { + setSorobanNetworkConfigForTest(cfg); cfg.mLedgerMaxTxCount = ledgerWideLimit; - }); - } + }, + simulation); + auto& loadGen = nodes[0]->getLoadGenerator(); auto& txsSucceeded = nodes[0]->getMetrics().NewCounter({"ledger", "apply", "success"}); @@ -3610,6 +3607,7 @@ TEST_CASE("soroban txs accepted by the network", [&]() { return loadGenDone.count() > currLoadGenCount; }, 10 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); + uint64_t lastSorobanSucceeded = sorobanTxsSucceeded.count(); uint64_t lastSucceeded = txsSucceeded.count(); REQUIRE(lastSucceeded > 0); REQUIRE(txsFailed.count() == 0); @@ -3749,8 +3747,9 @@ TEST_CASE("soroban txs accepted by the network", REQUIRE(secondLoadGenFailed.count() == 0); // Check all classic txs got applied REQUIRE(txsSucceeded.count() - lastSucceeded - - sorobanTxsSucceeded.count() == - classicTxCount); + sorobanTxsSucceeded.count() + + lastSorobanSucceeded /* to prevent double counting */ + == classicTxCount); REQUIRE(txsFailed.count() == sorobanTxsFailed.count()); } } @@ -3862,16 +3861,15 @@ herderExternalizesValuesWithProtocol(uint32_t version) REQUIRE(getC()->getHerder().getState() == Herder::State::HERDER_BOOTING_STATE); + simulation->startAllNodes(); if (protocolVersionStartsFrom(version, SOROBAN_PROTOCOL_VERSION)) { - for (auto const& node : simulation->getNodes()) - { - modifySorobanNetworkConfig(*node, [&](SorobanNetworkConfig& cfg) { + upgradeSorobanNetworkConfig( + [&](SorobanNetworkConfig& cfg) { cfg.mStateArchivalSettings.bucketListWindowSamplePeriod = 1; - }); - } + }, + simulation); } - simulation->startAllNodes(); // After SCP is restored, Herder is tracking REQUIRE(getC()->getHerder().getState() == @@ -3933,7 +3931,7 @@ herderExternalizesValuesWithProtocol(uint32_t version) return currentALedger(); }; - uint32_t currentLedger = 1; + uint32_t currentLedger = currentBLedger(); REQUIRE(currentALedger() == currentLedger); REQUIRE(currentCLedger() == currentLedger); @@ -4192,12 +4190,6 @@ herderExternalizesValuesWithProtocol(uint32_t version) simulation->removeNode(validatorCKey.getPublicKey()); configC.MAX_SLOTS_TO_REMEMBER += 5; auto newC = simulation->addNode(validatorCKey, qset, &configC, false); - if (protocolVersionStartsFrom(version, SOROBAN_PROTOCOL_VERSION)) - { - modifySorobanNetworkConfig(*newC, [&](SorobanNetworkConfig& cfg) { - cfg.mStateArchivalSettings.bucketListWindowSamplePeriod = 1; - }); - } newC->start(); HerderImpl& newHerderC = *static_cast(&newC->getHerder()); @@ -4208,7 +4200,6 @@ herderExternalizesValuesWithProtocol(uint32_t version) SECTION("tracking") { receiveLedger(destinationLedger, newHerderC); - checkHerder(*newC, newHerderC, Herder::State::HERDER_TRACKING_NETWORK_STATE, currentlyTracking); @@ -4641,8 +4632,8 @@ TEST_CASE("do not flood too many soroban transactions", Simulation::OVER_LOOPBACK, networkID, [&](int i) { auto cfg = getTestConfig(i); cfg.TESTING_UPGRADE_MAX_TX_SET_SIZE = 1000; - cfg.NODE_IS_VALIDATOR = false; - cfg.FORCE_SCP = false; + cfg.NODE_IS_VALIDATOR = true; + cfg.FORCE_SCP = true; cfg.FLOOD_TX_PERIOD_MS = 100; cfg.FLOOD_OP_RATE_PER_LEDGER = 2.0; cfg.FLOOD_SOROBAN_TX_PERIOD_MS = 50; @@ -4654,32 +4645,30 @@ TEST_CASE("do not flood too many soroban transactions", auto otherKey = SecretKey::fromSeed(sha256("other")); SCPQuorumSet qset; - qset.threshold = 1; + qset.threshold = 2; qset.validators.push_back(mainKey.getPublicKey()); + qset.validators.push_back(otherKey.getPublicKey()); simulation->addNode(mainKey, qset); simulation->addNode(otherKey, qset); - auto updateSorobanConfig = [](Application& app) { - overrideSorobanNetworkConfigForTest(app); - modifySorobanNetworkConfig(app, [](SorobanNetworkConfig& cfg) { - // Update read entries to allow flooding at most 1 tx per broadcast - // interval. - cfg.mLedgerMaxReadLedgerEntries = 40; - cfg.mLedgerMaxReadBytes = cfg.mTxMaxReadBytes; - }); - }; - auto app = simulation->getNode(mainKey.getPublicKey()); - updateSorobanConfig(*app); - updateSorobanConfig(*simulation->getNode(otherKey.getPublicKey())); - simulation->addPendingConnection(mainKey.getPublicKey(), otherKey.getPublicKey()); simulation->startAllNodes(); simulation->crankForAtLeast(std::chrono::seconds(1), false); + upgradeSorobanNetworkConfig( + [&](SorobanNetworkConfig& cfg) { + setSorobanNetworkConfigForTest(cfg); + // Update read entries to allow flooding at most 1 tx per broadcast + // interval. + cfg.mLedgerMaxReadLedgerEntries = 40; + cfg.mLedgerMaxReadBytes = cfg.mTxMaxReadBytes; + }, + simulation); + auto const& cfg = app->getConfig(); auto& lm = app->getLedgerManager(); auto& herder = static_cast(app->getHerder()); @@ -4769,6 +4758,8 @@ TEST_CASE("do not flood too many soroban transactions", { // no broadcast right away REQUIRE(numBroadcast == 0); + tq.clearBroadcastCarryover(); + // wait for a bit more than a broadcast period // rate per period is 100 ms auto broadcastPeriod = diff --git a/src/ledger/NetworkConfig.cpp b/src/ledger/NetworkConfig.cpp index fb2eed5303..b61328a772 100644 --- a/src/ledger/NetworkConfig.cpp +++ b/src/ledger/NetworkConfig.cpp @@ -1330,6 +1330,22 @@ SorobanNetworkConfig::bucketListTargetSizeBytes() const return mBucketListTargetSizeBytes; } +int64_t +SorobanNetworkConfig::writeFee1KBBucketListLow() const +{ + return mWriteFee1KBBucketListLow; +} +int64_t +SorobanNetworkConfig::writeFee1KBBucketListHigh() const +{ + return mWriteFee1KBBucketListHigh; +} +uint32_t +SorobanNetworkConfig::bucketListWriteFeeGrowthFactor() const +{ + return mBucketListWriteFeeGrowthFactor; +} + // Historical data (pushed to core archives) settings for contracts. int64_t SorobanNetworkConfig::feeHistorical1KB() const @@ -1712,4 +1728,59 @@ SorobanNetworkConfig::computeWriteFee(uint32_t configMaxProtocol, mFeeWrite1KB = rust_bridge::compute_write_fee_per_1kb( configMaxProtocol, protocolVersion, mAverageBucketListSize, feeConfig); } + +bool +SorobanNetworkConfig::operator==(SorobanNetworkConfig const& other) const +{ + return mMaxContractSizeBytes == other.maxContractSizeBytes() && + mMaxContractDataKeySizeBytes == + other.maxContractDataKeySizeBytes() && + mMaxContractDataEntrySizeBytes == + other.maxContractDataEntrySizeBytes() && + + mLedgerMaxInstructions == other.ledgerMaxInstructions() && + mTxMaxInstructions == other.txMaxInstructions() && + mFeeRatePerInstructionsIncrement == + other.feeRatePerInstructionsIncrement() && + mTxMemoryLimit == other.txMemoryLimit() && + + mLedgerMaxReadLedgerEntries == other.ledgerMaxReadLedgerEntries() && + mLedgerMaxReadBytes == other.ledgerMaxReadBytes() && + mLedgerMaxWriteLedgerEntries == + other.ledgerMaxWriteLedgerEntries() && + mLedgerMaxWriteBytes == other.ledgerMaxWriteBytes() && + mLedgerMaxTxCount == other.ledgerMaxTxCount() && + + mTxMaxReadLedgerEntries == other.txMaxReadLedgerEntries() && + mTxMaxReadBytes == other.txMaxReadBytes() && + mTxMaxWriteLedgerEntries == other.txMaxWriteLedgerEntries() && + mTxMaxWriteBytes == other.txMaxWriteBytes() && + mFeeReadLedgerEntry == other.feeReadLedgerEntry() && + mFeeWriteLedgerEntry == other.feeWriteLedgerEntry() && + mFeeRead1KB == other.feeRead1KB() && + mBucketListTargetSizeBytes == other.bucketListTargetSizeBytes() && + + mWriteFee1KBBucketListLow == other.writeFee1KBBucketListLow() && + mWriteFee1KBBucketListHigh == other.writeFee1KBBucketListHigh() && + mBucketListWriteFeeGrowthFactor == + other.bucketListWriteFeeGrowthFactor() && + + mFeeHistorical1KB == other.feeHistorical1KB() && + + mTxMaxContractEventsSizeBytes == + other.txMaxContractEventsSizeBytes() && + mFeeContractEvents1KB == other.feeContractEventsSize1KB() && + + mLedgerMaxTransactionsSizeBytes == + other.ledgerMaxTransactionSizesBytes() && + mTxMaxSizeBytes == other.txMaxSizeBytes() && + mFeeTransactionSize1KB == other.feeTransactionSize1KB() && + + mCpuCostParams == other.cpuCostParams() && + mMemCostParams == other.memCostParams() && + + mStateArchivalSettings == other.stateArchivalSettings() && + mEvictionIterator == other.evictionIterator(); +} + } // namespace stellar diff --git a/src/ledger/NetworkConfig.h b/src/ledger/NetworkConfig.h index a005e9367f..9be7a290ec 100644 --- a/src/ledger/NetworkConfig.h +++ b/src/ledger/NetworkConfig.h @@ -270,6 +270,9 @@ class SorobanNetworkConfig int64_t feeWrite1KB() const; // Bucket list target size (in bytes) int64_t bucketListTargetSizeBytes() const; + int64_t writeFee1KBBucketListLow() const; + int64_t writeFee1KBBucketListHigh() const; + uint32_t bucketListWriteFeeGrowthFactor() const; // Historical data (pushed to core archives) settings for contracts. // Fee for storing 1KB in archives @@ -328,6 +331,7 @@ class SorobanNetworkConfig StateArchivalSettings& stateArchivalSettings(); EvictionIterator& evictionIterator(); #endif + bool operator==(SorobanNetworkConfig const& other) const; private: void loadMaxContractSize(AbstractLedgerTxn& ltx); diff --git a/src/overlay/test/OverlayTests.cpp b/src/overlay/test/OverlayTests.cpp index 45da9a9460..d2d7d29748 100644 --- a/src/overlay/test/OverlayTests.cpp +++ b/src/overlay/test/OverlayTests.cpp @@ -2141,27 +2141,23 @@ TEST_CASE("overlay flow control", "[overlay][flowcontrol]") simulation->addPendingConnection(vNode2NodeID, vNode3NodeID); simulation->addPendingConnection(vNode3NodeID, vNode1NodeID); - for (auto& node2 : simulation->getNodes()) + simulation->startAllNodes(); + if (appProtocolVersionStartsFrom(*simulation->getNodes()[0], + SOROBAN_PROTOCOL_VERSION)) { - if (appProtocolVersionStartsFrom(*node2, SOROBAN_PROTOCOL_VERSION)) - { - modifySorobanNetworkConfig( - *node2, [](SorobanNetworkConfig& cfg) { - cfg.mTxMaxSizeBytes = - MinimumSorobanNetworkConfig::TX_MAX_SIZE_BYTES; - }); - } + upgradeSorobanNetworkConfig( + [](SorobanNetworkConfig& cfg) { + cfg.mTxMaxSizeBytes = + MinimumSorobanNetworkConfig::TX_MAX_SIZE_BYTES; + }, + simulation); } - simulation->startAllNodes(); }; SECTION("enabled") { setupSimulation(); - simulation->crankUntil( - [&] { return simulation->haveAllExternalized(2, 1); }, - 3 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); // Generate a bit of load to flood transactions, make sure nodes can // close ledgers properly auto& loadGen = node->getLoadGenerator(); @@ -2191,13 +2187,7 @@ TEST_CASE("overlay flow control", "[overlay][flowcontrol]") { configs[2].PEER_FLOOD_READING_CAPACITY = 0; configs[2].PEER_FLOOD_READING_CAPACITY_BYTES = 0; - - setupSimulation(); - REQUIRE_THROWS_AS( - simulation->crankUntil( - [&] { return simulation->haveAllExternalized(2, 1); }, - 3 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false), - std::runtime_error); + REQUIRE_THROWS_AS(setupSimulation(), std::runtime_error); } } diff --git a/src/simulation/LoadGenerator.cpp b/src/simulation/LoadGenerator.cpp index 9805934771..694fdc0002 100644 --- a/src/simulation/LoadGenerator.cpp +++ b/src/simulation/LoadGenerator.cpp @@ -3,6 +3,7 @@ // of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 #include "simulation/LoadGenerator.h" +#include "database/Database.h" #include "herder/Herder.h" #include "ledger/LedgerManager.h" #include "ledger/LedgerTxn.h" @@ -23,8 +24,6 @@ #include "util/numeric.h" #include "util/types.h" -#include "database/Database.h" - #include "xdrpp/marshal.h" #include "medida/meter.h" @@ -1565,12 +1564,50 @@ LoadGenerator::getConfigUpgradeSetFromLoadConfig( case CONFIG_SETTING_STATE_ARCHIVAL: { auto& ses = setting.stateArchivalSettings(); + if (upgradeCfg.maxEntryTTL > 0) + { + ses.maxEntryTTL = upgradeCfg.maxEntryTTL; + } + + if (upgradeCfg.minTemporaryTTL > 0) + { + ses.minTemporaryTTL = upgradeCfg.minTemporaryTTL; + } + + if (upgradeCfg.minPersistentTTL > 0) + { + ses.minPersistentTTL = upgradeCfg.minPersistentTTL; + } + + if (upgradeCfg.persistentRentRateDenominator > 0) + { + ses.persistentRentRateDenominator = + upgradeCfg.persistentRentRateDenominator; + } + + if (upgradeCfg.tempRentRateDenominator > 0) + { + ses.tempRentRateDenominator = + upgradeCfg.tempRentRateDenominator; + } + + if (upgradeCfg.maxEntriesToArchive > 0) + { + ses.maxEntriesToArchive = upgradeCfg.maxEntriesToArchive; + } + if (upgradeCfg.bucketListSizeWindowSampleSize > 0) { ses.bucketListSizeWindowSampleSize = upgradeCfg.bucketListSizeWindowSampleSize; } + if (upgradeCfg.bucketListWindowSamplePeriod > 0) + { + ses.bucketListWindowSamplePeriod = + upgradeCfg.bucketListWindowSamplePeriod; + } + if (upgradeCfg.evictionScanSize > 0) { ses.evictionScanSize = upgradeCfg.evictionScanSize; @@ -2202,6 +2239,57 @@ LoadGenerator::execute(TransactionTestFramePtr& txf, LoadGenMode mode, return addResult.code; } +void +GeneratedLoadConfig::copySorobanNetworkConfigToUpgradeConfig( + SorobanNetworkConfig const& cfg) +{ + releaseAssert(mode == LoadGenMode::SOROBAN_CREATE_UPGRADE); + auto& upgradeCfg = getMutSorobanUpgradeConfig(); + + upgradeCfg.maxContractSizeBytes = cfg.maxContractSizeBytes(); + upgradeCfg.maxContractDataKeySizeBytes = cfg.maxContractDataKeySizeBytes(); + upgradeCfg.maxContractDataEntrySizeBytes = + cfg.maxContractDataEntrySizeBytes(); + + upgradeCfg.ledgerMaxInstructions = cfg.ledgerMaxInstructions(); + upgradeCfg.txMaxInstructions = cfg.txMaxInstructions(); + upgradeCfg.txMemoryLimit = cfg.txMemoryLimit(); + + upgradeCfg.ledgerMaxReadLedgerEntries = cfg.ledgerMaxReadLedgerEntries(); + upgradeCfg.ledgerMaxReadBytes = cfg.ledgerMaxReadBytes(); + upgradeCfg.ledgerMaxWriteLedgerEntries = cfg.ledgerMaxWriteLedgerEntries(); + upgradeCfg.ledgerMaxWriteBytes = cfg.ledgerMaxWriteBytes(); + upgradeCfg.ledgerMaxTxCount = cfg.ledgerMaxTxCount(); + upgradeCfg.txMaxReadLedgerEntries = cfg.txMaxReadLedgerEntries(); + upgradeCfg.txMaxReadBytes = cfg.txMaxReadBytes(); + upgradeCfg.txMaxWriteLedgerEntries = cfg.txMaxWriteLedgerEntries(); + upgradeCfg.txMaxWriteBytes = cfg.txMaxWriteBytes(); + + upgradeCfg.txMaxContractEventsSizeBytes = + cfg.txMaxContractEventsSizeBytes(); + + upgradeCfg.ledgerMaxTransactionsSizeBytes = + cfg.ledgerMaxTransactionSizesBytes(); + upgradeCfg.txMaxSizeBytes = cfg.txMaxSizeBytes(); + + upgradeCfg.maxEntryTTL = cfg.stateArchivalSettings().maxEntryTTL; + upgradeCfg.minTemporaryTTL = cfg.stateArchivalSettings().minTemporaryTTL; + upgradeCfg.minPersistentTTL = cfg.stateArchivalSettings().minPersistentTTL; + upgradeCfg.persistentRentRateDenominator = + cfg.stateArchivalSettings().persistentRentRateDenominator; + upgradeCfg.tempRentRateDenominator = + cfg.stateArchivalSettings().tempRentRateDenominator; + upgradeCfg.maxEntriesToArchive = + cfg.stateArchivalSettings().maxEntriesToArchive; + upgradeCfg.bucketListSizeWindowSampleSize = + cfg.stateArchivalSettings().bucketListSizeWindowSampleSize; + upgradeCfg.bucketListWindowSamplePeriod = + cfg.stateArchivalSettings().bucketListWindowSamplePeriod; + upgradeCfg.evictionScanSize = cfg.stateArchivalSettings().evictionScanSize; + upgradeCfg.startingEvictionScanLevel = + cfg.stateArchivalSettings().startingEvictionScanLevel; +} + GeneratedLoadConfig GeneratedLoadConfig::createAccountsLoad(uint32_t nAccounts, uint32_t txRate) { diff --git a/src/simulation/LoadGenerator.h b/src/simulation/LoadGenerator.h index 9e441e5900..0d053765d4 100644 --- a/src/simulation/LoadGenerator.h +++ b/src/simulation/LoadGenerator.h @@ -92,7 +92,14 @@ struct GeneratedLoadConfig uint32_t txMaxSizeBytes{}; // State Archival Settings + uint32_t maxEntryTTL{}; + uint32_t minTemporaryTTL{}; + uint32_t minPersistentTTL{}; + int64_t persistentRentRateDenominator{}; + int64_t tempRentRateDenominator{}; + uint32_t maxEntriesToArchive{}; uint32_t bucketListSizeWindowSampleSize{}; + uint32_t bucketListWindowSamplePeriod{}; uint32_t evictionScanSize{}; uint32_t startingEvictionScanLevel{}; }; @@ -107,6 +114,9 @@ struct GeneratedLoadConfig double sorobanInvokeWeight = 0; }; + void + copySorobanNetworkConfigToUpgradeConfig(SorobanNetworkConfig const& cfg); + static GeneratedLoadConfig createAccountsLoad(uint32_t nAccounts, uint32_t txRate); diff --git a/src/simulation/test/LoadGeneratorTests.cpp b/src/simulation/test/LoadGeneratorTests.cpp index 03865af2f5..fc938406ed 100644 --- a/src/simulation/test/LoadGeneratorTests.cpp +++ b/src/simulation/test/LoadGeneratorTests.cpp @@ -91,6 +91,49 @@ TEST_CASE("generate load with unique accounts", "[loadgen]") } } +TEST_CASE("modify soroban network config", "[loadgen][soroban]") +{ + Hash networkID = sha256(getTestConfig().NETWORK_PASSPHRASE); + Simulation::pointer simulation = + Topologies::pair(Simulation::OVER_LOOPBACK, networkID, [&](int i) { + auto cfg = getTestConfig(i); + return cfg; + }); + + simulation->startAllNodes(); + simulation->crankUntil( + [&]() { return simulation->haveAllExternalized(3, 1); }, + 2 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); + auto nodes = simulation->getNodes(); + auto& app = *nodes[0]; // pick a node to generate load + + const uint32_t ledgerMaxTxCount = 42; + const uint32_t bucketListSizeWindowSampleSize = 99; + // Upgrade the network config. + upgradeSorobanNetworkConfig( + [&](SorobanNetworkConfig& cfg) { + cfg.mLedgerMaxTxCount = ledgerMaxTxCount; + cfg.stateArchivalSettings().bucketListSizeWindowSampleSize = + bucketListSizeWindowSampleSize; + }, + simulation); + // Check that the settings were properly updated. + LedgerTxn ltx(app.getLedgerTxnRoot()); + auto contractExecutionLanesSettingsEntry = + ltx.load(configSettingKey(CONFIG_SETTING_CONTRACT_EXECUTION_LANES)); + auto stateArchivalConfigSettinsgEntry = + ltx.load(configSettingKey(CONFIG_SETTING_STATE_ARCHIVAL)); + auto& contractExecutionLanesSettings = + contractExecutionLanesSettingsEntry.current().data.configSetting(); + auto& stateArchivalSettings = + stateArchivalConfigSettinsgEntry.current().data.configSetting(); + REQUIRE(contractExecutionLanesSettings.contractExecutionLanes() + .ledgerMaxTxCount == ledgerMaxTxCount); + REQUIRE(stateArchivalSettings.stateArchivalSettings() + .bucketListSizeWindowSampleSize == + bucketListSizeWindowSampleSize); +} + TEST_CASE("generate soroban load", "[loadgen][soroban]") { uint32_t const numDataEntries = 5; @@ -121,6 +164,7 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") 2 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); auto nodes = simulation->getNodes(); + auto& app = *nodes[0]; // pick a node to generate load auto& loadGen = app.getLoadGenerator(); auto getSuccessfulTxCount = [&]() { @@ -134,24 +178,20 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") loadGen.generateLoad(GeneratedLoadConfig::createAccountsLoad( /* nAccounts */ nAccounts, /* txRate */ 1)); + auto& complete = + app.getMetrics().NewMeter({"loadgen", "run", "complete"}, "run"); + auto completeCount = complete.count(); simulation->crankUntil( - [&]() { - return app.getMetrics() - .NewMeter({"loadgen", "run", "complete"}, "run") - .count() == 1; - }, + [&]() { return complete.count() == completeCount + 1; }, 100 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); int64_t numTxsBefore = getSuccessfulTxCount(); // Make sure config upgrade works with initial network config settings loadGen.generateLoad(GeneratedLoadConfig::createSorobanUpgradeSetupLoad()); + completeCount = complete.count(); simulation->crankUntil( - [&]() { - return app.getMetrics() - .NewMeter({"loadgen", "run", "complete"}, "run") - .count() == 2; - }, + [&]() { return complete.count() == completeCount + 1; }, 100 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); // Check that Soroban TXs were successfully applied @@ -219,12 +259,9 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") numTxsBefore = getSuccessfulTxCount(); loadGen.generateLoad(createUpgradeLoadGenConfig); + completeCount = complete.count(); simulation->crankUntil( - [&]() { - return app.getMetrics() - .NewMeter({"loadgen", "run", "complete"}, "run") - .count() == 3; - }, + [&]() { return complete.count() == completeCount + 1; }, 300 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); for (auto node : nodes) @@ -339,13 +376,12 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") } } - // Manually override network settings for invoke load gen - for (auto node : nodes) - { - overrideSorobanNetworkConfigForTest(*node); - modifySorobanNetworkConfig(*node, [&](SorobanNetworkConfig& cfg) { + upgradeSorobanNetworkConfig( + [&](SorobanNetworkConfig& cfg) { + setSorobanNetworkConfigForTest(cfg); + // Entries should never expire - cfg.mStateArchivalSettings.maxEntryTTL = 1'000'000; + cfg.mStateArchivalSettings.maxEntryTTL = 2'000'000; cfg.mStateArchivalSettings.minPersistentTTL = 1'000'000; // Set write limits so that we can write all keys in a single TX @@ -366,22 +402,19 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") cfg.mTxMaxWriteBytes * cfg.mLedgerMaxTxCount; cfg.mLedgerMaxTransactionsSizeBytes = cfg.mTxMaxSizeBytes * cfg.mLedgerMaxTxCount; - }); - } - + }, + simulation); auto const numInstances = 10; auto const numSorobanTxs = 100; numTxsBefore = getSuccessfulTxCount(); + loadGen.generateLoad(GeneratedLoadConfig::createSorobanInvokeSetupLoad( /* nAccounts */ nAccounts, numInstances, /* txRate */ 1)); + completeCount = complete.count(); simulation->crankUntil( - [&]() { - return app.getMetrics() - .NewMeter({"loadgen", "run", "complete"}, "run") - .count() == 4; - }, + [&]() { return complete.count() == completeCount + 1; }, 100 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); // Check that Soroban TXs were successfully applied @@ -409,12 +442,9 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") invokeLoadCfg.setMinSorobanPercentSuccess(100 - maxInvokeFail); loadGen.generateLoad(invokeLoadCfg); + completeCount = complete.count(); simulation->crankUntil( - [&]() { - return app.getMetrics() - .NewMeter({"loadgen", "run", "complete"}, "run") - .count() == 5; - }, + [&]() { return complete.count() == completeCount + 1; }, 300 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); // Check that Soroban TXs were successfully applied @@ -511,12 +541,9 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") app.getMetrics() .NewCounter({"ledger", "apply-soroban", "failure"}) .count(); + completeCount = complete.count(); simulation->crankUntil( - [&]() { - return app.getMetrics() - .NewMeter({"loadgen", "run", "complete"}, "run") - .count() == 6; - }, + [&]() { return complete.count() == completeCount + 1; }, 300 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); // Check results @@ -563,13 +590,12 @@ TEST_CASE("generate soroban load", "[loadgen][soroban]") // LoadGen should fail loadGen.generateLoad(uploadFailCfg); - simulation->crankUntil( - [&]() { - return app.getMetrics() - .NewMeter({"loadgen", "run", "failed"}, "run") - .count() == 1; - }, - 300 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); + 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); } } diff --git a/src/test/TestUtils.cpp b/src/test/TestUtils.cpp index 3b35dd71d5..c9f085e4e5 100644 --- a/src/test/TestUtils.cpp +++ b/src/test/TestUtils.cpp @@ -4,10 +4,11 @@ #include "TestUtils.h" #include "overlay/test/LoopbackPeer.h" +#include "simulation/LoadGenerator.h" +#include "simulation/Simulation.h" #include "test/TxTests.h" #include "test/test.h" #include "work/WorkScheduler.h" -#include "xdr/Stellar-ledger-entries.h" namespace stellar { @@ -194,6 +195,78 @@ genesis(int minute, int second) getTestDateTime(1, 7, 2014, 0, minute, second)); } +void +upgradeSorobanNetworkConfig(std::function modifyFn, + std::shared_ptr simulation) +{ + auto nodes = simulation->getNodes(); + auto& lg = nodes[0]->getLoadGenerator(); + auto& app = *nodes[0]; + + auto& complete = + app.getMetrics().NewMeter({"loadgen", "run", "complete"}, "run"); + auto completeCount = complete.count(); + // Only create an account if there are none aleady created. + uint32_t offset = 0; + if (app.getMetrics() + .NewMeter({"loadgen", "account", "created"}, "account") + .count() == 0) + { + auto createAccountsLoadConfig = + GeneratedLoadConfig::createAccountsLoad(1, 1); + offset = std::numeric_limits::max() - 1; + createAccountsLoadConfig.offset = offset; + + lg.generateLoad(createAccountsLoadConfig); + simulation->crankUntil( + [&]() { return complete.count() == completeCount + 1; }, + 300 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); + } + + // Create upload wasm transaction. + auto createUploadCfg = GeneratedLoadConfig::createSorobanUpgradeSetupLoad(); + createUploadCfg.offset = offset; + lg.generateLoad(createUploadCfg); + completeCount = complete.count(); + simulation->crankUntil( + [&]() { return complete.count() == completeCount + 1; }, + 300 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); + + // Create upgrade transaction. + auto createUpgradeLoadGenConfig = GeneratedLoadConfig::txLoad( + LoadGenMode::SOROBAN_CREATE_UPGRADE, 1, 1, 1); + createUpgradeLoadGenConfig.offset = offset; + // Get current network config. + auto cfg = nodes[0]->getLedgerManager().getSorobanNetworkConfig(); + modifyFn(cfg); + createUpgradeLoadGenConfig.copySorobanNetworkConfigToUpgradeConfig(cfg); + auto upgradeSetKey = lg.getConfigUpgradeSetKey(createUpgradeLoadGenConfig); + lg.generateLoad(createUpgradeLoadGenConfig); + completeCount = complete.count(); + simulation->crankUntil( + [&]() { return complete.count() == completeCount + 1; }, + 2 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); + + // Arm for upgrade. + for (auto app : nodes) + { + Upgrades::UpgradeParameters scheduledUpgrades; + auto lclHeader = + app->getLedgerManager().getLastClosedLedgerHeader().header; + scheduledUpgrades.mUpgradeTime = + VirtualClock::from_time_t(lclHeader.scpValue.closeTime); + scheduledUpgrades.mConfigUpgradeSetKey = upgradeSetKey; + app->getHerder().setUpgrades(scheduledUpgrades); + } + // Wait for upgrade to be applied + simulation->crankUntil( + [&]() { + auto netCfg = app.getLedgerManager().getSorobanNetworkConfig(); + return netCfg == cfg; + }, + 2 * Herder::EXP_LEDGER_TIMESPAN_SECONDS, false); +} + void modifySorobanNetworkConfig(Application& app, std::function modifyFn) @@ -216,6 +289,37 @@ modifySorobanNetworkConfig(Application& app, } } +void +setSorobanNetworkConfigForTest(SorobanNetworkConfig& cfg) +{ + cfg.mMaxContractSizeBytes = 64 * 1024; + cfg.mMaxContractDataEntrySizeBytes = 64 * 1024; + + cfg.mTxMaxSizeBytes = 100 * 1024; + cfg.mLedgerMaxTransactionsSizeBytes = cfg.mTxMaxSizeBytes * 10; + + cfg.mTxMaxInstructions = 100'000'000; + cfg.mLedgerMaxInstructions = cfg.mTxMaxInstructions * 10; + cfg.mTxMemoryLimit = 100 * 1024 * 1024; + + cfg.mTxMaxReadLedgerEntries = 40; + cfg.mTxMaxReadBytes = 200 * 1024; + + cfg.mTxMaxWriteLedgerEntries = 20; + cfg.mTxMaxWriteBytes = 100 * 1024; + + cfg.mLedgerMaxReadLedgerEntries = cfg.mTxMaxReadLedgerEntries * 10; + cfg.mLedgerMaxReadBytes = cfg.mTxMaxReadBytes * 10; + cfg.mLedgerMaxWriteLedgerEntries = cfg.mTxMaxWriteLedgerEntries * 10; + cfg.mLedgerMaxWriteBytes = cfg.mTxMaxWriteBytes * 10; + + cfg.mStateArchivalSettings.minPersistentTTL = 20; + cfg.mStateArchivalSettings.maxEntryTTL = 6'312'000; + cfg.mLedgerMaxTxCount = 100; + + cfg.mTxMaxContractEventsSizeBytes = 10'000; +} + void overrideSorobanNetworkConfigForTest(Application& app) { diff --git a/src/test/TestUtils.h b/src/test/TestUtils.h index 22e09f3584..83f3e6d4f9 100644 --- a/src/test/TestUtils.h +++ b/src/test/TestUtils.h @@ -16,6 +16,7 @@ namespace stellar { class LoopbackPeerConnection; +class Simulation; namespace testutil { @@ -94,11 +95,18 @@ std::tm getTestDateTime(int day, int month, int year, int hour, int minute, VirtualClock::system_time_point genesis(int minute, int second); +// Assigns values to the SorobanNetworkConfig fields that are suitable for +// most of the unit tests. +void setSorobanNetworkConfigForTest(SorobanNetworkConfig& cfg); + // Override Soroban network config defaults with generous settings suitable // for most of the unit tests (unless the test is meant to exercise the // configuration limits). void overrideSorobanNetworkConfigForTest(Application& app); void +upgradeSorobanNetworkConfig(std::function modifyFn, + std::shared_ptr simulation); +void modifySorobanNetworkConfig(Application& app, std::function modifyFn);