Skip to content

feat(test-benchmark): storage initialization helper with 7702 authorization#2672

Open
LouisTsai-Csie wants to merge 3 commits intoethereum:forks/amsterdamfrom
LouisTsai-Csie:refactor-bal-benchmark
Open

feat(test-benchmark): storage initialization helper with 7702 authorization#2672
LouisTsai-Csie wants to merge 3 commits intoethereum:forks/amsterdamfrom
LouisTsai-Csie:refactor-bal-benchmark

Conversation

@LouisTsai-Csie
Copy link
Copy Markdown
Collaborator

@LouisTsai-Csie LouisTsai-Csie commented Apr 14, 2026

🗒️ Description

In the pre-allocation phase that deploys a contract, the framework supports passing in a dictionary that represents the storage to be initialized, and then embeds the logic inside the initcode. When the contract is created, it executes the initcode and performs the storage update.

However, in most of the benchmark cases, this is too inefficient, since the initialization phase requires a huge range of storage initialization, it leads to an initcode prefix too long issue.

Solution

To resolve this issue, we create a helper for the stateful benchmark scenario. Users can define a storage init range like this:

@dataclass(frozen=True)
class StorageInitRange:
    """One contiguous range of storage to initialize."""

    start_slot: int
    num_slots: int
    offset: int

Which means the storage would be initialized to STORAGE[i] = i + offset, where i starts from start_slot to start_slot + num_slots.

We leverage the EIP-7702 authorization approach for testing. The workflow now becomes:

  1. Delegate the authority to the storage initialization contract (create_sequential_sstore_initializer).
  2. Initialize the specified range — this leverages IteratingBytecode with transactions_by_iteration_counts.
  3. Pack the initialization transactions into blocks under the setup phase.
  4. Re-delegate the authority to the real benchmarking execution code.
  5. Start the BAL benchmarking phase.

Design decisions

  • The authority EOA is created in the BAL benchmark test, not inside the helper function. This provides the flexibility to use a stub account if needed.
  • Nonces use authority.nonce (incremented in-place) rather than hardcoded constants, ensuring compatibility with execute-remote where nonces are fetched from the live network.
  • Shared helpers (build_sequential_storage_init, StorageInitRange, etc.) live in tests/benchmark/stateful/helpers.py so they are reusable beyond the BAL tests.

🔗 Related Issues or PRs

N/A.

✅ Checklist

  • All: Ran fast static checks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:
    just static
  • All: PR title adheres to the repo standard - it will be used as the squash commit message and should start type(scope):.
  • All: Considered updating the online docs in the ./docs/ directory.
  • All: Set appropriate labels for the changes (only maintainers can apply labels).
  • Tests: Ran mkdocs serve locally and verified the auto-generated docs for new tests in the Test Case Reference are correctly formatted.
  • Tests: For PRs implementing a missed test case, update the post-mortem document to add an entry the list.
  • Ported Tests: All converted JSON/YML tests from ethereum/tests or tests/static have been assigned @ported_from marker.

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

@LouisTsai-Csie LouisTsai-Csie marked this pull request as ready for review April 14, 2026 08:10
@LouisTsai-Csie
Copy link
Copy Markdown
Collaborator Author

For @jochem-brouwer and @nerolation , you could focus on create_sequential_sstore_initializer and related logic. For create_sstore_initializer and build_delegated_storage_setup, i just move them out of the test_single_opcode.py file, no logic changes. You could ignore this as it is irrelevant to BAL benchmark

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.25%. Comparing base (a830dab) to head (b57e961).

Additional details and impacted files
@@               Coverage Diff                @@
##           forks/amsterdam    #2672   +/-   ##
================================================
  Coverage            86.25%   86.25%           
================================================
  Files                  599      599           
  Lines                37032    37032           
  Branches              3795     3795           
================================================
  Hits                 31943    31943           
  Misses                4525     4525           
  Partials               564      564           
Flag Coverage Δ
unittests 86.25% <ø> (ø)

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.

Copy link
Copy Markdown
Member

@jochem-brouwer jochem-brouwer left a comment

Choose a reason for hiding this comment

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

Some questions about the storage logic 😄 👍

a storage-initializer contract (if *needs_init*), then to the
benchmark executor contract. Return the list of setup blocks.
"""
blocks: list[Block] = []
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this method be wrapped in TestPhaseManager.setup() ?

start_iteration=1,
calldata=initializer_calldata_generator,
)
iteration_count = max(1, tx_gas_limit // iteration_cost)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this should be ceil(tx_gas_limit // iteration_cost)?

Suggested change
iteration_count = max(1, tx_gas_limit // iteration_cost)
iteration_count = ceil(tx_gas_limit // iteration_cost)


# Final block: Authorize to executor
blocks.append(
Block(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this should read the nonce for the authority EOA variable. If we use a test which has to delegate again after the setup, then we must ensure the nonce is correct 🤔

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