Skip to content

Commit

Permalink
Merge pull request #3855 from sisuresh/setting-validations
Browse files Browse the repository at this point in the history
Setting validations

Reviewed-by: dmkozh
  • Loading branch information
latobarita authored Jul 26, 2023
2 parents 6ae2f30 + 8a86ff2 commit 9215e8d
Show file tree
Hide file tree
Showing 5 changed files with 331 additions and 25 deletions.
115 changes: 103 additions & 12 deletions src/herder/Upgrades.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1466,42 +1466,133 @@ ConfigUpgradeSetFrame::isValidForApply() const
{
return Upgrades::UpgradeValidity::XDR_INVALID;
}
for (auto const& configEntry : mConfigUpgradeSet.updatedEntry)
for (auto const& cfg : mConfigUpgradeSet.updatedEntry)
{
bool valid = false;
switch (configEntry.configSettingID())
switch (cfg.configSettingID())
{
case ConfigSettingID::CONFIG_SETTING_CONTRACT_MAX_SIZE_BYTES:
valid = configEntry.contractMaxSizeBytes() > 0;
valid = cfg.contractMaxSizeBytes() >=
MinimumSorobanNetworkConfig::MAX_CONTRACT_SIZE;
break;
case ConfigSettingID::
CONFIG_SETTING_CONTRACT_COST_PARAMS_CPU_INSTRUCTIONS:
valid = SorobanNetworkConfig::isValidCostParams(
configEntry.contractCostParamsCpuInsns());
cfg.contractCostParamsCpuInsns());
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_COST_PARAMS_MEMORY_BYTES:
valid = SorobanNetworkConfig::isValidCostParams(
configEntry.contractCostParamsMemBytes());
cfg.contractCostParamsMemBytes());
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_DATA_KEY_SIZE_BYTES:
valid = configEntry.contractDataKeySizeBytes() > 0;
valid =
cfg.contractDataKeySizeBytes() >=
MinimumSorobanNetworkConfig::MAX_CONTRACT_DATA_KEY_SIZE_BYTES;
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_DATA_ENTRY_SIZE_BYTES:
valid = configEntry.contractDataEntrySizeBytes() > 0;
valid =
cfg.contractDataEntrySizeBytes() >=
MinimumSorobanNetworkConfig::MAX_CONTRACT_DATA_ENTRY_SIZE_BYTES;
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_EXECUTION_LANES:
valid = configEntry.contractExecutionLanes().ledgerMaxTxCount >= 0;
valid = true;
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_BANDWIDTH_V0:
valid = cfg.contractBandwidth().feePropagateData1KB >= 0 &&
cfg.contractBandwidth().ledgerMaxPropagateSizeBytes >=
MinimumSorobanNetworkConfig::
LEDGER_MAX_PROPAGATE_SIZE_BYTES &&
cfg.contractBandwidth().txMaxSizeBytes >=
MinimumSorobanNetworkConfig::TX_MAX_SIZE_BYTES;
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_COMPUTE_V0:
valid =
cfg.contractCompute().feeRatePerInstructionsIncrement >= 0 &&
cfg.contractCompute().ledgerMaxInstructions >=
MinimumSorobanNetworkConfig::LEDGER_MAX_INSTRUCTIONS &&
cfg.contractCompute().txMaxInstructions >=
MinimumSorobanNetworkConfig::TX_MAX_INSTRUCTIONS &&
cfg.contractCompute().txMemoryLimit >=
MinimumSorobanNetworkConfig::MEMORY_LIMIT;

valid = valid && cfg.contractCompute().ledgerMaxInstructions >=
cfg.contractCompute().txMaxInstructions;
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_HISTORICAL_DATA_V0:
valid = cfg.contractHistoricalData().feeHistorical1KB >= 0;
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_LEDGER_COST_V0:
valid =
cfg.contractLedgerCost().ledgerMaxReadLedgerEntries >=
MinimumSorobanNetworkConfig::
LEDGER_MAX_READ_LEDGER_ENTRIES &&
cfg.contractLedgerCost().ledgerMaxReadBytes >=
MinimumSorobanNetworkConfig::LEDGER_MAX_READ_BYTES &&
cfg.contractLedgerCost().ledgerMaxWriteLedgerEntries >=
MinimumSorobanNetworkConfig::
LEDGER_MAX_WRITE_LEDGER_ENTRIES &&
cfg.contractLedgerCost().ledgerMaxWriteBytes >=
MinimumSorobanNetworkConfig::LEDGER_MAX_WRITE_BYTES &&
cfg.contractLedgerCost().txMaxReadLedgerEntries >=
MinimumSorobanNetworkConfig::
LEDGER_MAX_READ_LEDGER_ENTRIES &&
cfg.contractLedgerCost().txMaxReadBytes >=
MinimumSorobanNetworkConfig::TX_MAX_READ_BYTES &&
cfg.contractLedgerCost().txMaxWriteLedgerEntries >=
MinimumSorobanNetworkConfig::TX_MAX_WRITE_LEDGER_ENTRIES &&
cfg.contractLedgerCost().txMaxWriteBytes >=
MinimumSorobanNetworkConfig::TX_MAX_WRITE_BYTES &&
cfg.contractLedgerCost().feeReadLedgerEntry >= 0 &&
cfg.contractLedgerCost().feeWriteLedgerEntry >= 0 &&
cfg.contractLedgerCost().feeRead1KB >= 0 &&
cfg.contractLedgerCost().bucketListTargetSizeBytes > 0 &&
cfg.contractLedgerCost().writeFee1KBBucketListLow >= 0 &&
cfg.contractLedgerCost().writeFee1KBBucketListHigh >= 0 &&
cfg.contractLedgerCost().bucketListWriteFeeGrowthFactor >= 0;

valid =
valid && cfg.contractLedgerCost().ledgerMaxReadLedgerEntries >=
cfg.contractLedgerCost().txMaxReadLedgerEntries;
valid = valid && cfg.contractLedgerCost().ledgerMaxReadBytes >=
cfg.contractLedgerCost().txMaxReadBytes;

valid =
valid && cfg.contractLedgerCost().ledgerMaxWriteLedgerEntries >=
cfg.contractLedgerCost().txMaxWriteLedgerEntries;
valid = valid && cfg.contractLedgerCost().ledgerMaxWriteBytes >=
cfg.contractLedgerCost().txMaxWriteBytes;
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_META_DATA_V0:
valid = cfg.contractMetaData().txMaxExtendedMetaDataSizeBytes >=
MinimumSorobanNetworkConfig::
TX_MAX_EXTENDED_META_DATA_SIZE_BYTES &&
cfg.contractMetaData().feeExtendedMetaData1KB >= 0;
break;
case ConfigSettingID::CONFIG_SETTING_STATE_EXPIRATION:
// For now none of these settings have any semantical value.
// Validation should be implemented when implementing/tuning
// the respective settings.
valid = true;
valid =
cfg.stateExpirationSettings().maxEntryExpiration >=
MinimumSorobanNetworkConfig::MAXIMUM_ENTRY_LIFETIME &&
cfg.stateExpirationSettings().minTempEntryExpiration > 0 &&
cfg.stateExpirationSettings().minPersistentEntryExpiration >=
MinimumSorobanNetworkConfig::
MINIMUM_PERSISTENT_ENTRY_LIFETIME &&
cfg.stateExpirationSettings().autoBumpLedgers >=
0 && // autobumpLedgers can be disabled by setting to 0
cfg.stateExpirationSettings().persistentRentRateDenominator >
0 &&
cfg.stateExpirationSettings().tempRentRateDenominator > 0 &&
cfg.stateExpirationSettings().maxEntriesToExpire > 0 &&
cfg.stateExpirationSettings().bucketListSizeWindowSampleSize >
0 &&
cfg.stateExpirationSettings().evictionScanSize > 0;

valid =
valid &&
cfg.stateExpirationSettings().maxEntryExpiration >
cfg.stateExpirationSettings().minPersistentEntryExpiration;
valid = valid &&
cfg.stateExpirationSettings().maxEntryExpiration >
cfg.stateExpirationSettings().minTempEntryExpiration;
break;
case ConfigSettingID::CONFIG_SETTING_BUCKETLIST_SIZE_WINDOW:
// While the BucketList size window is stored in a ConfigSetting
Expand Down
49 changes: 43 additions & 6 deletions src/herder/test/UpgradesTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,9 +841,12 @@ TEST_CASE("config upgrades applied to ledger", "[soroban][upgrades]")
auto& configEntry = configUpgradeSetXdr.updatedEntry.emplace_back();
configEntry.configSettingID(CONFIG_SETTING_CONTRACT_COMPUTE_V0);
configEntry.contractCompute().feeRatePerInstructionsIncrement = 111;
configEntry.contractCompute().ledgerMaxInstructions = 222;
configEntry.contractCompute().txMemoryLimit = 333;
configEntry.contractCompute().txMaxInstructions = 444;
configEntry.contractCompute().ledgerMaxInstructions =
MinimumSorobanNetworkConfig::LEDGER_MAX_INSTRUCTIONS;
configEntry.contractCompute().txMemoryLimit =
MinimumSorobanNetworkConfig::MEMORY_LIMIT;
configEntry.contractCompute().txMaxInstructions =
MinimumSorobanNetworkConfig::TX_MAX_INSTRUCTIONS;
auto& configEntry2 =
configUpgradeSetXdr.updatedEntry.emplace_back();
configEntry2.configSettingID(
Expand All @@ -855,11 +858,45 @@ TEST_CASE("config upgrades applied to ledger", "[soroban][upgrades]")
}
executeUpgrade(*app, makeConfigUpgrade(*configUpgradeSet));
REQUIRE(sorobanConfig.feeRatePerInstructionsIncrement() == 111);
REQUIRE(sorobanConfig.ledgerMaxInstructions() == 222);
REQUIRE(sorobanConfig.txMemoryLimit() == 333);
REQUIRE(sorobanConfig.txMaxInstructions() == 444);
REQUIRE(sorobanConfig.ledgerMaxInstructions() ==
MinimumSorobanNetworkConfig::LEDGER_MAX_INSTRUCTIONS);
REQUIRE(sorobanConfig.txMemoryLimit() ==
MinimumSorobanNetworkConfig::MEMORY_LIMIT);
REQUIRE(sorobanConfig.txMaxInstructions() ==
MinimumSorobanNetworkConfig::TX_MAX_INSTRUCTIONS);
REQUIRE(sorobanConfig.feeHistorical1KB() == 555);
}
SECTION("upgrade rejected due to value below minimum")
{
// This just test one setting. We should test more.
auto upgrade = [&](uint32_t min, uint32_t upgradeVal) {
ConfigUpgradeSetFrameConstPtr configUpgradeSet;
LedgerTxn ltx2(app->getLedgerTxnRoot());
// Copy current settings
LedgerKey key(CONFIG_SETTING);
key.configSetting().configSettingID =
ConfigSettingID::CONFIG_SETTING_CONTRACT_LEDGER_COST_V0;
auto le = ltx2.loadWithoutRecord(key, false).current();
auto configSetting = le.data.configSetting();
configSetting.contractLedgerCost().txMaxWriteBytes = upgradeVal;

ConfigUpgradeSet configUpgradeSetXdr;
configUpgradeSetXdr.updatedEntry.emplace_back(configSetting);
configUpgradeSet = makeConfigUpgradeSet(ltx2, configUpgradeSetXdr);
ltx2.commit();

executeUpgrade(*app, makeConfigUpgrade(*configUpgradeSet));
REQUIRE(sorobanConfig.txMaxWriteBytes() == min);
};

// First set to minimum
upgrade(MinimumSorobanNetworkConfig::TX_MAX_WRITE_BYTES,
MinimumSorobanNetworkConfig::TX_MAX_WRITE_BYTES);

// Then try to go below minimum
upgrade(MinimumSorobanNetworkConfig::TX_MAX_WRITE_BYTES,
MinimumSorobanNetworkConfig::TX_MAX_WRITE_BYTES - 1);
}
}

TEST_CASE("Soroban max tx set size upgrade applied to ledger",
Expand Down
110 changes: 105 additions & 5 deletions src/invariant/LedgerEntryIsValid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,6 @@ LedgerEntryIsValid::checkIsValid(ConfigSettingEntry const& cfg,
LedgerEntry const* previous,
uint32 version) const
{

switch (cfg.configSettingID())
{
case ConfigSettingID::CONFIG_SETTING_CONTRACT_MAX_SIZE_BYTES:
Expand Down Expand Up @@ -641,19 +640,120 @@ LedgerEntryIsValid::checkIsValid(ConfigSettingEntry const& cfg,
}
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_EXECUTION_LANES:
if (cfg.contractExecutionLanes().ledgerMaxTxCount < 0)
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_BANDWIDTH_V0:
if (cfg.contractBandwidth().feePropagateData1KB < 0 ||
cfg.contractBandwidth().ledgerMaxPropagateSizeBytes <
MinimumSorobanNetworkConfig::LEDGER_MAX_PROPAGATE_SIZE_BYTES ||
cfg.contractBandwidth().txMaxSizeBytes <
MinimumSorobanNetworkConfig::TX_MAX_SIZE_BYTES)
{
return "Invalid ledgerMaxTxCount";
return "Invalid contractBandwidth";
}
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_BANDWIDTH_V0:
case ConfigSettingID::CONFIG_SETTING_CONTRACT_COMPUTE_V0:
if (cfg.contractCompute().feeRatePerInstructionsIncrement < 0 ||
cfg.contractCompute().ledgerMaxInstructions <
MinimumSorobanNetworkConfig::LEDGER_MAX_INSTRUCTIONS ||
cfg.contractCompute().txMaxInstructions <
MinimumSorobanNetworkConfig::TX_MAX_INSTRUCTIONS ||
cfg.contractCompute().txMemoryLimit <
MinimumSorobanNetworkConfig::MEMORY_LIMIT)
{
return "Invalid contractCompute";
}
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_HISTORICAL_DATA_V0:
if (cfg.contractHistoricalData().feeHistorical1KB < 0)
{
return "Invalid feeHistorical1KB";
}
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_LEDGER_COST_V0:
if (cfg.contractLedgerCost().ledgerMaxReadLedgerEntries <
MinimumSorobanNetworkConfig::LEDGER_MAX_READ_LEDGER_ENTRIES ||
cfg.contractLedgerCost().ledgerMaxReadBytes <
MinimumSorobanNetworkConfig::LEDGER_MAX_READ_BYTES ||
cfg.contractLedgerCost().ledgerMaxWriteLedgerEntries <
MinimumSorobanNetworkConfig::LEDGER_MAX_WRITE_LEDGER_ENTRIES ||
cfg.contractLedgerCost().ledgerMaxWriteBytes <
MinimumSorobanNetworkConfig::LEDGER_MAX_WRITE_BYTES ||
cfg.contractLedgerCost().txMaxReadLedgerEntries <
MinimumSorobanNetworkConfig::LEDGER_MAX_READ_LEDGER_ENTRIES ||
cfg.contractLedgerCost().txMaxReadBytes <
MinimumSorobanNetworkConfig::TX_MAX_READ_BYTES ||
cfg.contractLedgerCost().txMaxWriteLedgerEntries <
MinimumSorobanNetworkConfig::TX_MAX_WRITE_LEDGER_ENTRIES ||
cfg.contractLedgerCost().txMaxWriteBytes <
MinimumSorobanNetworkConfig::TX_MAX_WRITE_BYTES ||
cfg.contractLedgerCost().feeReadLedgerEntry < 0 ||
cfg.contractLedgerCost().feeWriteLedgerEntry < 0 ||
cfg.contractLedgerCost().feeRead1KB < 0 ||
cfg.contractLedgerCost().bucketListTargetSizeBytes <= 0 ||
cfg.contractLedgerCost().writeFee1KBBucketListLow < 0 ||
cfg.contractLedgerCost().writeFee1KBBucketListHigh < 0 ||
cfg.contractLedgerCost().bucketListWriteFeeGrowthFactor < 0)
{
return "Invalid contractLedgerCost";
}
if (cfg.contractLedgerCost().ledgerMaxReadLedgerEntries <
cfg.contractLedgerCost().txMaxReadLedgerEntries)
{
return "ledgerMaxReadLedgerEntries < txMaxReadLedgerEntries";
}
if (cfg.contractLedgerCost().ledgerMaxReadBytes <
cfg.contractLedgerCost().txMaxReadBytes)
{
return "ledgerMaxReadBytes < txMaxReadBytes";
}
if (cfg.contractLedgerCost().ledgerMaxWriteLedgerEntries <
cfg.contractLedgerCost().txMaxWriteLedgerEntries)
{
return "ledgerMaxWriteLedgerEntries < txMaxWriteLedgerEntries";
}
if (cfg.contractLedgerCost().ledgerMaxWriteBytes <
cfg.contractLedgerCost().txMaxWriteBytes)
{
return "ledgerMaxWriteBytes < txMaxWriteBytes";
}
break;
case ConfigSettingID::CONFIG_SETTING_CONTRACT_META_DATA_V0:
if (cfg.contractMetaData().txMaxExtendedMetaDataSizeBytes <
MinimumSorobanNetworkConfig::
TX_MAX_EXTENDED_META_DATA_SIZE_BYTES ||
cfg.contractMetaData().feeExtendedMetaData1KB < 0)
{
return "Invalid contractMetaData";
}
case ConfigSettingID::CONFIG_SETTING_STATE_EXPIRATION:
if (cfg.stateExpirationSettings().maxEntryExpiration <
MinimumSorobanNetworkConfig::MAXIMUM_ENTRY_LIFETIME ||
cfg.stateExpirationSettings().minTempEntryExpiration < 1 ||
cfg.stateExpirationSettings().minPersistentEntryExpiration <
MinimumSorobanNetworkConfig::
MINIMUM_PERSISTENT_ENTRY_LIFETIME ||
cfg.stateExpirationSettings().autoBumpLedgers < 0 ||
cfg.stateExpirationSettings().persistentRentRateDenominator < 1 ||
cfg.stateExpirationSettings().tempRentRateDenominator < 1 ||
cfg.stateExpirationSettings().maxEntriesToExpire < 1 ||
cfg.stateExpirationSettings().bucketListSizeWindowSampleSize < 1 ||
cfg.stateExpirationSettings().evictionScanSize < 1)
{
return "Invalid stateExpirationSettings";
}

if (cfg.stateExpirationSettings().maxEntryExpiration <=
cfg.stateExpirationSettings().minPersistentEntryExpiration)
{
return "maxEntryExpiration <= minPersistentEntryExpiration";
}

if (cfg.stateExpirationSettings().maxEntryExpiration <=
cfg.stateExpirationSettings().minTempEntryExpiration)
{
return "maxEntryExpiration <= minTempEntryExpiration";
}
case ConfigSettingID::CONFIG_SETTING_BUCKETLIST_SIZE_WINDOW:
// TODO: https://github.com/stellar/stellar-core/issues/3802
break;
}

Expand Down
33 changes: 33 additions & 0 deletions src/ledger/NetworkConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,39 @@ struct InitialSorobanNetworkConfig
static constexpr uint32_t LEDGER_MAX_TX_COUNT = 10;
};

// Defines the minimum values allowed for the network configuration
// settings during upgrades. An upgrade that does not follow the minimums
// will be rejected.
struct MinimumSorobanNetworkConfig
{
static constexpr uint32_t TX_MAX_READ_LEDGER_ENTRIES = 5;
static constexpr uint32_t TX_MAX_READ_BYTES = 5000;

static constexpr uint32_t TX_MAX_WRITE_LEDGER_ENTRIES = 2;
static constexpr uint32_t TX_MAX_WRITE_BYTES = 5000;

static constexpr uint32_t LEDGER_MAX_READ_LEDGER_ENTRIES = 5;
static constexpr uint32_t LEDGER_MAX_READ_BYTES = 5000;
static constexpr uint32_t LEDGER_MAX_WRITE_LEDGER_ENTRIES = 2;
static constexpr uint32_t LEDGER_MAX_WRITE_BYTES = 5000;

static constexpr uint32_t TX_MAX_EXTENDED_META_DATA_SIZE_BYTES = 15000;

static constexpr uint32_t TX_MAX_SIZE_BYTES = 10000;
static constexpr uint32_t LEDGER_MAX_PROPAGATE_SIZE_BYTES = 10000;

static constexpr uint32_t TX_MAX_INSTRUCTIONS = 5'000'000;
static constexpr uint32_t LEDGER_MAX_INSTRUCTIONS = 5'000'000;
static constexpr uint32_t MEMORY_LIMIT = 5'000'000;

static constexpr uint32_t MAX_CONTRACT_DATA_KEY_SIZE_BYTES = 500;
static constexpr uint32_t MAX_CONTRACT_DATA_ENTRY_SIZE_BYTES = 5000;
static constexpr uint32_t MAX_CONTRACT_SIZE = 5000;

static constexpr uint32_t MINIMUM_PERSISTENT_ENTRY_LIFETIME = 100;
static constexpr uint32_t MAXIMUM_ENTRY_LIFETIME = 259200; // 15 days
};

// Wrapper for the contract-related network configuration.
class SorobanNetworkConfig
{
Expand Down
Loading

0 comments on commit 9215e8d

Please sign in to comment.