Skip to content

Conversation

@CPerezz
Copy link
Contributor

@CPerezz CPerezz commented Jan 2, 2026

Summary

This PR adds a new extcodesize_setup scenario that deploys contracts for EXTCODESIZE benchmarks in execution-spec-tests. See: ethereum/execution-specs#1961 for the related PR which introduces the test case.

Features

  • Deploys initcode contracts that generate bytecode of specific sizes (0.5, 1, 2, 5, 10, 24 KB) using keccak256 expansion loops
  • Deploys CREATE2 factory contracts that use EXTCODECOPY to deploy contracts with unique bytecode per deployment
  • Supports parallel deployment using multiple wallets (default 50)
  • Dynamic gas calculation based on contract size and block gas limit
  • Outputs factory addresses in stubs.json format for execution-spec-tests compatibility
  • Supports pre-deployed addresses via YAML config

- Implements new `storage-trie-brancher` scenario that replicates Python `deploy_deep_branches.py` functionality (See: ethereum/execution-specs#1937)
- Enables deployment of contracts designed to create worst-case storage trie depth scenarios (See https://github.com/CPerezz/worst_case_miner/settings)
- Automatically handles Nick's factory deployment if not present on network.
- Add loadDataFromPathOrURL helper function to load files from URLs or local paths
- Support HTTP/HTTPS URLs for both --data-file and --contract-file flags
- Download contract files to temp directory before compilation when using URLs
- Add comprehensive YAML configuration examples to README
- Document URL loading capabilities with examples

This allows users to load deployment data and Solidity contracts from external
sources like GitHub raw URLs or any HTTP server, enabling more flexible
deployment workflows.
Remove all local JSON and Solidity files from the storage_trie_brancher scenario
directory since the scenario now supports loading these files from external URLs
(GitHub gists, repositories, or any HTTP server).

Removed files:
- All s*_acc*.json deployment data files
- All depth_*.sol Solidity contract files
- deployed_contracts.json output file
- stubs.json test file

Users should now load these files from external sources using the --data-file
and --contract-file flags with HTTP/HTTPS URLs.
Major changes to support running in Docker containers:

1. Replaced Solidity compilation with direct bytecode loading:
   - Removed solc dependency (not available in Docker)
   - Added --bytecode flag to accept hex bytecode directly
   - Supports loading bytecode from string, file path, or URL
   - Removed --contract-file flag

2. Replaced file writing with structured logging:
   - Removed saveDeploymentInfo() that wrote to filesystem
   - Added logDeploymentInfo() that outputs to logs
   - Deployment summary logged at INFO level
   - Full deployment data available at DEBUG level with --log-txs
   - No dependency on scenario directory structure

3. Made data-file and bytecode required parameters:
   - Removed auto-detection logic that relied on file paths
   - Users must explicitly provide both parameters
   - Supports URLs for both data and bytecode

4. Fixed calculateCreate2Address to use factory address:
   - Now uses s.factoryAddress instead of hardcoded NickFactoryAddress
   - Correctly handles dynamic factory addresses

5. Updated documentation:
   - README examples now use --bytecode instead of --contract-file
   - Added examples for URL-based loading
   - Clarified required parameters

These changes ensure the scenario works properly in containerized
environments where only the spamoor binary is available.
…ark contracts

This scenario deploys initcode contracts, CREATE2 factory contracts, and test
contracts of various sizes (0.5, 1, 2, 5, 10, 24 KB) for EXTCODESIZE benchmarks.

Features:
- Deploys initcode contracts that generate bytecode of specific sizes using
  keccak256 expansion loops
- Deploys CREATE2 factory contracts that use EXTCODECOPY to deploy contracts
  with unique bytecode
- Supports parallel deployment using multiple wallets (default 50)
- Dynamic gas calculation based on contract size and block gas limit
- Outputs factory addresses in stubs.json format for execution-spec-tests
- Supports pre-deployed addresses via YAML config
@CPerezz CPerezz force-pushed the feat/deployment_for_extcodesize_setup branch from 5d544f0 to 03433cf Compare January 3, 2026 07:05
Signed-off-by: CPerezz <37264926+CPerezz@users.noreply.github.com>
@jochem-brouwer
Copy link

One quick Q: for the bytecode contracts with specific depth, does it deploy extra unique storage field(s) per contract?

The reason I ask is, if you have mined specific depths, (so depth 10 is SSTOREing 10-ish mined key/value items) then without adding anything the storage root will be the same. So in theory, if we would do any modification (on all of these duplicates) then clients could cache this result instead of forcing them to go to disk and read these values.

(A simple way to do so is to SSTORE(0, Op.ADDRESS), or SSTORE(Op.ADDRESS, Op.ADDRESS), to guarantee each contract has an unique storage trie)

@CPerezz
Copy link
Contributor Author

CPerezz commented Jan 7, 2026

One quick Q: for the bytecode contracts with specific depth, does it deploy extra unique storage field(s) per contract?

The reason I ask is, if you have mined specific depths, (so depth 10 is SSTOREing 10-ish mined key/value items) then without adding anything the storage root will be the same. So in theory, if we would do any modification (on all of these duplicates) then clients could cache this result instead of forcing them to go to disk and read these values.

(A simple way to do so is to SSTORE(0, Op.ADDRESS), or SSTORE(Op.ADDRESS, Op.ADDRESS), to guarantee each contract has an unique storage trie)

How are you going to cache? You cache based on positions (keys) in the tree IIUC. Thus, you can't cache predicting that the storage of a contract will be exactly the same as one you already have.

Nevertheless, we can change the attack tx st. we get different values at the deepest key and therefore, different roots for every contract. Would you prefer that?

@jochem-brouwer
Copy link

Yes, I'm not saying that this happens in practice, but there could be cases especially for small contracts (~50 keys or less) where the entire contract just is kept in memory. Notice that the storage root of the contract is the "fingerprint", if we have equal roots we know the DBs are the same. We therefore don't have to make a copy of that storage trie into our memory, we can just point two contracts to the same storage trie in memory (this is handy for reading). By forcing different state roots it is not possible to use these kind of tactics.
I don't think this happens in practice, but to be sure, we should add just one Op.ADDRESS + Op.ADDRESS + Op.SSTORE to the initcode of the contract to ensure that each storage trie is unique and different 😄 👍

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