Skip to content

Commit

Permalink
validation: unit test for zero values after read from standard tomls (#…
Browse files Browse the repository at this point in the history
…716)

* validation: unit test for zero values after read from standard tomls

* add more release-specific unit tests

* improve versions.Release[Release] test
  • Loading branch information
bitwiseguy authored Nov 27, 2024
1 parent d98924a commit c56b992
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 5 deletions.
4 changes: 2 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ test-superchain: clean-add-chain

# Unit test all Go code in the validation module, and do not run validation checks themselves
test-validation: clean-add-chain
TEST_DIRECTORY=./validation go run gotest.tools/gotestsum@latest --format testname -- -run='[^TestValidation|^TestPromotion]'
TEST_DIRECTORY=./validation/... go run gotest.tools/gotestsum@latest --format testname -- -run '[^TestValidation|^TestPromotion|^TestGenesisAllocs]'

# Runs validation checks for any chain whose config changed
validate-modified-chains REF:
Expand All @@ -63,7 +63,7 @@ promotion-test:

# Run the promotion tests for chains with a name or chain ID matching the supplied regex, example: just promote-test 10
validate-standard-candidate CHAIN_ID:
TEST_DIRECTORY=./validation go run gotest.tools/gotestsum@latest --format testname -- -run='Promotion/.+\({{CHAIN_ID}}\)$' -count=1
TEST_DIRECTORY=./validation go run gotest.tools/gotestsum@latest --format testname -- -run='Promotion/.+\({{CHAIN_ID}}\)$' -count=1

# Clean test files generated by the add-chain tooling
clean-add-chain:
Expand Down
59 changes: 59 additions & 0 deletions validation/standard/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package standard

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
)

func TestConfigInitialization(t *testing.T) {
t.Run("Release", func(t *testing.T) {
require.NotEmpty(t, Release, "Release should not be empty")
})

t.Run("BytecodeHashes", func(t *testing.T) {
require.NotNil(t, BytecodeHashes[Release], "BytecodeHashes should not be nil")
require.NotZero(t, len(BytecodeHashes), "BytecodeHashes should not be empty")
})

t.Run("BytecodeImmutables", func(t *testing.T) {
require.NotNil(t, BytecodeImmutables[Release], "BytecodeImmutables should not be nil")
require.NotZero(t, len(BytecodeImmutables), "BytecodeImmutables should not be empty")
})

require.NotNil(t, Config, "Config should not be nil")
require.NotNil(t, Config.Params, "Config.Params should not be nil")
require.NotNil(t, Config.Roles, "Config.Roles should not be nil")
require.NotNil(t, Config.MultisigRoles, "Config.MultisigRoles should not be nil")

// Check individual network configurations
networks := []string{"mainnet", "sepolia"}
for _, network := range networks {
t.Run(fmt.Sprintf("Params[%s]", network), func(t *testing.T) {
// Ensure network Params are populated
require.NotNil(t, Config.Params[network], "Config.Params[%s] should not be nil", network)
require.NoError(t, Config.Params[network].Check(), "Config.Params[%s] has invalid zero value", network)
})

t.Run(fmt.Sprintf("MultisigRoles[%s]", network), func(t *testing.T) {
// Ensure network MultisigRoles are populated
require.NotNil(t, Config.MultisigRoles[network], "Config.MultisigRoles[%s] should not be nil", network)
require.NotZero(t, Config.MultisigRoles[network], "Config.MultisigRoles[%s] should not be zero value", network)
})

t.Run(fmt.Sprintf("NetworkVersion[%s]", network), func(t *testing.T) {
// Ensure network Versions are populated
versions, ok := NetworkVersions[network]
require.True(t, ok, "NetworkVersions[%s] should exist", network)
require.NotNil(t, versions, "NetworkVersions[%s] should not be nil", network)
require.NotZero(t, len(versions.Releases), "NetworkVersions[%s].Releases should not be empty", network)

_, ok = versions.Releases[Release]
require.True(t, ok, "NetworkVersions[%s].Releases[%s] should exist", network, Release)

_, ok = versions.Releases["fake-release"]
require.False(t, ok, "NetworkVersions[%s].Releases[%s] should not exist", network, Release)
})
}
}
117 changes: 114 additions & 3 deletions validation/standard/params.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package standard

import (
"fmt"
"math/big"

"github.com/ethereum-optimism/superchain-registry/superchain"
Expand All @@ -24,10 +25,9 @@ type SystemConfig struct {
GasLimit [2]uint64 `toml:"gas_limit"`
}

type BigIntBounds = [2]*big.Int

type (
Uint32Bounds = [2]uint32
BigIntBounds [2]*big.Int
Uint32Bounds [2]uint32
PreEcotoneGasPriceOracleBounds struct {
Decimals BigIntBounds `toml:"decimals"`
Overhead BigIntBounds `toml:"overhead"`
Expand Down Expand Up @@ -60,3 +60,114 @@ type Params struct {
GPOParams GasPriceOracleBounds `toml:"gas_price_oracle"`
SystemConfig SystemConfig `toml:"system_config"`
}

func (rc *ResourceConfig) Check() error {
if rc.MaxResourceLimit == 0 {
return fmt.Errorf("MaxResourceLimit is 0")
}
if rc.ElasticityMultiplier == 0 {
return fmt.Errorf("ElasticityMultiplier is 0")
}
if rc.BaseFeeMaxChangeDenominator == 0 {
return fmt.Errorf("BaseFeeMaxChangeDenominator is 0")
}
if rc.MinimumBaseFee == 0 {
return fmt.Errorf("MinimumBaseFee is 0")
}
if rc.SystemTxMaxGas == 0 {
return fmt.Errorf("SystemTxMaxGas is 0")
}
if rc.MaximumBaseFee == nil || rc.MaximumBaseFee.Cmp(big.NewInt(0)) == 0 {
return fmt.Errorf("MaximumBaseFee is 0 or nil")
}
return nil
}

func (sc *SystemConfig) Check() error {
if sc.GasLimit[1] == 0 {
return fmt.Errorf("GasLimit upper bound is 0")
}
return nil
}

func (bb BigIntBounds) Check() error {
if bb[1] == nil || bb[1].Cmp(big.NewInt(0)) == 0 {
return fmt.Errorf("BigIntBounds upper bound is 0 or nil")
}
return nil
}

func (ub Uint32Bounds) Check() error {
if ub[1] == 0 {
return fmt.Errorf("Uint32Bounds upper bound is 0")
}
return nil
}

func (pe *PreEcotoneGasPriceOracleBounds) Check() error {
if err := pe.Decimals.Check(); err != nil {
return fmt.Errorf("Decimals: %w", err)
}
if err := pe.Overhead.Check(); err != nil {
return fmt.Errorf("Overhead: %w", err)
}
if err := pe.Scalar.Check(); err != nil {
return fmt.Errorf("Scalar: %w", err)
}
return nil
}

func (ec *EcotoneGasPriceOracleBounds) Check() error {
if err := ec.Decimals.Check(); err != nil {
return fmt.Errorf("Decimals: %w", err)
}
if err := ec.BlobBaseFeeScalar.Check(); err != nil {
return fmt.Errorf("BlobBaseFeeScalar: %w", err)
}
if err := ec.BaseFeeScalar.Check(); err != nil {
return fmt.Errorf("BaseFeeScalar: %w", err)
}
return nil
}

func (rc *RollupConfigBounds) Check() error {
if rc.BlockTime[1] == 0 {
return fmt.Errorf("BlockTime upper bound is 0")
}
if rc.SequencerWindowSize[1] == 0 {
return fmt.Errorf("SequencerWindowSize upper bound is 0")
}
return nil
}

func (op *OptimismPortal2Bounds) Check() error {
if op.ProofMaturityDelaySeconds[1] == 0 {
return fmt.Errorf("ProofMaturityDelaySeconds upper bound is 0")
}
if op.DisputeGameFinalityDelaySeconds[1] == 0 {
return fmt.Errorf("DisputeGameFinalityDelaySeconds upper bound is 0")
}
return nil
}

func (p *Params) Check() error {
if err := p.RollupConfig.Check(); err != nil {
return fmt.Errorf("RollupConfig: %w", err)
}
if err := p.OptimismPortal2Config.Check(); err != nil {
return fmt.Errorf("OptimismPortal2Config: %w", err)
}
if err := p.ResourceConfig.Check(); err != nil {
return fmt.Errorf("ResourceConfig: %w", err)
}
if err := p.GPOParams.PreEcotone.Check(); err != nil {
return fmt.Errorf("PreEcotone: %w", err)
}
if err := p.GPOParams.Ecotone.Check(); err != nil {
return fmt.Errorf("Ecotone: %w", err)
}
if err := p.SystemConfig.Check(); err != nil {
return fmt.Errorf("SystemConfig: %w", err)
}
return nil
}

0 comments on commit c56b992

Please sign in to comment.