Skip to content

Conversation

@tac0turtle
Copy link
Contributor

Description

This pr adds a e2e test for verifying the contract size limit is handled correctly.

@claude
Copy link

claude bot commented Jan 10, 2026

Claude finished @tac0turtle's task —— View job


PR Review: E2E Test for Contract Size

I've completed my review of this PR that adds contract size limit validation functionality and e2e tests. Here's my comprehensive feedback:

Todo List:

  • Read and analyze all modified files
  • Review code quality and best practices
  • Check for potential bugs or issues
  • Assess performance considerations
  • Identify security concerns
  • Evaluate test coverage
  • Provide comprehensive feedback

Strengths

Excellent Test Coverage & Design:

  • Comprehensive E2E Testing: The new test_e2e_contract_size_limit_allows_oversized_deploy() test provides end-to-end validation of the contract size limit feature
  • Proper Test Isolation: Uses dedicated chain specs and test fixtures to avoid interference
  • Real-world Scenario Testing: Tests actual contract deployment with oversized bytecode (32KB), exceeding the standard EIP-170 limit (24KB)

Clean Architecture & Implementation:

  • Consistent Pattern: Follows the same activation height pattern as other configurable features (base fee redirect, mint precompile)
  • Proper Separation of Concerns: Configuration logic in config.rs, factory integration in factory.rs, test utilities in common.rs
  • Type Safety: Uses usize for size limits and u64 for activation heights with proper validation

Configuration Validation:

  • Robust Validation Logic: Prevents invalid configurations (size limit = 0, activation height without limit)
  • Sensible Defaults: Falls back to EIP-170 default (24KB) when custom limit isn't configured

🔧 Minor Issues & Suggestions

1. Magic Number Documentation (crates/tests/src/e2e_tests.rs:65, 422)

const OVERSIZED_RUNTIME_SIZE: usize = 32 * 1024;

Suggestion: Add documentation explaining why 32KB was chosen:

/// Contract size larger than EIP-170 default (24KB) but within custom limit (64KB)
const OVERSIZED_RUNTIME_SIZE: usize = 32 * 1024;

2. Test Assertion Enhancement (crates/tests/src/e2e_tests.rs:488-489)

assert_eq!(code.len(), OVERSIZED_RUNTIME_SIZE, "deployed contract should exceed the default size limit");
assert!(code.len() > 24 * 1024);

Suggestion: The second assertion is redundant since OVERSIZED_RUNTIME_SIZE is already 32KB. Consider a more descriptive message:

assert_eq!(code.len(), OVERSIZED_RUNTIME_SIZE, "deployed contract should be 32KB");
assert!(code.len() > DEFAULT_CONTRACT_SIZE_LIMIT, "contract should exceed EIP-170 default");

3. Error Handling Specificity (crates/node/src/config.rs:126-128)

The validation logic is correct but could be more explicit about which error condition triggered.


Code Quality Assessment

Best Practices Adherence:

  • ✅ Follows Rust naming conventions consistently
  • ✅ Proper use of const for compile-time constants
  • ✅ Appropriate error types with thiserror
  • ✅ Comprehensive unit tests for configuration logic
  • ✅ Uses proper RLP encoding for test transactions

Performance Considerations:

  • Efficient Lookups: Block number comparisons use simple integer arithmetic
  • Lazy Evaluation: Contract size limits only computed when needed
  • Memory Efficient: No unnecessary allocations in hot paths

Security Considerations:

  • Input Validation: Prevents zero size limits and malformed configurations
  • Safe Arithmetic: Uses proper bounds checking for size calculations
  • Controlled Feature Activation: Activation heights prevent accidental early enabling

📋 Test Coverage Analysis

The PR significantly enhances test coverage:

New Test Coverage:

  • Unit Tests: Configuration parsing, validation, and activation logic (config.rs:390-506)
  • Integration Tests: EVM factory behavior with custom limits (factory.rs:601-711)
  • E2E Tests: Full deployment workflow with oversized contracts (e2e_tests.rs:413-492)

Test Scenarios Covered:

  1. Configuration from chainspec - ✅
  2. Activation height respect - ✅
  3. Default fallback behavior - ✅
  4. Oversized contract rejection (default) - ✅
  5. Oversized contract acceptance (custom limit) - ✅
  6. Invalid configuration detection - ✅

📊 Technical Implementation Review

Factory Integration (crates/ev-revm/src/factory.rs:76-134)

  • Correct EVM Configuration: Properly sets evm_env.cfg_env.limit_contract_code_size
  • Activation Logic: Correctly compares block numbers for feature activation
  • Integration Points: Seamlessly integrates with existing EVM factory pattern

Configuration Management (crates/node/src/config.rs:97-118)

  • Chain Spec Integration: Properly deserializes from chain spec extras
  • API Design: Clean methods for querying configuration state
  • Edge Case Handling: Handles missing activation heights gracefully

🎯 Summary

This is a high-quality PR that implements contract size limit functionality following established patterns in the codebase. The implementation is:

  • Well-tested with comprehensive unit, integration, and e2e tests
  • Properly integrated with existing EVM factory and configuration systems
  • Security-conscious with input validation and safe activation logic
  • Performance-optimized with efficient runtime checks

The minor suggestions above are cosmetic improvements rather than functional issues. The PR is ready for approval with excellent adherence to the project's coding standards and architectural patterns.


📝 Files Reviewed:

  • crates/ev-revm/src/factory.rs (+146 lines) - EVM factory integration ✅
  • crates/node/src/config.rs (+31 lines) - Configuration management ✅
  • crates/tests/src/common.rs (+31 lines) - Test utilities ✅
  • crates/tests/src/e2e_tests.rs (+118 lines) - E2E test implementation ✅

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @tac0turtle, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the testing coverage for the contract size limit feature within the EVM and node configuration. It ensures that the system correctly enforces default contract size restrictions, allows for configurable overrides, and validates these configurations to prevent erroneous settings. The addition of both unit and end-to-end tests provides robust verification of this critical EVM behavior.

Highlights

  • New Test Cases for Contract Size Limits: Introduced unit tests in crates/ev-revm/src/factory.rs to validate the EVM's handling of contract size limits, specifically testing rejection of oversized code and successful deployment when a custom limit is configured.
  • Configuration Validation Enhancements: Modified EvolvePayloadBuilderConfig::validate in crates/node/src/config.rs to enforce stricter rules for contract size limit configurations, preventing invalid settings like a zero limit or an activation height without a defined limit.
  • E2E Test for Custom Contract Size Limits: Added an end-to-end test in crates/tests/src/e2e_tests.rs to confirm that the system correctly applies and allows deployment of contracts exceeding the default size when a custom contract size limit is specified in the chain specification.
  • Test Utility Functions: Introduced helper functions like oversized_initcode (in both ev-revm and e2e_tests for local context) and create_test_chain_spec_with_contract_size_limit to facilitate the creation of test scenarios involving various contract sizes and chain configurations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds e2e tests for contract size limits, along with the necessary configuration validation and test helpers. The changes are logically sound and the tests cover the intended functionality well. I've identified a few areas with code duplication across tests and test helpers. Addressing these will improve the long-term maintainability of the codebase. My comments provide specific suggestions for refactoring.

Comment on lines +601 to +711
#[test]
fn contract_size_limit_rejects_oversized_code() {
let caller = address!("0x0000000000000000000000000000000000000abc");
let initcode = oversized_initcode(OVERSIZED_RUNTIME_SIZE);

let mut state = empty_state();
state.insert_account(
caller,
AccountInfo {
balance: U256::from(10_000_000_000u64),
nonce: 0,
code_hash: KECCAK_EMPTY,
code: None,
},
);

let mut evm_env: alloy_evm::EvmEnv<SpecId> = EvmEnv::default();
evm_env.cfg_env.chain_id = 1;
evm_env.cfg_env.spec = SpecId::CANCUN;
evm_env.block_env.number = U256::from(1);
evm_env.block_env.basefee = 1;
evm_env.block_env.gas_limit = 30_000_000;

let mut evm = EvEvmFactory::new(alloy_evm::eth::EthEvmFactory::default(), None, None, None)
.create_evm(state, evm_env);

let tx = crate::factory::TxEnv {
caller,
kind: TxKind::Create,
gas_limit: 15_000_000,
gas_price: 1,
value: U256::ZERO,
data: initcode,
..Default::default()
};

let result_and_state = evm
.transact_raw(tx)
.expect("oversized create executes to a halt");

let ExecutionResult::Halt { reason, .. } = result_and_state.result else {
panic!("expected oversized code to halt");
};
assert!(
matches!(reason, HaltReason::CreateContractSizeLimit),
"expected create code size limit halt"
);
}

#[test]
fn contract_size_limit_allows_oversized_code_when_configured() {
let caller = address!("0x0000000000000000000000000000000000000def");
let initcode = oversized_initcode(OVERSIZED_RUNTIME_SIZE);

let mut state = empty_state();
state.insert_account(
caller,
AccountInfo {
balance: U256::from(10_000_000_000u64),
nonce: 0,
code_hash: KECCAK_EMPTY,
code: None,
},
);

let mut evm_env: alloy_evm::EvmEnv<SpecId> = EvmEnv::default();
evm_env.cfg_env.chain_id = 1;
evm_env.cfg_env.spec = SpecId::CANCUN;
evm_env.block_env.number = U256::from(1);
evm_env.block_env.basefee = 1;
evm_env.block_env.gas_limit = 30_000_000;

let mut evm = EvEvmFactory::new(
alloy_evm::eth::EthEvmFactory::default(),
None,
None,
Some(ContractSizeLimitSettings::new(64 * 1024, 0)),
)
.create_evm(state, evm_env);

let tx = crate::factory::TxEnv {
caller,
kind: TxKind::Create,
gas_limit: 15_000_000,
gas_price: 1,
value: U256::ZERO,
data: initcode,
..Default::default()
};

let result_and_state = evm.transact_raw(tx).expect("oversized create executes");

let ExecutionResult::Success { .. } = result_and_state.result else {
panic!("expected oversized code to deploy with custom limit");
};

let created_address = result_and_state
.result
.created_address()
.expect("created address available");
let state: EvmState = result_and_state.state;
let created_account = state
.get(&created_address)
.expect("created contract must be in state");
let code = created_account.info.code.as_ref().expect("code stored");
assert_eq!(
code.len(),
OVERSIZED_RUNTIME_SIZE,
"contract runtime size should match initcode payload"
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

There's significant code duplication between contract_size_limit_rejects_oversized_code and contract_size_limit_allows_oversized_code_when_configured. The setup for state, caller account, and evm_env is nearly identical.

To improve readability and maintainability, consider extracting this common setup into a helper function. This function could take the ContractSizeLimitSettings as a parameter and return the configured EVM instance and other necessary test data.

Comment on lines +59 to +88
/// Creates a reusable chain specification with a custom contract size limit.
pub fn create_test_chain_spec_with_contract_size_limit(
contract_size_limit: usize,
activation_height: Option<u64>,
) -> Arc<ChainSpec> {
let mut genesis: Genesis =
serde_json::from_str(include_str!("../assets/genesis.json")).expect("valid genesis");

let mut extras = serde_json::Map::new();
extras.insert("contractSizeLimit".to_string(), json!(contract_size_limit));
if let Some(height) = activation_height {
extras.insert(
"contractSizeLimitActivationHeight".to_string(),
json!(height),
);
}

genesis
.config
.extra_fields
.insert("evolve".to_string(), serde_json::Value::Object(extras));

Arc::new(
ChainSpecBuilder::default()
.chain(reth_chainspec::Chain::from_id(TEST_CHAIN_ID))
.genesis(genesis)
.cancun_activated()
.build(),
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The logic for creating a ChainSpec (loading genesis, building with ChainSpecBuilder) is duplicated between this new function create_test_chain_spec_with_contract_size_limit and the existing create_test_chain_spec_with_extras.

To reduce duplication, you could refactor create_test_chain_spec_with_extras to be more generic, allowing it to handle different "extra" configurations, and have the public helper functions call it. This would centralize the ChainSpec creation logic.

Comment on lines +81 to +112
fn oversized_initcode(runtime_size: usize) -> Bytes {
const INIT_PREFIX_LEN: usize = 14;

assert!(
runtime_size <= u16::MAX as usize,
"runtime size must fit in PUSH2"
);

let size_hi = ((runtime_size >> 8) & 0xff) as u8;
let size_lo = (runtime_size & 0xff) as u8;
let mut initcode = Vec::with_capacity(INIT_PREFIX_LEN + runtime_size);

initcode.extend_from_slice(&[
0x61,
size_hi,
size_lo, // PUSH2 size
0x60,
INIT_PREFIX_LEN as u8, // PUSH1 offset
0x60,
0x00, // PUSH1 0
0x39, // CODECOPY
0x61,
size_hi,
size_lo, // PUSH2 size
0x60,
0x00, // PUSH1 0
0xf3, // RETURN
]);
initcode.resize(INIT_PREFIX_LEN + runtime_size, 0u8);

Bytes::from(initcode)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This oversized_initcode function is a duplicate of the one found in crates/ev-revm/src/factory.rs. To improve maintainability and avoid inconsistencies, this function should be defined in a single, shared location.

Consider creating a common test utility module or crate (e.g., a test-utils crate or exposing it from ev-revm under a test-utils feature flag) that both ev-revm's tests and the e2e tests can depend on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants