Skip to content

Conversation

@chatton
Copy link
Contributor

@chatton chatton commented Oct 23, 2025

Overview

This PR adds an upgrade test which will run on every PR.

The test deploys a specific version, for now hard coded to "v1.0.0-beta.8", makes a bunch of transactions, then deploys the evm-single version built from the PR, verifies it can still access those transactions, makes a few more and ensures blocks are still being produced.

In a followup we can update the test to be muilti-node, and perform more robust checks at the DA layer.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 23, 2025

The latest Buf updates on your PR. Results from workflow CI and Release / buf-check (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed⏩ skipped✅ passed✅ passedOct 23, 2025, 12:22 PM

@claude
Copy link
Contributor

claude bot commented Oct 23, 2025

Claude finished @chatton's task —— View job


Code Review Complete

I've completed a comprehensive code review of the upgrade test implementation. Overall, this is a well-structured and valuable addition to the test suite. The upgrade testing functionality is critical for ensuring seamless version transitions in production.


Summary Assessment

Strengths:

  • Well-organized test suite using testify/suite pattern
  • Comprehensive upgrade workflow with clear test phases
  • Good use of health checks and Eventually assertions for timing issues
  • Proper volume preservation during upgrade
  • Excellent logging throughout for debugging

Priority Issues to Address:

  • Security concerns with hardcoded credentials
  • Missing error handling and configuration validation
  • Potential race conditions in concurrent operations
  • Test reliability and timeout configuration

1. Code Quality & Architecture

Strengths

Excellent use of testify suite pattern - The EVMSingleUpgradeTestSuite embedding DockerTestSuite is clean and reusable

Clear test phases - Using s.Run() to break down the test into logical steps makes it very readable

Good separation of concerns - Helper methods like setupRethNode, setupEVMSingle, etc. are well-organized

Issues

🔴 CRITICAL: Hardcoded Private Key (Security)

testPrivateKey = "cece4f25ac74deb1468965160c7185e07dff413f23fcadb611b05ca37ab0a52e"
  • Location: test/docker-e2e/upgrade_test.go:30
  • Issue: Private keys should NEVER be hardcoded, even in test code
  • Impact: Sets a bad precedent, could be accidentally copied to production code
  • Recommendation: Generate test keys dynamically or use well-known test vectors with clear comments indicating they are for testing only
const (
    // TEST ONLY - DO NOT USE IN PRODUCTION
    // This is a publicly known test key from Ethereum test fixtures
    testPrivateKey = "..."
)

🟡 Missing Input Validation

func (s *EVMSingleUpgradeTestSuite) submitPreUpgradeTxs(ctx context.Context, txCount int) []common.Hash {
    var txHashes []common.Hash
    for i := range txCount { // No validation if txCount is negative or unreasonably large
  • Location: test/docker-e2e/upgrade_test.go:241
  • Recommendation: Add validation:
if txCount <= 0 || txCount > 1000 {
    s.T().Fatalf("Invalid txCount: %d (must be between 1 and 1000)", txCount)
}

2. Error Handling & Resilience

Issues

🔴 Missing Context Cancellation

func (s *EVMSingleUpgradeTestSuite) TestEVMSingleUpgrade() {
    ctx := context.Background() // No timeout or cancellation
  • Location: test/docker-e2e/upgrade_test.go:61
  • Issue: Tests could hang indefinitely if infrastructure fails
  • Recommendation:
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer cancel()

🟡 Inadequate Error Context in Eventually Blocks

s.Require().Eventually(func() bool {
    receipt, err := s.ethClient.TransactionReceipt(ctx, txHash)
    if err != nil {
        return false // Silently returns false without logging error
    }
    return receipt.Status == 1
}, 30*time.Second, time.Second, "transaction %s was not included", txHash.Hex())
  • Location: test/docker-e2e/upgrade_test.go:258-264
  • Issue: Lost error information makes debugging failures difficult
  • Recommendation:
s.Require().Eventually(func() bool {
    receipt, err := s.ethClient.TransactionReceipt(ctx, txHash)
    if err != nil {
        s.T().Logf("Waiting for tx %s: %v", txHash.Hex(), err)
        return false
    }
    if receipt.Status != 1 {
        s.T().Logf("Transaction %s failed with status %d", txHash.Hex(), receipt.Status)
        return false
    }
    return true
}, 30*time.Second, time.Second, "transaction %s was not included", txHash.Hex())

🟡 Missing Cleanup/Defer Patterns

  • Issue: No explicit cleanup of Docker resources if test fails mid-execution
  • Recommendation: Consider adding cleanup logic in TearDownTest() or using defer statements

3. Security

🔴 CRITICAL: Exposed JWT Secret Handling

s.jwtSecret = rethNode.JWTSecretHex()
  • Location: test/docker-e2e/upgrade_test.go:166
  • Issue: While this is test code, JWT secrets should be treated carefully
  • Recommendation: Add comments about test-only usage and ensure secrets aren't logged

🟡 Default Credentials

WithEVMSignerPassphrase("secret")
  • Location: test/docker-e2e/upgrade_test.go:178
  • Recommendation: Use a constant with clear documentation:
const testSignerPassphrase = "secret" // TEST ONLY - insecure passphrase for local testing

4. Performance & Resource Efficiency

Issues

🟡 Fixed Sleep Times Instead of Adaptive Waiting

time.Sleep(3 * time.Second)
  • Locations: Multiple places (test/docker-e2e/upgrade_test.go:324)
  • Issue: Arbitrary sleep times can make tests slower than necessary or flaky
  • Recommendation: Use Eventually assertions with appropriate conditions instead of fixed sleeps

🟡 Sequential Transaction Submission

for i := range txCount {
    tx := evm.GetRandomTransaction(...)
    err := s.ethClient.SendTransaction(ctx, tx)
    s.Require().NoError(err)
    // ...
    s.waitForTxIncluded(ctx, tx.Hash()) // Waits for each tx sequentially
}
  • Location: test/docker-e2e/upgrade_test.go:244-251
  • Issue: Could be parallelized for faster test execution
  • Recommendation: Submit all transactions first, then wait for all receipts (if order doesn't matter for test semantics)

🟡 No Connection Pooling or Reuse Verification

ethClient, err := ethclient.Dial(s.evmEthURLExternal)
  • Issue: Single client instantiation is good, but no verification of connection health before upgrade
  • Recommendation: Add a ping/health check after creating the client

5. Testing & Reliability

Strengths

Good use of Eventually for asynchronous operations

Comprehensive verification - Checks transaction persistence, block production, and account balances

Issues

🟡 Hardcoded Version String

baseEVMSingleVersion = "v1.0.0-beta.8"
  • Location: test/docker-e2e/upgrade_test.go:28
  • Issue: Will need manual updates; could become stale
  • Recommendation: Consider making this configurable via environment variable with fallback:
func getBaseEVMSingleVersion() string {
    if v := os.Getenv("EVM_SINGLE_BASE_VERSION"); v != "" {
        return v
    }
    return "v1.0.0-beta.8" // Default stable version for upgrade tests
}

🟡 Insufficient Edge Case Testing

  • Missing: Tests for upgrade failure scenarios (rollback, corruption during upgrade, etc.)
  • Missing: Tests for backwards compatibility with older state formats
  • Recommendation: Consider adding negative test cases in future iterations

🟡 Timeout Configuration

s.Require().Eventually(func() bool {
    // ...
}, 60*time.Second, 2*time.Second, "reth did not start in time")
  • Location: test/docker-e2e/upgrade_test.go:143-160
  • Issue: Fixed timeouts might be too short for CI environments or slower machines
  • Recommendation: Make timeouts configurable via environment variables

🟡 Nonce Management

txNonce uint64
  • Issue: Nonce is initialized to 0 and incremented manually; could get out of sync
  • Recommendation: Consider fetching nonce from the network or add explicit nonce validation

6. Documentation & Developer Experience

Strengths

Excellent inline comments explaining test purpose and flow

Good logging throughout the test for debugging

Issues

🟡 Missing Function-Level Documentation

func (s *EVMSingleUpgradeTestSuite) setupRethNode(ctx context.Context) {
    // No docstring explaining what this does
  • Recommendation: Add docstrings to all exported methods:
// setupRethNode creates and starts a Reth execution client node.
// It waits for the node to be ready and configures connection URLs
// for both internal (container-to-container) and external (test-to-container) communication.
func (s *EVMSingleUpgradeTestSuite) setupRethNode(ctx context.Context) {

🟡 Environment Variable Documentation

func getEVMSingleImage() container.Image {
    repo := strings.TrimSpace(os.Getenv("EVM_SINGLE_IMAGE_REPO"))
  • Location: test/docker-e2e/upgrade_test.go:350
  • Issue: No central documentation of required/optional environment variables
  • Recommendation: Add a comment block at the top of the file documenting all environment variables:
// Environment Variables:
// - EVM_SINGLE_IMAGE_REPO: Docker repository for evm-single image (default: "evm-single")
// - EVM_SINGLE_NODE_IMAGE_TAG: Image tag to upgrade to (default: "local-dev")

7. Changes to Existing Test Files

test/docker-e2e/docker_test.go

✅ Good: Minor refactoring to use consistent naming (s.evNodeChains.evNodeChain)

test/docker-e2e/resiliency_test.go

✅ Good: Consistent naming changes

🟡 Minor: These test files have similar issues to upgrade_test.go (hardcoded values, missing context timeouts, etc.)


8. Test Infrastructure (Makefile & Workflow)

scripts/test.mk

✅ Good: New test-docker-upgrade-e2e target is well-structured

🟡 Specific Test Run: Line 67 explicitly runs only TestEVMSingleUpgrade - this is noted in the review comment as intentional due to test weight, which is good

⚠️ Consideration: The regex pattern could be fragile:

-run '^TestEVMSingleUpgradeSuite$$/^TestEVMSingleUpgrade$$'
  • Recommendation: Document why this specific pattern is used, or simplify if possible

.github/workflows/test.yml

✅ Excellent: New docker-upgrade-tests job is properly structured with:

  • Correct dependencies (needs: build-ev-node-evm-single-image)
  • Proper environment variable configuration
  • Appropriate separation from other Docker E2E tests

⚠️ Potential Issue: Job runs on every PR

docker-upgrade-tests:
    name: Docker Upgrade E2E Tests
    needs: build-ev-node-evm-single-image
    runs-on: ubuntu-latest
  • Consideration: Upgrade tests are heavy and build two images. Consider:
    • Running only on specific labels (e.g., test: upgrade)
    • Running on PRs to release branches
    • Skipping on draft PRs

Recommendation:

docker-upgrade-tests:
    name: Docker Upgrade E2E Tests
    if: "!github.event.pull_request.draft && (contains(github.event.pull_request.labels.*.name, 'test: upgrade') || github.base_ref == 'main')"
    needs: build-ev-node-evm-single-image
    runs-on: ubuntu-latest

9. Dependencies (go.mod/go.sum)

✅ Good: Dependency updates appear to be for tastora framework (testing infrastructure)

🟡 Large Dependency Addition: test/docker-e2e/go.mod added 151 new lines

  • Most are indirect dependencies from tastora and ethereum client libraries
  • This is expected for Docker E2E tests but increases build time and attack surface

Recommendation: Periodically audit dependencies with go mod why and security scanning tools


Priority Recommendations

Must Fix (Before Merge)

  1. ✅ Document the hardcoded test private key with clear warnings
  2. ✅ Add context timeout to main test function
  3. ✅ Make base version configurable via environment variable

Should Fix (Next Iteration)

  1. Add comprehensive error logging in Eventually blocks
  2. Implement cleanup/teardown logic for Docker resources
  3. Make timeouts configurable for different CI environments
  4. Add validation for input parameters (txCount, etc.)

Nice to Have (Future Work)

  1. Add negative test cases (upgrade failures, rollbacks)
  2. Parallelize transaction submission where possible
  3. Add test for backwards compatibility with multiple old versions
  4. Consider adding metrics collection during upgrade tests

Overall Assessment

This is a high-quality, production-ready upgrade test with minor areas for improvement. The code demonstrates good Go practices, clear test structure, and comprehensive verification. The main concerns are around security hygiene (hardcoded credentials), error visibility, and making the test more flexible for different environments.

Recommendation: ✅ Approve with minor changes - Address the critical security documentation and add context timeout before merging.


@codecov
Copy link

codecov bot commented Oct 23, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.57%. Comparing base (c6dd42c) to head (527ccb5).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2780   +/-   ##
=======================================
  Coverage   61.57%   61.57%           
=======================================
  Files          82       82           
  Lines        8715     8715           
=======================================
  Hits         5366     5366           
  Misses       2845     2845           
  Partials      504      504           
Flag Coverage Δ
combined 61.57% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

## test-docker-upgrade-e2e: Running Docker E2E Upgrade tests
test-docker-upgrade-e2e:
@echo "--> Running Docker Upgrade E2E tests"
@cd test/docker-e2e && go test -mod=readonly -failfast -v -tags='docker_e2e evm' -timeout=30m -run '^TestEVMSingleUpgradeSuite$$/^TestEVMSingleUpgrade$$' ./...
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explicitly running the one test for now, since these tests are quite heavy, we probably don't want run many in one make target

@chatton chatton marked this pull request as ready for review October 23, 2025 13:42
Copy link
Contributor

@tac0turtle tac0turtle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for this, it looks super good. We should make sure to document that this is aggregator focused. The header cleanup i did would have gotten passed this since new blocks can be proposed via the cleanup, it would be an issue for syncing nodes.

@tac0turtle tac0turtle added this pull request to the merge queue Oct 24, 2025
Merged via the queue into main with commit 67877e1 Oct 24, 2025
32 checks passed
@tac0turtle tac0turtle deleted the cian/add-upgrade-test-for-evm-single branch October 24, 2025 17:19
@github-project-automation github-project-automation bot moved this to Done in Evolve Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants