Skip to content

Conversation

@Dargon789
Copy link
Owner

@Dargon789 Dargon789 commented Jun 15, 2025

What was wrong?

Related to Issue #
Closes #

How was it fixed?

Todo:

  • Clean up commit history
  • Add or update documentation related to these changes
  • Add entry to the release notes

Cute Animal Picture

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

Summary by Sourcery

Implement the Prague network upgrade and bump package version to 0.12.1-beta.1

New Features:

  • Introduce Prague fork as the new latest VM with accompanying block, header, state, computation, and transition logic
  • Add EIP-7702 SetCode transaction type with authorization lists and on-chain SetCodeAuthorizationAPI
  • Implement block request processing for deposit, withdrawal, and consolidation (requestsHash) per EIP-6110, EIP-7002, and EIP-7251
  • Add BLS12-381 precompiles (G1/G2 add, multi-scalar multiply, map to curve, pairing) for EIP-2537
  • Support EIP-7623 data floor gas calculations and adjust blob base fee updates for Prague

Enhancements:

  • Refactor transaction validation into shared validate_dynamic_fee_tx and new validate_nonce and validate_uint8 helpers
  • Extend call logic to handle code delegation and track gas refunds via a refund field on MessageAPI
  • Centralize account load fee logic in a BaseCallEIP2929 implementation

CI:

  • Add CircleCI and tox jobs for Prague native blockchain tests

Documentation:

  • Update README to describe Py-EVM as an Ethereum Virtual Machine reference implementation

Tests:

  • Add comprehensive tests for Prague transition chain, transaction builders (including SetCode), legacy transactions across forks, VM transitions, and fixture filtering for new EEST and legacy paths

Chores:

  • Bump version to 0.12.1-beta.1 and update bumpversion config
  • Upgrade eth-typing and py-ecc dependency bounds
  • Remove obsolete constants and helper functions in favor of shared utilities

fselmo and others added 30 commits April 21, 2025 13:49
- add ``fixtures_eest`` as a submodule; use ``v4.1.0`` tarball develop fixtures
- update ``fixtures`` to v14.1
- update fixture loader to pull in EEST and ethereum test fixtures
- take Pyspecs fixtures out entirely, rather than collecting & skipping.
- Initial 7702 Commit - ExtCode* opcodes
- 7702 CallCode opcode
- Update EXTCODE* opcodes
- 7702 StaticCall and DelegateCall opcodes
- Adds to Prague fork classes
- Comment out 7702 opcodes for now
- Transaction tests are running - not correct yet
- Fix lint issues; add 7702 TODOs
- Implement block requests and compute the block request hash for
  the block header, post-prague.

- Extend the block header for Prague blocks to include the ``requests_hash``.

- Some refactoring of block preprocessing to get ready for EIP-7002.
  This takes in the ``block``, not just the ``block.header`` as an
  argument so that we have access to the block requests.
- STANDARD_TOKEN_COST as per EIP-7623 is really just another
  way of calculating the current gas schedule. It factors the
  4 out of (4 * zero_bytes) + (16 * non_zero_bytes), leaving
  (zero_bytes + 4 * non_zero_bytes). Leave the current schedule
  untouched and instead compare this to the new data_floor when
  finalizing the computation, subtracting more gas if necessary
  until we reach the data floor cost.
- g1 add, msm, and map fp to g1
- g2 add, msm, and map fp2 to g2
- pairing

- bonus: bump py_ecc version
- newsfragment for #2204
- Still missing some eips so some test failures are expected
- For ethereum/tests, this is provided in the pre state.
  If users want this functionality for testing, we need to
  deploy these as the respective EIPs define.
- Some precompiles passing
- Add chainId check
- fix error msg typo
- Put back process_authorizations, use correct ecrecover
- Old Call tests passing
- Tests for extcodesize, extcodehash, and extcodecopy passing
- StaticCall tests down to 10 failing, some cleanup
- (DRY) Refactor ``BaseCall`` logic to accommodate some smaller
  changes to call opcodes so we don't have to re-write a bunch of
  code for Prague, only overwrite certain methods.

 - Keep static call logic unchanged.

 - Track message refunds separately. Even if computation fails,
   apply message refunds.

 - Fix some logic to match EIP.

 Along the way:

 - Logic for ``secp256k1n/2`` seems to have been wrong in py-evm.
   Fixed that check and added it to the auth validation.
- Do not pull data floor diff from refunds, nor attempt to use it
  from the computation gas itself. This should be calculated after
  refunds and separate from the computation gas.

- Add an extra ``data_floor_gas`` property to the computation that is
  calculated by the transaction executor. This value can be used to
  calculate the total gas used by the transaction at any point in the
  processing of the computation. This is useful when issueing refunds
  and when making the transaction receipt.
@sourcery-ai
Copy link

sourcery-ai bot commented Jun 15, 2025

Reviewer's Guide

This PR adds full support for the new Prague network upgrade, including a new SetCode transaction type (EIP-7702), block request processing (deposits, withdrawals, consolidations), updated gas accounting (data floor and extended refunds), unified call/delegation handling, consolidated transaction validation helpers, new BLS12-381 precompiles, and updates to versioning, fixtures, and tests.

Sequence Diagram: EIP-7702 SetCode Transaction Authorization Processing

sequenceDiagram
    participant TX as SetCode Transaction
    participant Executor as PragueTransactionExecutor
    participant State as PragueState
    participant EVM

    TX->>Executor: Submitted to network
    Executor->>State: calc_message_refund(TX)
    State->>State: process_set_code_authorizations(TX)
    loop for each auth in TX.authorization_list
        State->>State: auth.validate(chain_id)
        State->>EVM: ecrecover(MAGIC+rlp(auth.chain_id, auth.address, auth.nonce), auth.vrs) to get authority_address
        EVM-->>State: authority_address
        State->>State: mark_address_warm(authority_address)
        State->>State: code = get_code(authority_address)
        alt code is empty or delegation designation AND nonce matches
            State->>State: refund += PER_EMPTY_ACCOUNT_BASE_COST - PER_AUTH_BASE_COST (if account exists)
            State->>State: set_code(authority_address, DELEGATION_DESIGNATION_PREFIX + auth.address)
            State->>State: increment_nonce(authority_address)
        else Invalid Authorization
            State->>State: Continue to next auth
        end
    end
    State-->>Executor: message_refund (including auth_refunds)
Loading

Sequence Diagram: EVM Call Operation with Code Delegation (EIP-7702)

sequenceDiagram
    participant Caller as Calling Contract / EOA
    participant EVM as EVM Execution
    participant State as PragueState
    participant TargetContract as Target Contract Code
    participant DelegationContract as Delegated Contract Code

    Caller->>EVM: Initiates CALL/DELEGATECALL/STATICCALL/CALLCODE
    EVM->>EVM: Opcode (e.g., CallEIP7702) execution
    EVM->>State: get_code_at_address(code_source_address)
    activate State
    State->>State: real_code = get_code(code_source_address)
    alt real_code is Delegation Designation (e.g., EF0100 + delegation_addr)
        State->>State: delegation_address = extract_address(real_code)
        State->>State: mark_address_warm(delegation_address)
        State->>State: final_code = get_code(delegation_address)
        State-->>EVM: (final_code, delegation_address)
    else Not a Delegation
        State-->>EVM: (real_code, null)
    end
    deactivate State

    EVM->>EVM: Prepare child message (msg)
    EVM->>EVM: msg.is_delegation = (delegation_address is not null)
    EVM->>EVM: msg.code = final_code
    EVM->>EVM: msg.code_address = delegation_address or code_source_address

    alt Precompile Call AND msg.is_delegation is true
        EVM->>EVM: Skip precompile execution
        EVM-->>Caller: Return (e.g., error or specific result)
    else Regular Call or Non-Delegated Precompile
        EVM->>TargetContract/DelegationContract: Execute child computation with msg
        TargetContract/DelegationContract-->>EVM: Result
        EVM-->>Caller: Return result
    end
Loading

Sequence Diagram: PragueVM Block Post-Processing (Requests Hash)

sequenceDiagram
    participant BlockBuilder
    participant PragueVM
    participant State as PragueState
    participant DepositContract
    participant WithdrawalPredeploy
    participant ConsolidationPredeploy

    BlockBuilder->>PragueVM: mine_block(filled_block)
    PragueVM->>PragueVM: block_postprocessing(filled_block)
    activate PragueVM
    PragueVM->>PragueVM: process_deposit_request_data(block)
    PragueVM->>State: Iterate block.receipts for deposit events
    State-->>PragueVM: Deposit log data
    PragueVM->>PragueVM: block.block_requests.append(DEPOSIT_REQUEST_TYPE + data)

    PragueVM->>PragueVM: process_withdrawal_request_data(block)
    PragueVM->>State: get_code(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS)
    State-->>PragueVM: withdrawal_contract_code
    opt withdrawal_contract_code exists
        PragueVM->>WithdrawalPredeploy: execute_bytecode(...)
        WithdrawalPredeploy-->>PragueVM: withdrawal_computation.output
        PragueVM->>PragueVM: block.block_requests.append(WITHDRAWAL_REQUEST_TYPE + output)
    end

    PragueVM->>PragueVM: process_consolidation_request_data(block)
    PragueVM->>State: get_code(CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS)
    State-->>PragueVM: consolidation_contract_code
    opt consolidation_contract_code exists
        PragueVM->>ConsolidationPredeploy: execute_bytecode(...)
        ConsolidationPredeploy-->>PragueVM: consolidation_computation.output
        PragueVM->>PragueVM: block.block_requests.append(CONSOLIDATION_REQUEST_TYPE + output)
    end

    PragueVM->>PragueVM: compute_requests_hash(block)
    PragueVM->>PragueVM: header = block.header.copy(requests_hash=sha256(all_requests))
    PragueVM->>PragueVM: processed_block = block.copy(header=header)
    PragueVM-->>BlockBuilder: return processed_block
    deactivate PragueVM
Loading

ER Diagram: Core Data Model Changes in Prague Fork

erDiagram
    TRANSACTION_FIELDS_API {
        sequence_SetCodeAuthorizationAPI_ authorization_list "new"
    }

    SET_CODE_AUTHORIZATION_API {
        int chain_id
        Address address
        int nonce
        int y_parity
        int r
        int s
    }
    TRANSACTION_FIELDS_API ||--o{ SET_CODE_AUTHORIZATION_API : "has 0..* (via authorization_list)"

    AUTHORIZATION {
        int chain_id
        Address address
        int nonce
        int y_parity
        int r
        int s
    }
    AUTHORIZATION }|..|| SET_CODE_AUTHORIZATION_API : "implements"

    SET_CODE_TRANSACTION {
        int chain_id
        int nonce
        int max_priority_fee_per_gas
        int max_fee_per_gas
        int gas
        Address to
        int value
        bytes data
        sequence_AccountAccesses_ access_list
        sequence_Authorization_ authorization_list "new"
        int y_parity
        int r
        int s
    }
    SET_CODE_TRANSACTION ||--o{ AUTHORIZATION : "contains"

    BLOCK_API {
        list_bytes_ block_requests "new"
    }

    PRAGUE_BLOCK_HEADER {
        Hash32 requests_hash "new"
    }
    BLOCK_API ||--|{ PRAGUE_BLOCK_HEADER : "has a"

    MESSAGE_API {
        bool is_delegation "new"
        int refund "new"
    }

    COMPUTATION_API {
        int data_floor_gas "new"
    }

    TRANSACTION_CONTEXT_API {
        sequence_SetCodeAuthorizationAPI_ authorization_list "new, optional"
    }
Loading

Class Diagram: Prague EIP-7702 Transaction Structures

classDiagram
    direction LR
    class SetCodeAuthorizationAPI {
        <<Interface>>
        +chain_id int
        +address Address
        +nonce int
        +y_parity int
        +r int
        +s int
        +validate_for_transaction() None
        +validate(chain_id int) None
    }
    class Authorization {
        <<RLPSerializable>>
        +chain_id int
        +address Address
        +nonce int
        +y_parity int
        +r int
        +s int
    }
    Authorization ..|> SetCodeAuthorizationAPI : implements

    class TransactionFieldsAPI {
        <<Interface>>
        +max_fee_per_blob_gas int
        +blob_versioned_hashes Sequence~Hash32~
        +authorization_list Sequence~SetCodeAuthorizationAPI~
    }

    class UnsignedSetCodeTransaction {
        <<RLPSerializable>>
        +chain_id int
        +nonce int
        +max_priority_fee_per_gas int
        +max_fee_per_gas int
        +gas int
        +to Address
        +value int
        +data bytes
        +access_list Sequence
        +authorization_list Sequence~Authorization~
        +as_signed_transaction(private_key PrivateKey) TypedTransaction
    }
    UnsignedSetCodeTransaction -- TransactionFieldsAPI : (implicitly uses fields)
    UnsignedSetCodeTransaction "1" *-- "0..*" Authorization : contains

    class SetCodeTransaction {
        <<RLPSerializable>>
        +chain_id int
        +nonce int
        +max_priority_fee_per_gas int
        +max_fee_per_gas int
        +gas int
        +to Address
        +value int
        +data bytes
        +access_list Sequence
        +authorization_list Sequence~Authorization~
        +y_parity int
        +r int
        +s int
    }
    SetCodeTransaction -- TransactionFieldsAPI : (implicitly uses fields)
    SetCodeTransaction "1" *-- "0..*" Authorization : contains

    class PragueTypedTransaction {
        +decoders Dict
        +receipt_builder PragueReceiptBuilder
        +_inner SignedTransactionAPI
    }
    PragueTypedTransaction o-- SetCodeTransaction : wraps

    class PragueTransactionBuilder {
        +legacy_signed PragueLegacyTransaction
        +legacy_unsigned PragueUnsignedLegacyTransaction
        +typed_transaction PragueTypedTransaction
        +new_unsigned_set_code_transaction(...) UnsignedSetCodeTransaction
        +new_set_code_transaction(...) PragueTypedTransaction
    }
    PragueTransactionBuilder ..> UnsignedSetCodeTransaction : creates
    PragueTransactionBuilder ..> SetCodeTransaction : creates
    PragueTransactionBuilder ..> PragueTypedTransaction : creates
Loading

Class Diagram: Prague Block and Header Structures

classDiagram
    class BlockAPI {
        <<Interface>>
        +header BlockHeaderAPI
        +transactions Sequence~SignedTransactionAPI~
        +uncles Sequence~BlockHeaderAPI~
        +withdrawals Sequence~WithdrawalAPI~
        +block_requests List~bytes~
    }
    class CancunBlock {
        header CancunBlockHeader
    }
    class PragueBlock {
        header PragueBlockHeader
        transaction_builder PragueTransactionBuilder
        receipt_builder PragueReceiptBuilder
        +block_requests List~bytes~
    }
    PragueBlock --|> CancunBlock
    PragueBlock ..|> BlockAPI

    class BlockHeaderAPI {
        <<Interface>>
        +parent_beacon_block_root Hash32
        +requests_hash Hash32
    }
    class CancunBlockHeader {
        parent_beacon_block_root Hash32
    }
    class PragueBlockHeader {
        requests_hash Hash32
    }
    PragueBlockHeader --|> CancunBlockHeader
    PragueBlockHeader ..|> BlockHeaderAPI

    PragueBlock *-- "1" PragueBlockHeader : contains
    PragueBlock *-- "0..*" PragueTransactionBuilder : uses transactions from
Loading

File-Level Changes

Change Details Files
Introduce full Prague hard-fork support modules
  • Add eth/vm/forks/prague directories: blocks.py, headers.py, state.py, computation.py, logic.py, transactions.py, constants.py, receipts.py, opcodes.py
  • Wire Prague VM into eth/vm/forks/init.py and update MAINNET_VMS and LATEST_VM
  • Add PragueBlock and PragueBlockHeader RLP definitions and header factory
eth/vm/forks/prague/blocks.py
eth/vm/forks/prague/headers.py
eth/vm/forks/prague/state.py
eth/vm/forks/prague/transactions.py
eth/vm/forks/prague/computation.py
eth/vm/forks/prague/logic.py
eth/vm/forks/prague/constants.py
eth/vm/forks/prague/receipts.py
eth/vm/forks/prague/opcodes.py
eth/vm/forks/__init__.py
Add SetCode authorization EIP-7702
  • Define SetCodeAuthorizationAPI and Authorization RLP type
  • Implement UnsignedSetCodeTransaction and SetCodeTransaction with authorization_list
  • Extend TransactionFieldsAPI and TypedTransaction to expose authorization_list
eth/abc.py
eth/validation.py
eth/typing.py
eth/vm/forks/prague/transactions.py
eth/_utils/normalization.py
Block requests processing lifecycle
  • Add block_requests field to BlockAPI and RLP models
  • Extend Base VM: block_preprocessing, block_postprocessing, compute_requests_hash
  • Implement deposit, withdrawal, consolidation request extraction in PragueVM
eth/vm/base.py
eth/rlp/blocks.py
eth/vm/logic/call.py
eth/vm/forks/prague/__init__.py
Unified code-loading and delegation logic
  • Remove per-opcode account load fee duplication
  • Introduce get_code_at_address returning code and optional delegation_address
  • Add is_delegation flag to MessageAPI and call execution
eth/vm/logic/call.py
eth/vm/message.py
eth/vm/computation.py
eth/vm/forks/berlin/logic.py
Enhanced gas accounting (data floor and refunds)
  • Add data_floor_gas to ComputationAPI and update finalize_computation flow
  • Calculate EIP-7623 data floor cost in PragueState and refund logic
  • Include message.refund in get_gas_refund
eth/vm/computation.py
eth/vm/state.py
eth/vm/forks/frontier/state.py
eth/vm/forks/prague/state.py
Consolidate transaction validation helpers
  • Extract validate_dynamic_fee_tx for dynamic-fee txs
  • Add validate_uint8, validate_nonce, validate_chain_id_is_current_or_zero
  • Use new helpers across London, Berlin, Cancun, Frontier forks
eth/validation.py
eth/vm/forks/london/transactions.py
eth/vm/forks/berlin/transactions.py
eth/vm/forks/cancun/transactions.py
eth/vm/forks/frontier/transactions.py
Add BLS12-381 precompiles
  • Define constants and gas costs for G1/G2 addition, MSM, map, pairing
  • Implement precompile functions under eth/precompiles/bls12_381
  • Register precompiles in PragueComputation
eth/precompiles/bls12_381/constants.py
eth/precompiles/bls12_381/bls12_381_g1.py
eth/precompiles/bls12_381/bls12_381_g2.py
eth/precompiles/bls12_381/bls12_381_pairing.py
eth/vm/forks/prague/computation.py
Version bump and dependency updates
  • Update version to 0.12.1-beta.1 in setup.py and pyproject.toml
  • Bump py-ecc requirement
  • Adjust pre-commit and CI configs to include Prague
setup.py
pyproject.toml
.circleci/config.yml
.pre-commit-config.yaml
tox.ini
Update fixtures and tests for new forks
  • Extend fixture loader to handle multiple base dirs (legacy and EEST)
  • Add tests for Prague fork in chain construction, VM transitions, transaction builder, legacy transactions
  • Update skip logic and fixture paths for Cancun/EEST
eth/tools/fixtures/loading.py
tests/json-fixtures/*
tests/core/*
eth/tools/fixtures/generation.py
eth/tools/fixtures/helpers.py
eth/tools/_utils/normalization.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Dargon789 Dargon789 enabled auto-merge (squash) June 15, 2025 22:11
auto-merge was automatically disabled September 5, 2025 21:30

Head branch was pushed to by a user without write access

Removed Discord and build status badges from README.
Copy link
Owner Author

@Dargon789 Dargon789 left a comment

Choose a reason for hiding this comment

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

fix: Bump version: 0.12.0-beta.3 → 0.12.1-beta.1 #4

@Dargon789 Dargon789 self-assigned this Jan 25, 2026
@Dargon789 Dargon789 added bug Something isn't working documentation Improvements or additions to documentation duplicate This issue or pull request already exists enhancement New feature or request help wanted Extra attention is needed good first issue Good for newcomers invalid This doesn't seem right question Further information is requested labels Jan 25, 2026
@github-project-automation github-project-automation bot moved this to Backlog in Hardhat Jan 25, 2026
@Dargon789 Dargon789 disabled auto-merge January 25, 2026 07:35
Copy link
Owner Author

@Dargon789 Dargon789 left a comment

Choose a reason for hiding this comment

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

fix: Bump version: 0.12.0-beta.3 → 0.12.1-beta.1 #4

@Dargon789 Dargon789 enabled auto-merge January 25, 2026 07:40
@Dargon789 Dargon789 disabled auto-merge January 25, 2026 08:17
@Dargon789 Dargon789 linked an issue Jan 25, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation duplicate This issue or pull request already exists enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed invalid This doesn't seem right question Further information is requested

Projects

Status: Backlog
Status: Todo

Development

Successfully merging this pull request may close these issues.

# Sequence diagram for PR-triggered CI pipeline # Sequence Diagram: EIP-7702 SetCode Transaction Authorization Processing

4 participants